1
|
<?php
|
2
|
|
3
|
/**
|
4
|
* @file Rules UI forms
|
5
|
*/
|
6
|
|
7
|
/**
|
8
|
* Ajax callback for reloading the whole form.
|
9
|
*/
|
10
|
function rules_ui_form_ajax_reload_form($form, $form_state) {
|
11
|
return $form;
|
12
|
}
|
13
|
|
14
|
/**
|
15
|
* Defines #ajax properties.
|
16
|
*/
|
17
|
function rules_ui_form_default_ajax($effect = 'slide') {
|
18
|
return array(
|
19
|
'callback' => 'rules_ui_form_ajax_reload_form',
|
20
|
'wrapper' => 'rules-form-wrapper',
|
21
|
'effect' => $effect,
|
22
|
'speed' => 'fast',
|
23
|
);
|
24
|
}
|
25
|
|
26
|
/**
|
27
|
* Submit handler for switching the parameter input mode.
|
28
|
*/
|
29
|
function rules_ui_parameter_replace_submit($form, &$form_state) {
|
30
|
if (isset($form_state['triggering_element'])) {
|
31
|
$name = $form_state['triggering_element']['#parameter'];
|
32
|
$form_state['parameter_mode'][$name] = $form_state['parameter_mode'][$name] == 'selector' ? 'input' : 'selector';
|
33
|
}
|
34
|
$form_state['rebuild'] = TRUE;
|
35
|
}
|
36
|
|
37
|
/**
|
38
|
* General form submit handler, that rebuilds the form
|
39
|
*/
|
40
|
function rules_form_submit_rebuild($form, &$form_state) {
|
41
|
$form_state['rebuild'] = TRUE;
|
42
|
}
|
43
|
|
44
|
/**
|
45
|
* Edit a rules configuration.
|
46
|
*/
|
47
|
function rules_ui_form_edit_rules_config($form, &$form_state, $rules_config, $base_path) {
|
48
|
RulesPluginUI::$basePath = $base_path;
|
49
|
$form_state += array('rules_element' => $rules_config);
|
50
|
// Add the rule configuration's form.
|
51
|
$rules_config->form($form, $form_state, array('show settings' => TRUE, 'button' => TRUE));
|
52
|
$form['#validate'] = array('rules_ui_form_rules_config_validate');
|
53
|
return $form;
|
54
|
}
|
55
|
|
56
|
/**
|
57
|
* General rules configuration form validation callback. Also populates the
|
58
|
* rules configuration with the form values.
|
59
|
*/
|
60
|
function rules_ui_form_rules_config_validate($form, &$form_state) {
|
61
|
$form_state['rules_element']->form_validate($form, $form_state);
|
62
|
}
|
63
|
|
64
|
/**
|
65
|
* Edit a rules configuration form submit callback.
|
66
|
*/
|
67
|
function rules_ui_form_edit_rules_config_submit($form, &$form_state) {
|
68
|
$form_state['rules_element']->form_submit($form, $form_state);
|
69
|
drupal_set_message(t('Your changes have been saved.'));
|
70
|
if (empty($form_state['redirect'])) {
|
71
|
$form_state['redirect'] = RulesPluginUI::defaultRedirect($form_state['rules_element']);
|
72
|
}
|
73
|
}
|
74
|
|
75
|
/**
|
76
|
* Clone a rules configuration form.
|
77
|
*/
|
78
|
function rules_ui_form_clone_rules_config($form, &$form_state, $rules_config, $base_path) {
|
79
|
RulesPluginUI::$basePath = $base_path;
|
80
|
$rules_config = clone $rules_config;
|
81
|
$rules_config->id = NULL;
|
82
|
$rules_config->name = '';
|
83
|
$rules_config->label .= ' (' . t('cloned') . ')';
|
84
|
$rules_config->status = ENTITY_CUSTOM;
|
85
|
|
86
|
$form['#validate'][] = 'rules_ui_form_rules_config_validate';
|
87
|
$form['#submit'][] = 'rules_ui_form_edit_rules_config_submit';
|
88
|
$form_state += array('rules_element' => $rules_config, 'op' => 'clone');
|
89
|
|
90
|
// Add the rule configuration's form.
|
91
|
$rules_config->form($form, $form_state, array('show settings' => TRUE, 'button' => TRUE, 'init' => TRUE));
|
92
|
|
93
|
// Open the settings fieldset so altering the name is easier.
|
94
|
$form['settings']['#collapsed'] = FALSE;
|
95
|
return $form;
|
96
|
}
|
97
|
|
98
|
/**
|
99
|
* A simple form just showing a textarea with the export.
|
100
|
*/
|
101
|
function rules_ui_form_export_rules_config($form, &$form_state, $rules_config, $base_path) {
|
102
|
$form['export'] = array(
|
103
|
'#type' => 'textarea',
|
104
|
'#title' => t('Export'),
|
105
|
'#description' => t('For importing copy the content of the text area and paste it into the import page.'),
|
106
|
'#rows' => 25,
|
107
|
'#default_value' => $rules_config->export(),
|
108
|
);
|
109
|
return $form;
|
110
|
}
|
111
|
|
112
|
/**
|
113
|
* Configuration form to directly execute a rules configuration.
|
114
|
*/
|
115
|
function rules_ui_form_execute_rules_config($form, &$form_state, $rules_config, $base_path) {
|
116
|
// Only components can be executed.
|
117
|
if (!($rules_config instanceof RulesTriggerableInterface)) {
|
118
|
RulesPluginUI::$basePath = $base_path;
|
119
|
// Create either the appropriate action or condition element.
|
120
|
$element = rules_plugin_factory($rules_config instanceof RulesActionInterface ? 'action' : 'condition', 'component_' . $rules_config->name);
|
121
|
$form['exec_help'] = array(
|
122
|
'#prefix' => '<p>',
|
123
|
'#markup' => t('This form allows you to manually trigger the execution of the @plugin "%label". If this component requires any parameters, input the suiting execution arguments below.', array('@plugin' => $rules_config->plugin(), '%label' => $rules_config->label())),
|
124
|
'#suffix' => '</p>',
|
125
|
);
|
126
|
$element->form($form, $form_state);
|
127
|
|
128
|
// For conditions hide the option to negate them.
|
129
|
if (isset($form['negate'])) {
|
130
|
$form['negate']['#access'] = FALSE;
|
131
|
}
|
132
|
$form['submit'] = array(
|
133
|
'#type' => 'submit',
|
134
|
'#value' => t('Execute'),
|
135
|
'#weight' => 20,
|
136
|
);
|
137
|
// Re-use the validation callback, which will also populate the action with
|
138
|
// the configuration settings in the form.
|
139
|
$form['#validate'] = array('rules_ui_form_rules_config_validate');
|
140
|
return $form;
|
141
|
}
|
142
|
drupal_not_found();
|
143
|
exit;
|
144
|
}
|
145
|
|
146
|
/**
|
147
|
* Submit callback for directly executing a component.
|
148
|
*/
|
149
|
function rules_ui_form_execute_rules_config_submit($form, &$form_state) {
|
150
|
$element = $form_state['rules_element'];
|
151
|
$result = $element->execute();
|
152
|
if ($element instanceof RulesActionInterface) {
|
153
|
drupal_set_message(t('Component %label has been executed.', array('%label' => $element->label())));
|
154
|
}
|
155
|
else {
|
156
|
drupal_set_message(t('Component %label evaluated to %result.', array('%label' => $element->label(), '%result' => $result ? 'true' : 'false')));
|
157
|
}
|
158
|
}
|
159
|
|
160
|
/**
|
161
|
* Gets the confirmation question for valid operations, or else FALSE.
|
162
|
*/
|
163
|
function rules_ui_confirm_operations($op, $rules_config) {
|
164
|
$vars = array('%plugin' => $rules_config->plugin(), '%label' => $rules_config->label());
|
165
|
|
166
|
switch ($op) {
|
167
|
case 'enable':
|
168
|
return array(t('Are you sure you want to enable the %plugin %label?', $vars), '');
|
169
|
case 'disable':
|
170
|
return array(t('Are you sure you want to disable the %plugin %label?', $vars), '');
|
171
|
case 'revert':
|
172
|
return array(t('Are you sure you want to revert the %plugin %label?', $vars), t('This action cannot be undone.'));
|
173
|
case 'delete':
|
174
|
return array(t('Are you sure you want to delete the %plugin %label?', $vars), t('This action cannot be undone.'));
|
175
|
default:
|
176
|
return FALSE;
|
177
|
}
|
178
|
}
|
179
|
|
180
|
/**
|
181
|
* Confirmation form for applying the operation to the config.
|
182
|
*/
|
183
|
function rules_ui_form_rules_config_confirm_op($form, &$form_state, $rules_config, $op, $base_path) {
|
184
|
if (list($confirm_question, $description) = rules_ui_confirm_operations($op, $rules_config)) {
|
185
|
RulesPluginUI::$basePath = $base_path;
|
186
|
$form_state += array('rules_config' => $rules_config, 'op' => $op);
|
187
|
return confirm_form($form, $confirm_question, $base_path, $description, t('Confirm'), t('Cancel'));
|
188
|
}
|
189
|
else {
|
190
|
drupal_not_found();
|
191
|
exit;
|
192
|
}
|
193
|
}
|
194
|
|
195
|
/**
|
196
|
* Applies the operation and returns the message to show to the user. Also the
|
197
|
* operation is logged to the watchdog. Note that the string is defined two
|
198
|
* times so that the translation extractor can find it.
|
199
|
*/
|
200
|
function rules_ui_confirm_operation_apply($op, $rules_config) {
|
201
|
$vars = array('%plugin' => $rules_config->plugin(), '%label' => $rules_config->label());
|
202
|
$edit_link = l(t('edit'), RulesPluginUI::path($rules_config->name));
|
203
|
|
204
|
switch ($op) {
|
205
|
case 'enable':
|
206
|
$rules_config->active = TRUE;
|
207
|
$rules_config->save();
|
208
|
watchdog('rules', 'Enabled %plugin %label.', $vars, WATCHDOG_NOTICE, $edit_link);
|
209
|
return t('Enabled %plugin %label.', $vars);
|
210
|
|
211
|
case 'disable':
|
212
|
$rules_config->active = FALSE;
|
213
|
$rules_config->save();
|
214
|
watchdog('rules', 'Disabled %plugin %label.', $vars, WATCHDOG_NOTICE, $edit_link);
|
215
|
return t('Disabled %plugin %label.', $vars);
|
216
|
|
217
|
case 'revert':
|
218
|
$rules_config->delete();
|
219
|
watchdog('rules', 'Reverted %plugin %label to the defaults.', $vars, WATCHDOG_NOTICE, $edit_link);
|
220
|
return t('Reverted %plugin %label to the defaults.', $vars);
|
221
|
|
222
|
case 'delete':
|
223
|
$rules_config->delete();
|
224
|
watchdog('rules', 'Deleted %plugin %label.', $vars);
|
225
|
return t('Deleted %plugin %label.', $vars);
|
226
|
}
|
227
|
}
|
228
|
|
229
|
/**
|
230
|
* Rule config deletion form submit callback.
|
231
|
*/
|
232
|
function rules_ui_form_rules_config_confirm_op_submit($form, &$form_state) {
|
233
|
if ($form_state['values']['confirm']) {
|
234
|
$msg = rules_ui_confirm_operation_apply($form_state['op'], $form_state['rules_config']);
|
235
|
drupal_set_message($msg);
|
236
|
}
|
237
|
}
|
238
|
|
239
|
/**
|
240
|
* Add a new element a rules configuration.
|
241
|
*/
|
242
|
function rules_ui_add_element($form, &$form_state, $rules_config, $plugin_name, RulesContainerPlugin $parent, $base_path) {
|
243
|
$cache = rules_get_cache();
|
244
|
if (!isset($cache['plugin_info'][$plugin_name]['class'])) {
|
245
|
drupal_not_found();
|
246
|
exit;
|
247
|
}
|
248
|
RulesPluginUI::$basePath = $base_path;
|
249
|
$plugin_is_abstract = in_array('RulesAbstractPlugin', class_parents($cache['plugin_info'][$plugin_name]['class']));
|
250
|
// In the first step create the element and in the second step show its edit
|
251
|
// form.
|
252
|
if ($plugin_is_abstract && !isset($form_state['rules_element'])) {
|
253
|
RulesPluginUI::formDefaults($form, $form_state);
|
254
|
$form_state += array('parent_element' => $parent, 'plugin' => $plugin_name);
|
255
|
|
256
|
$form['element_name'] = array(
|
257
|
'#type' => 'select',
|
258
|
'#title' => t('Select the %element to add', array('%element' => $plugin_name)),
|
259
|
'#options' => RulesPluginUI::getOptions($plugin_name),
|
260
|
'#ajax' => rules_ui_form_default_ajax() + array(
|
261
|
'trigger_as' => array('name' => 'continue'),
|
262
|
),
|
263
|
);
|
264
|
$form['continue'] = array(
|
265
|
'#type' => 'submit',
|
266
|
'#name' => 'continue',
|
267
|
'#value' => t('Continue'),
|
268
|
'#ajax' => rules_ui_form_default_ajax(),
|
269
|
);
|
270
|
}
|
271
|
elseif (!$plugin_is_abstract) {
|
272
|
// Create the initial, empty element.
|
273
|
$element = rules_plugin_factory($plugin_name);
|
274
|
// Always add the new element at the bottom, thus set an appropriate weight.
|
275
|
$iterator = $parent->getIterator();
|
276
|
if ($sibling = end($iterator)) {
|
277
|
$element->weight = $sibling->weight + 1;
|
278
|
}
|
279
|
$element->setParent($parent);
|
280
|
$form_state['rules_element'] = $element;
|
281
|
}
|
282
|
|
283
|
if (isset($form_state['rules_element'])) {
|
284
|
$form_state['rules_element']->form($form, $form_state, array('button' => TRUE, 'init' => TRUE));
|
285
|
$form['#validate'][] = 'rules_ui_edit_element_validate';
|
286
|
$form['#submit'][] = 'rules_ui_edit_element_submit';
|
287
|
}
|
288
|
return $form;
|
289
|
}
|
290
|
|
291
|
/**
|
292
|
* Add element submit callback.
|
293
|
* Used for "abstract plugins" to create the initial element object with the
|
294
|
* given implemenation name and rebuild the form.
|
295
|
*/
|
296
|
function rules_ui_add_element_submit($form, &$form_state) {
|
297
|
$element = rules_plugin_factory($form_state['plugin'], $form_state['values']['element_name']);
|
298
|
|
299
|
// Always add the new element at the bottom, thus set an appropriate weight.
|
300
|
$iterator = $form_state['parent_element']->getIterator();
|
301
|
if ($sibling = end($iterator)) {
|
302
|
$element->weight = $sibling->weight + 1;
|
303
|
}
|
304
|
// Clear the element settings so they won't be processed on serialization as
|
305
|
// there is nothing to be processed yet.
|
306
|
$element->settings = array();
|
307
|
$element->setParent($form_state['parent_element']);
|
308
|
|
309
|
$form_state['rules_element'] = $element;
|
310
|
$form_state['rebuild'] = TRUE;
|
311
|
}
|
312
|
|
313
|
/**
|
314
|
* Delete elements.
|
315
|
*/
|
316
|
function rules_ui_delete_element($form, &$form_state, $rules_config, $rules_element, $base_path) {
|
317
|
RulesPluginUI::$basePath = $base_path;
|
318
|
|
319
|
if (empty($form_state['rules_config'])) {
|
320
|
// Before modifying the rules config we have to clone it, so any
|
321
|
// modifications won't appear in the static cache of the loading controller.
|
322
|
$rules_config = clone $rules_config;
|
323
|
// Also get the element from the cloned config.
|
324
|
$rules_element = $rules_config->elementMap()->lookup($rules_element->elementId());
|
325
|
|
326
|
$form_state['rules_config'] = $rules_config;
|
327
|
$form_state['rules_element'] = $rules_element;
|
328
|
$form_state['element_parent'] = $rules_element->parentElement();
|
329
|
}
|
330
|
|
331
|
// Try deleting the element and warn the user if something breaks, but
|
332
|
// save the parent for determining the right redirect target on submit.
|
333
|
$removed_plugin = $form_state['rules_element']->plugin();
|
334
|
$rules_element->delete();
|
335
|
|
336
|
if (empty($rules_config->dirty) && empty($form_state['input'])) {
|
337
|
try {
|
338
|
$rules_config->integrityCheck();
|
339
|
}
|
340
|
catch (RulesIntegrityException $e) {
|
341
|
$args = array(
|
342
|
'@plugin' => $e->element->plugin(),
|
343
|
'%label' => $e->element->label(),
|
344
|
'@removed-plugin' => $removed_plugin,
|
345
|
'!url' => url(RulesPluginUI::path($form_state['rules_config']->name, 'edit', $e->element)),
|
346
|
);
|
347
|
drupal_set_message(t('Deleting this @removed-plugin would break your configuration as some of its provided variables are utilized by the @plugin <a href="!url">%label</a>.', $args), 'warning');
|
348
|
}
|
349
|
}
|
350
|
|
351
|
$confirm_question = t('Are you sure you want to delete the %element_plugin %element_name?', array('%element_plugin' => $rules_element->plugin(), '%element_name' => $rules_element->label(), '%plugin' => $rules_config->plugin(), '%label' => $rules_config->label()));
|
352
|
return confirm_form($form, $confirm_question, RulesPluginUI::path($rules_config->name), t('This action cannot be undone.'), t('Delete'), t('Cancel'));
|
353
|
}
|
354
|
|
355
|
/**
|
356
|
* Rule config deletion form submit callback.
|
357
|
*/
|
358
|
function rules_ui_delete_element_submit($form, &$form_state) {
|
359
|
$rules_config = $form_state['rules_config'];
|
360
|
$rules_config->save();
|
361
|
if (empty($form_state['redirect'])) {
|
362
|
$form_state['redirect'] = RulesPluginUI::defaultRedirect($form_state['element_parent']);
|
363
|
}
|
364
|
}
|
365
|
|
366
|
|
367
|
/**
|
368
|
* Configure a rule element.
|
369
|
*/
|
370
|
function rules_ui_edit_element($form, &$form_state, $rules_config, $element, $base_path) {
|
371
|
RulesPluginUI::$basePath = $base_path;
|
372
|
$form_state += array('rules_element' => $element);
|
373
|
$form_state['rules_element']->form($form, $form_state, array('button' => TRUE));
|
374
|
return $form;
|
375
|
}
|
376
|
|
377
|
/**
|
378
|
* Validate the element configuration.
|
379
|
*/
|
380
|
function rules_ui_edit_element_validate($form, &$form_state) {
|
381
|
$form_state['rules_element']->form_validate($form, $form_state);
|
382
|
}
|
383
|
|
384
|
/**
|
385
|
* Submit the element configuration.
|
386
|
*/
|
387
|
function rules_ui_edit_element_submit($form, &$form_state) {
|
388
|
$form_state['rules_element']->form_submit($form, $form_state);
|
389
|
drupal_set_message(t('Your changes have been saved.'));
|
390
|
if (empty($form_state['redirect'])) {
|
391
|
$form_state['redirect'] = RulesPluginUI::defaultRedirect($form_state['rules_element']);
|
392
|
}
|
393
|
}
|
394
|
|
395
|
/**
|
396
|
* Form builder for the "add event" page.
|
397
|
*/
|
398
|
function rules_ui_add_event_page($form, &$form_state, RulesTriggerableInterface $rules_config, $base_path) {
|
399
|
RulesPluginUI::$basePath = $base_path;
|
400
|
RulesPluginUI::formDefaults($form, $form_state);
|
401
|
$form = rules_ui_add_event($form, $form_state, $rules_config, $base_path);
|
402
|
$form['#validate'][] = 'rules_ui_add_event_validate';
|
403
|
return $form;
|
404
|
}
|
405
|
|
406
|
/**
|
407
|
* Submit the event configuration.
|
408
|
*/
|
409
|
function rules_ui_add_event_page_submit($form, &$form_state) {
|
410
|
rules_ui_add_event_apply($form, $form_state);
|
411
|
$rules_config = $form_state['rules_config'];
|
412
|
|
413
|
// Tell the user if this breaks something, but let him proceed.
|
414
|
if (empty($rules_config->dirty)) {
|
415
|
try {
|
416
|
$rules_config->integrityCheck();
|
417
|
}
|
418
|
catch (RulesIntegrityException $e) {
|
419
|
$warning = TRUE;
|
420
|
drupal_set_message(t('Added the event, but it does not provide all variables utilized.'), 'warning');
|
421
|
}
|
422
|
}
|
423
|
$rules_config->save();
|
424
|
if (!isset($warning)) {
|
425
|
$events = rules_fetch_data('event_info');
|
426
|
$label = $events[$form_state['values']['event']]['label'];
|
427
|
drupal_set_message(t('Added event %event.', array('%event' => $label)));
|
428
|
}
|
429
|
}
|
430
|
|
431
|
/**
|
432
|
* Add a new event.
|
433
|
*/
|
434
|
function rules_ui_add_event($form, &$form_state, RulesReactionRule $rules_config, $base_path) {
|
435
|
$form_state += array('rules_config' => $rules_config);
|
436
|
$events = array_diff_key(rules_fetch_data('event_info'), array_flip($rules_config->events()));
|
437
|
|
438
|
$form['help'] = array(
|
439
|
'#markup' => t('Select the event to add. However note that all added events need to provide all variables that should be available to your rule.'),
|
440
|
);
|
441
|
$form['event'] = array(
|
442
|
'#type' => 'select',
|
443
|
'#title' => t('React on event'),
|
444
|
'#options' => RulesPluginUI::getOptions('event', $events),
|
445
|
'#description' => t('Whenever the event occurs, rule evaluation is triggered.'),
|
446
|
'#ajax' => rules_ui_form_default_ajax(),
|
447
|
'#required' => TRUE,
|
448
|
);
|
449
|
if (!empty($form_state['values']['event'])) {
|
450
|
$handler = rules_get_event_handler($form_state['values']['event']);
|
451
|
$form['event_settings'] = $handler->buildForm($form_state);
|
452
|
}
|
453
|
else {
|
454
|
$form['event_settings'] = array();
|
455
|
}
|
456
|
$form['submit'] = array(
|
457
|
'#type' => 'submit',
|
458
|
'#value' => t('Add'),
|
459
|
);
|
460
|
$form_state['redirect'] = RulesPluginUI::path($rules_config->name);
|
461
|
return $form;
|
462
|
}
|
463
|
|
464
|
/**
|
465
|
* Validation callback for adding an event.
|
466
|
*/
|
467
|
function rules_ui_add_event_validate($form, $form_state) {
|
468
|
$handler = rules_get_event_handler($form_state['values']['event']);
|
469
|
$handler->extractFormValues($form['event_settings'], $form_state);
|
470
|
try {
|
471
|
$handler->validate();
|
472
|
}
|
473
|
catch (RulesIntegrityException $e) {
|
474
|
form_set_error(implode('][', $e->keys), $e->getMessage());
|
475
|
}
|
476
|
}
|
477
|
|
478
|
/**
|
479
|
* Submit callback that just adds the selected event.
|
480
|
*
|
481
|
* @see rules_admin_add_reaction_rule()
|
482
|
*/
|
483
|
function rules_ui_add_event_apply($form, &$form_state) {
|
484
|
$handler = rules_get_event_handler($form_state['values']['event']);
|
485
|
$handler->extractFormValues($form['event_settings'], $form_state);
|
486
|
$form_state['rules_config']->event($form_state['values']['event'], $handler->getSettings());
|
487
|
}
|
488
|
|
489
|
/**
|
490
|
* Form to remove a event from a rule.
|
491
|
*/
|
492
|
function rules_ui_remove_event($form, &$form_state, $rules_config, $event, $base_path) {
|
493
|
RulesPluginUI::$basePath = $base_path;
|
494
|
$form_state += array('rules_config' => $rules_config, 'rules_event' => $event);
|
495
|
$event_info = rules_get_event_info($event);
|
496
|
$form_state['event_label'] = $event_info['label'];
|
497
|
$confirm_question = t('Are you sure you want to remove the event?');
|
498
|
return confirm_form($form, $confirm_question, RulesPluginUI::path($rules_config->name), t('You are about to remove the event %event.', array('%event' => $form_state['event_label'])), t('Remove'), t('Cancel'));
|
499
|
}
|
500
|
|
501
|
/**
|
502
|
* Submit the event configuration.
|
503
|
*/
|
504
|
function rules_ui_remove_event_submit($form, &$form_state) {
|
505
|
$rules_config = $form_state['rules_config'];
|
506
|
$rules_config->removeEvent($form_state['rules_event']);
|
507
|
// Tell the user if this breaks something, but let him proceed.
|
508
|
if (empty($rules_config->dirty)) {
|
509
|
try {
|
510
|
$rules_config->integrityCheck();
|
511
|
}
|
512
|
catch (RulesIntegrityException $e) {
|
513
|
$warning = TRUE;
|
514
|
drupal_set_message(t('Removed the event, but it had provided some variables which are now missing.'), 'warning');
|
515
|
}
|
516
|
}
|
517
|
$rules_config->save();
|
518
|
if (!isset($warning)) {
|
519
|
drupal_set_message(t('Event %event has been removed.', array('%event' => $form_state['event_label'])));
|
520
|
}
|
521
|
$form_state['redirect'] = RulesPluginUI::path($rules_config->name);
|
522
|
}
|
523
|
|
524
|
/**
|
525
|
* Import form for rule configurations.
|
526
|
*/
|
527
|
function rules_ui_import_form($form, &$form_state, $base_path) {
|
528
|
RulesPluginUI::$basePath = $base_path;
|
529
|
RulesPluginUI::formDefaults($form, $form_state);
|
530
|
$form['import'] = array(
|
531
|
'#type' => 'textarea',
|
532
|
'#title' => t('Import'),
|
533
|
'#description' => t('Paste an exported Rules configuration here.'),
|
534
|
'#rows' => 20,
|
535
|
);
|
536
|
$form['overwrite'] = array(
|
537
|
'#title' => t('Overwrite'),
|
538
|
'#type' => 'checkbox',
|
539
|
'#description' => t('If checked, any existing configuration with the same identifier will be replaced by the import.'),
|
540
|
'#default_value' => FALSE,
|
541
|
);
|
542
|
$form['submit'] = array(
|
543
|
'#type' => 'submit',
|
544
|
'#value' => t('Import'),
|
545
|
);
|
546
|
return $form;
|
547
|
}
|
548
|
|
549
|
/**
|
550
|
* Validation callback for the import form.
|
551
|
*/
|
552
|
function rules_ui_import_form_validate($form, &$form_state) {
|
553
|
if ($rules_config = rules_import($form_state['values']['import'], $error_msg)) {
|
554
|
// Store the successfully imported entity in $form_state.
|
555
|
$form_state['rules_config'] = $rules_config;
|
556
|
if (!$form_state['values']['overwrite']) {
|
557
|
// Check for existing entities with the same identifier.
|
558
|
if (rules_config_load($rules_config->name)) {
|
559
|
$vars = array('@entity' => t('Rules configuration'), '%label' => $rules_config->label());
|
560
|
form_set_error('import', t('Import of @entity %label failed, a @entity with the same machine name already exists. Check the overwrite option to replace it.', $vars));
|
561
|
}
|
562
|
}
|
563
|
try {
|
564
|
$rules_config->integrityCheck();
|
565
|
}
|
566
|
catch (RulesIntegrityException $e) {
|
567
|
form_set_error('import', t('Integrity check for the imported configuration failed. Error message: %message.', array('%message' => $e->getMessage())));
|
568
|
}
|
569
|
if (!user_access('bypass rules access') && !$rules_config->access()) {
|
570
|
form_set_error('import', t('You have insufficient access permissions for importing this Rules configuration.'));
|
571
|
}
|
572
|
}
|
573
|
else {
|
574
|
form_set_error('import', t('Import failed.'));
|
575
|
if ($error_msg) {
|
576
|
drupal_set_message($error_msg, 'error');
|
577
|
}
|
578
|
}
|
579
|
}
|
580
|
|
581
|
/**
|
582
|
* Submit callback for the import form.
|
583
|
*/
|
584
|
function rules_ui_import_form_submit($form, &$form_state) {
|
585
|
$rules_config = $form_state['rules_config'];
|
586
|
|
587
|
if ($existing_config = rules_config_load($rules_config->name)) {
|
588
|
// Copy DB id and remove the new indicator to overwrite the existing record.
|
589
|
$rules_config->id = $existing_config->id;
|
590
|
unset($rules_config->is_new);
|
591
|
}
|
592
|
$rules_config->save();
|
593
|
$vars = array('@entity' => t('Rules configuration'), '%label' => $rules_config->label());
|
594
|
watchdog('rules_config', 'Imported @entity %label.', $vars);
|
595
|
drupal_set_message(t('Imported @entity %label.', $vars));
|
596
|
$form_state['redirect'] = RulesPluginUI::$basePath;
|
597
|
}
|
598
|
|
599
|
/**
|
600
|
* FAPI process callback for the data selection widget.
|
601
|
* This finalises the auto completion callback path by appending the form build
|
602
|
* id.
|
603
|
*/
|
604
|
function rules_data_selection_process($element, &$form_state, $form) {
|
605
|
$element['#autocomplete_path'] .= '/' . $form['#build_id'];
|
606
|
$form_state['cache'] = TRUE;
|
607
|
return $element;
|
608
|
}
|
609
|
|
610
|
/**
|
611
|
* Autocomplete data selection results.
|
612
|
*/
|
613
|
function rules_ui_form_data_selection_auto_completion($parameter, $form_build_id, $string = '') {
|
614
|
// Get the form and its state from the cache to get the currently edited
|
615
|
// or created element.
|
616
|
$form_state = form_state_defaults();
|
617
|
$form = form_get_cache($form_build_id, $form_state);
|
618
|
if (!isset($form_state['rules_element'])) {
|
619
|
return;
|
620
|
}
|
621
|
$element = $form_state['rules_element'];
|
622
|
|
623
|
$params = $element->pluginParameterInfo();
|
624
|
$matches = array();
|
625
|
if (isset($params[$parameter])) {
|
626
|
$parts = explode(':', $string);
|
627
|
// Remove the last part as it might be unfinished.
|
628
|
$last_part = array_pop($parts);
|
629
|
$selector = implode(':', $parts);
|
630
|
|
631
|
// Start with the partly given selector or from scratch.
|
632
|
$result = array();
|
633
|
if ($selector && $wrapper = $element->applyDataSelector($selector)) {
|
634
|
$result = RulesData::matchingDataSelector($wrapper, $params[$parameter], $selector . ':', 0);
|
635
|
}
|
636
|
elseif (!$selector) {
|
637
|
$result = RulesData::matchingDataSelector($element->availableVariables(), $params[$parameter], '', 0);
|
638
|
}
|
639
|
|
640
|
foreach ($result as $selector => $info) {
|
641
|
// If we have an uncomplete last part, take it into account now.
|
642
|
$attributes = array();
|
643
|
if (!$last_part || strpos($selector, $string) === 0) {
|
644
|
$attributes['class'][] = 'rules-dsac-item';
|
645
|
$attributes['title'] = isset($info['description']) ? strip_tags($info['description']) : '';
|
646
|
if ($selector[strlen($selector) - 1] == ':') {
|
647
|
$attributes['class'][] = 'rules-dsac-group';
|
648
|
$text = check_plain($selector) . '... (' . check_plain($info['label']) . ')';
|
649
|
}
|
650
|
else {
|
651
|
$text = check_plain($selector) . ' (' . check_plain($info['label']) . ')';
|
652
|
}
|
653
|
$matches[$selector] = "<div" . drupal_attributes($attributes) . ">$text</div>";
|
654
|
}
|
655
|
}
|
656
|
}
|
657
|
drupal_json_output($matches);
|
658
|
}
|
659
|
|
660
|
|
661
|
/**
|
662
|
* FAPI validation of an integer element. Copy of the private function
|
663
|
* _element_validate_integer().
|
664
|
*/
|
665
|
function rules_ui_element_integer_validate($element, &$form_state) {;
|
666
|
$value = $element['#value'];
|
667
|
if (isset($value) && $value !== '' && (!is_numeric($value) || intval($value) != $value)) {
|
668
|
form_error($element, t('%name must be an integer value.', array('%name' => isset($element['#title']) ? $element['#title'] : t('Element'))));
|
669
|
}
|
670
|
}
|
671
|
|
672
|
/**
|
673
|
* FAPI validation of a decimal element. Improved version of the private
|
674
|
* function _element_validate_number().
|
675
|
*/
|
676
|
function rules_ui_element_decimal_validate($element, &$form_state) {
|
677
|
// Substitute the decimal separator ",".
|
678
|
$value = strtr($element['#value'], ',', '.');
|
679
|
if ($value != '' && !is_numeric($value)) {
|
680
|
form_error($element, t('%name must be a number.', array('%name' => $element['#title'])));
|
681
|
}
|
682
|
elseif ($value != $element['#value']) {
|
683
|
form_set_value($element, $value, $form_state);
|
684
|
}
|
685
|
}
|
686
|
|
687
|
/**
|
688
|
* FAPI callback to validate an IP address.
|
689
|
*/
|
690
|
function rules_ui_element_ip_address_validate($element, &$form_state) {
|
691
|
$value = $element['#value'];
|
692
|
if ($value != '' && !filter_var($value, FILTER_VALIDATE_IP)) {
|
693
|
form_error($element, t('%name is not a valid IP address.', array('%name' => $element['#title'])));
|
694
|
}
|
695
|
}
|
696
|
|
697
|
/**
|
698
|
* FAPI validation of a date element. Makes sure the specified date format is
|
699
|
* correct and converts date values specifiy a fixed (= non relative) date to
|
700
|
* a timestamp. Relative dates are handled by the date input evaluator.
|
701
|
*/
|
702
|
function rules_ui_element_date_validate($element, &$form_state) {
|
703
|
$value = $element['#value'];
|
704
|
if ($value == '' || (is_numeric($value) && intval($value) == $value)) {
|
705
|
// The value is a timestamp.
|
706
|
return;
|
707
|
}
|
708
|
elseif (is_string($value) && RulesDateInputEvaluator::gmstrtotime($value) === FALSE) {
|
709
|
form_error($element, t('Wrong date format. Specify the date in the format %format.', array('%format' => gmdate('Y-m-d H:i:s', time() + 86400))));
|
710
|
}
|
711
|
elseif (is_string($value) && RulesDateInputEvaluator::isFixedDateString($value)) {
|
712
|
// As the date string specifies a fixed format, we can convert it now.
|
713
|
$value = RulesDateInputEvaluator::gmstrtotime($value);
|
714
|
form_set_value($element, $value, $form_state);
|
715
|
}
|
716
|
}
|
717
|
|
718
|
/**
|
719
|
* FAPI process callback for the duration element type.
|
720
|
*/
|
721
|
function rules_ui_element_duration_process($element, &$form_state) {
|
722
|
$element['value'] = array(
|
723
|
'#type' => 'textfield',
|
724
|
'#size' => 8,
|
725
|
'#element_validate' => array('rules_ui_element_integer_validate'),
|
726
|
'#default_value' => $element['#default_value'],
|
727
|
'#required' => !empty($element['#required']),
|
728
|
);
|
729
|
$element['multiplier'] = array(
|
730
|
'#type' => 'select',
|
731
|
'#options' => rules_ui_element_duration_multipliers(),
|
732
|
'#default_value' => 1,
|
733
|
);
|
734
|
|
735
|
// Put the child elements in a container-inline div.
|
736
|
$element['value']['#prefix'] = '<div class="rules-duration container-inline">';
|
737
|
$element['multiplier']['#suffix'] = '</div>';
|
738
|
|
739
|
// Set an appropriate multiplier.
|
740
|
if (!empty($element['value']['#default_value'])) {
|
741
|
foreach (array_keys(rules_ui_element_duration_multipliers()) as $m) {
|
742
|
if ($element['value']['#default_value'] % $m == 0) {
|
743
|
$element['multiplier']['#default_value'] = $m;
|
744
|
}
|
745
|
}
|
746
|
// Divide value by the multiplier, so the display is correct.
|
747
|
$element['value']['#default_value'] /= $element['multiplier']['#default_value'];
|
748
|
}
|
749
|
return $element;
|
750
|
}
|
751
|
|
752
|
/**
|
753
|
* Defines possible duration multiplier.
|
754
|
*/
|
755
|
function rules_ui_element_duration_multipliers() {
|
756
|
return array(
|
757
|
1 => t('seconds'),
|
758
|
60 => t('minutes'),
|
759
|
3600 => t('hours'),
|
760
|
// Just use approximate numbers for days (might last 23h on DST change),
|
761
|
// months and years.
|
762
|
86400 => t('days'),
|
763
|
86400 * 30 => t('months'),
|
764
|
86400 * 30 * 12 => t('years'),
|
765
|
);
|
766
|
}
|
767
|
|
768
|
/**
|
769
|
* Helper function to determine the value for a rules duration form
|
770
|
* element.
|
771
|
*/
|
772
|
function rules_ui_element_duration_value($element, $input = FALSE) {
|
773
|
// This runs before child elements are processed, so we cannot calculate the
|
774
|
// value here. But we have to make sure the value is an array, so the form
|
775
|
// API is able to process the children to set their values in the array. Thus
|
776
|
// once the form API has finished processing the element, the value is an
|
777
|
// array containing the child element values. Then finally the after build
|
778
|
// callback converts it back to the numeric value and sets that.
|
779
|
return array();
|
780
|
}
|
781
|
|
782
|
/**
|
783
|
* FAPI after build callback for the duration parameter type form.
|
784
|
* Fixes up the form value by applying the multiplier.
|
785
|
*/
|
786
|
function rules_ui_element_duration_after_build($element, &$form_state) {
|
787
|
if ($element['value']['#value'] !== '') {
|
788
|
$element['#value'] = $element['value']['#value'] * $element['multiplier']['#value'];
|
789
|
form_set_value($element, $element['#value'], $form_state);
|
790
|
}
|
791
|
else {
|
792
|
$element['#value'] = NULL;
|
793
|
form_set_value($element, NULL, $form_state);
|
794
|
}
|
795
|
return $element;
|
796
|
}
|
797
|
|
798
|
/**
|
799
|
* FAPI after build callback to ensure empty form elements result in no value.
|
800
|
*/
|
801
|
function rules_ui_element_fix_empty_after_build($element, &$form_state) {
|
802
|
if (isset($element['#value']) && $element['#value'] === '') {
|
803
|
$element['#value'] = NULL;
|
804
|
form_set_value($element, NULL, $form_state);
|
805
|
}
|
806
|
// Work-a-round for the text_format element.
|
807
|
elseif ($element['#type'] == 'text_format' && !isset($element['value']['#value'])) {
|
808
|
form_set_value($element, NULL, $form_state);
|
809
|
}
|
810
|
return $element;
|
811
|
}
|
812
|
|
813
|
|
814
|
/**
|
815
|
* FAPI after build callback for specifying a list of values.
|
816
|
*
|
817
|
* Turns the textual value in an array by splitting the text in chunks using the
|
818
|
* delimiter set at $element['#delimiter'].
|
819
|
*/
|
820
|
function rules_ui_list_textarea_after_build($element, &$form_state) {
|
821
|
$element['#value'] = $element['#value'] ? explode($element['#delimiter'], $element['#value']) : array();
|
822
|
$element['#value'] = array_map('trim', $element['#value']);
|
823
|
form_set_value($element, $element['#value'], $form_state);
|
824
|
return $element;
|
825
|
}
|
826
|
|
827
|
/**
|
828
|
* FAPI pre render callback. Turns the value back to a string for rendering.
|
829
|
*
|
830
|
* @see rules_ui_list_textarea_after_build()
|
831
|
*/
|
832
|
function rules_ui_list_textarea_pre_render($element) {
|
833
|
$element['#value'] = implode($element['#delimiter'], $element['#value']);
|
834
|
return $element;
|
835
|
}
|
836
|
|
837
|
/**
|
838
|
* FAPI callback to validate a list of integers.
|
839
|
*/
|
840
|
function rules_ui_element_integer_list_validate($element, &$form_state) {
|
841
|
foreach ($element['#value'] as $value) {
|
842
|
if ($value !== '' && (!is_numeric($value) || intval($value) != $value)) {
|
843
|
form_error($element, t('Each value must be an integer.'));
|
844
|
}
|
845
|
}
|
846
|
}
|
847
|
|
848
|
/**
|
849
|
* FAPI callback to validate a token.
|
850
|
*/
|
851
|
function rules_ui_element_token_validate($element) {
|
852
|
$value = $element['#value'];
|
853
|
if (isset($value) && $value !== '' && !entity_property_verify_data_type($value, 'token')) {
|
854
|
form_error($element, t('%name may only contain lowercase letters, numbers, and underscores and has to start with a letter.', array('%name' => isset($element['#title']) ? $element['#title'] : t('Element'))));
|
855
|
}
|
856
|
}
|
857
|
|
858
|
/**
|
859
|
* FAPI callback to validate a list of tokens.
|
860
|
*/
|
861
|
function rules_ui_element_token_list_validate($element, &$form_state) {
|
862
|
foreach ($element['#value'] as $value) {
|
863
|
if ($value !== '' && !entity_property_verify_data_type($value, 'token')) {
|
864
|
form_error($element, t('Each value may only contain lowercase letters, numbers, and underscores and has to start with a letter.'));
|
865
|
}
|
866
|
}
|
867
|
}
|
868
|
|
869
|
/**
|
870
|
* FAPI callback to validate a machine readable name.
|
871
|
*/
|
872
|
function rules_ui_element_machine_name_validate($element, &$form_state) {
|
873
|
if ($element['#value'] && !preg_match('!^[a-z0-9_]+$!', $element['#value'])) {
|
874
|
form_error($element, t('Machine-readable names must contain only lowercase letters, numbers, and underscores.'));
|
875
|
}
|
876
|
}
|
877
|
|
878
|
/**
|
879
|
* FAPI callback to validate the form for editing variable info.
|
880
|
* @see RulesPluginUI::getVariableForm()
|
881
|
*/
|
882
|
function rules_ui_element_variable_form_validate($elements, &$form_state) {
|
883
|
$names = array();
|
884
|
foreach (element_children($elements['items']) as $item_key) {
|
885
|
$element = &$elements['items'][$item_key];
|
886
|
if ($element['name']['#value'] || $element['type']['#value'] || $element['label']['#value']) {
|
887
|
foreach (array('name' => t('Machine name'), 'label' => t('Label'), 'type' => t('Data type')) as $key => $title) {
|
888
|
if (!$element[$key]['#value']) {
|
889
|
form_error($element[$key], t('!name field is required.', array('!name' => $title)));
|
890
|
}
|
891
|
}
|
892
|
if (isset($names[$element['name']['#value']])) {
|
893
|
form_error($element['name'], t('The machine-readable name %name is already taken.', array('%name' => $element['name']['#value'])));
|
894
|
}
|
895
|
$names[$element['name']['#value']] = TRUE;
|
896
|
}
|
897
|
}
|
898
|
}
|
899
|
|
900
|
/**
|
901
|
* Helper to sort elements by their 'weight' key.
|
902
|
*/
|
903
|
function rules_element_sort_helper($a, $b) {
|
904
|
$a += array('weight' => 0);
|
905
|
$b += array('weight' => 0);
|
906
|
if ($a['weight'] == $b['weight']) {
|
907
|
return 0;
|
908
|
}
|
909
|
return ($a['weight'] < $b['weight']) ? -1 : 1;
|
910
|
}
|
911
|
|
912
|
/**
|
913
|
* Form after build handler to set the static base path.
|
914
|
*
|
915
|
* @see RulesPluginUI::formDefaults()
|
916
|
*/
|
917
|
function rules_form_after_build_restore_base_path($form, &$form_state) {
|
918
|
if (isset($form_state['_rules_base_path'])) {
|
919
|
RulesPluginUI::$basePath = $form_state['_rules_base_path'];
|
920
|
}
|
921
|
return $form;
|
922
|
}
|
923
|
|
924
|
/**
|
925
|
* AJAX page callback to load tag suggestions.
|
926
|
*
|
927
|
* Largely copied from taxonomy_autocomplete().
|
928
|
*/
|
929
|
function rules_autocomplete_tags($tags_typed = '') {
|
930
|
// The user enters a comma-separated list of tags. We only autocomplete the
|
931
|
// last tag.
|
932
|
$tags_typed = drupal_explode_tags($tags_typed);
|
933
|
$tag_last = drupal_strtolower(array_pop($tags_typed));
|
934
|
|
935
|
$tag_matches = array();
|
936
|
if ($tag_last != '') {
|
937
|
$query = db_select('rules_tags', 'rt');
|
938
|
// Do not select already entered terms.
|
939
|
if (!empty($tags_typed)) {
|
940
|
$query->condition('rt.tag', $tags_typed, 'NOT IN');
|
941
|
}
|
942
|
// Select rows that match by tag name.
|
943
|
$tags_return = $query
|
944
|
->distinct()
|
945
|
->fields('rt', array('tag'))
|
946
|
->condition('rt.tag', '%' . db_like($tag_last) . '%', 'LIKE')
|
947
|
->groupBy('rt.tag')
|
948
|
->range(0, 10)
|
949
|
->execute()
|
950
|
->fetchCol('rt.tag');
|
951
|
|
952
|
$prefix = count($tags_typed) ? drupal_implode_tags($tags_typed) . ', ' : '';
|
953
|
|
954
|
foreach ($tags_return as $name) {
|
955
|
$n = $name;
|
956
|
// Tag names containing commas or quotes must be wrapped in quotes.
|
957
|
if (strpos($name, ',') !== FALSE || strpos($name, '"') !== FALSE) {
|
958
|
$n = '"' . str_replace('"', '""', $name) . '"';
|
959
|
}
|
960
|
$tag_matches[$prefix . $n] = check_plain($name);
|
961
|
}
|
962
|
}
|
963
|
drupal_json_output($tag_matches);
|
964
|
}
|