1
|
<?php
|
2
|
|
3
|
/**
|
4
|
* @file Contains core ui functions.
|
5
|
*/
|
6
|
|
7
|
/**
|
8
|
* Plugin UI Interface.
|
9
|
*/
|
10
|
interface RulesPluginUIInterface {
|
11
|
|
12
|
/**
|
13
|
* Adds the whole configuration form of this rules configuration. For rule
|
14
|
* elements that are part of a configuration this method just adds the
|
15
|
* elements configuration form.
|
16
|
*
|
17
|
* @param $form
|
18
|
* The form array where to add the form.
|
19
|
* @param $form_state
|
20
|
* The current form state.
|
21
|
* @param $options
|
22
|
* An optional array of options with the known keys:
|
23
|
* - 'show settings': Whether to include the 'settings' fieldset for
|
24
|
* editing configuration settings like the label or categories. Defaults
|
25
|
* to FALSE.
|
26
|
* - 'button': Whether a submit button should be added. Defaults to FALSE.
|
27
|
* - 'init': Whether the element is about to be configured the first time
|
28
|
* and the configuration is about to be initialized. Defaults to FALSE.
|
29
|
* - 'restrict plugins: May be used to restrict the list of rules plugins
|
30
|
* that may be added to this configuration. For that set an array of
|
31
|
* valid plugins. Note that conditions and actions are always valid, so
|
32
|
* just set an empty array for just allowing those.
|
33
|
* - 'restrict conditions': Optionally set an array of condition names to
|
34
|
* restrict the conditions that are available for adding.
|
35
|
* - 'restrict actions': Optionally set an array of action names to
|
36
|
* restrict the actions that are available to for adding.
|
37
|
* - 'restrict events': Optionally set an array of event names to restrict
|
38
|
* the events that are available for adding.
|
39
|
*
|
40
|
* @todo
|
41
|
* Implement the 'restrict *' options.
|
42
|
*/
|
43
|
public function form(&$form, &$form_state, $options = array());
|
44
|
|
45
|
/**
|
46
|
* Validate the configuration form of this rule element.
|
47
|
*
|
48
|
* @param $form
|
49
|
* @param $form_state
|
50
|
*/
|
51
|
public function form_validate($form, &$form_state);
|
52
|
|
53
|
/**
|
54
|
* Submit the configuration form of this rule element. This makes sure to
|
55
|
* put the updated configuration in the form state. For saving changes
|
56
|
* permanently, just call $config->save() afterwards.
|
57
|
*
|
58
|
* @param $form
|
59
|
* @param $form_state
|
60
|
*/
|
61
|
public function form_submit($form, &$form_state);
|
62
|
|
63
|
/**
|
64
|
* Returns a structured array for rendering this element in overviews.
|
65
|
*/
|
66
|
public function buildContent();
|
67
|
|
68
|
/**
|
69
|
* Returns the help text for editing this plugin.
|
70
|
*/
|
71
|
public function help();
|
72
|
|
73
|
/**
|
74
|
* Returns ui operations for this element.
|
75
|
*/
|
76
|
public function operations();
|
77
|
|
78
|
}
|
79
|
|
80
|
/**
|
81
|
* Helper object for mapping elements to ids.
|
82
|
*/
|
83
|
class RulesElementMap {
|
84
|
|
85
|
/**
|
86
|
* @var RulesPlugin
|
87
|
*/
|
88
|
protected $configuration;
|
89
|
protected $index = array();
|
90
|
protected $counter = 0;
|
91
|
|
92
|
public function __construct(RulesPlugin $config) {
|
93
|
$this->configuration = $config->root();
|
94
|
}
|
95
|
|
96
|
/**
|
97
|
* Makes sure each element has an assigned id.
|
98
|
*/
|
99
|
public function index() {
|
100
|
foreach ($this->getUnIndexedElements($this->configuration) as $element) {
|
101
|
$id = &$element->property('elementId');
|
102
|
$id = ++$this->counter;
|
103
|
$this->index[$id] = $element;
|
104
|
}
|
105
|
}
|
106
|
|
107
|
protected function getUnIndexedElements($element, &$unindexed = array()) {
|
108
|
// Remember unindexed elements.
|
109
|
$id = $element->property('elementId');
|
110
|
if (!isset($id)) {
|
111
|
$unindexed[] = $element;
|
112
|
}
|
113
|
else {
|
114
|
// Make sure $this->counter refers to the highest id.
|
115
|
if ($id > $this->counter) {
|
116
|
$this->counter = $id;
|
117
|
}
|
118
|
$this->index[$id] = $element;
|
119
|
}
|
120
|
// Recurse down the tree.
|
121
|
if ($element instanceof RulesContainerPlugin) {
|
122
|
foreach ($element as $child) {
|
123
|
$this->getUnIndexedElements($child, $unindexed);
|
124
|
}
|
125
|
}
|
126
|
return $unindexed;
|
127
|
}
|
128
|
|
129
|
/**
|
130
|
* Looks up the element with the given id.
|
131
|
*/
|
132
|
public function lookup($id) {
|
133
|
if (!$this->index) {
|
134
|
$this->index();
|
135
|
}
|
136
|
return isset($this->index[$id]) ? $this->index[$id] : FALSE;
|
137
|
}
|
138
|
}
|
139
|
|
140
|
/**
|
141
|
* Faces UI extender for all kind of Rules plugins. Provides various useful
|
142
|
* methods for any rules UI.
|
143
|
*/
|
144
|
class RulesPluginUI extends FacesExtender implements RulesPluginUIInterface {
|
145
|
|
146
|
/**
|
147
|
* @var RulesPlugin
|
148
|
*/
|
149
|
protected $element;
|
150
|
|
151
|
/**
|
152
|
* The base path determines where a Rules overview UI lives. All forms that
|
153
|
* want to display Rules (overview) forms need to set this variable. This is
|
154
|
* necessary in order to get correct operation links, paths, redirects, bread
|
155
|
* crumbs etc. for the form() and overviewTable() methods.
|
156
|
*
|
157
|
* @see RulesUIController
|
158
|
* @see rules_admin_reaction_overview()
|
159
|
* @see rules_admin_components_overview()
|
160
|
*/
|
161
|
public static $basePath = NULL;
|
162
|
|
163
|
/**
|
164
|
* Provide $this->element to make the code more meaningful.
|
165
|
*/
|
166
|
public function __construct(FacesExtendable $object) {
|
167
|
parent::__construct($object);
|
168
|
$this->element = $object;
|
169
|
}
|
170
|
|
171
|
/**
|
172
|
* Returns the form values for the given form, possible being only a part of the whole form.
|
173
|
*
|
174
|
* In case the form is embedded somewhere, this function figures out the
|
175
|
* location of its form values and returns them for further use.
|
176
|
*
|
177
|
* @param $form
|
178
|
* A form array, or an array of form elements to get the value for.
|
179
|
* @param $form_state
|
180
|
* The form state as usual.
|
181
|
*/
|
182
|
public static function &getFormStateValues($form, &$form_state) {
|
183
|
$values = NULL;
|
184
|
if (isset($form_state['values'])) {
|
185
|
// Assume the top level if parents are not yet set.
|
186
|
$form += array('#parents' => array());
|
187
|
$values = &$form_state['values'];
|
188
|
foreach ($form['#parents'] as $parent) {
|
189
|
$values = &$values[$parent];
|
190
|
}
|
191
|
}
|
192
|
return $values;
|
193
|
}
|
194
|
|
195
|
/**
|
196
|
* Implements RulesPluginUIInterface.
|
197
|
* Generates the element edit form.
|
198
|
*
|
199
|
* Note: Make sure that you set RulesPluginUI::$basePath before using this
|
200
|
* method, otherwise paths, links, redirects etc. won't be correct.
|
201
|
*/
|
202
|
public function form(&$form, &$form_state, $options = array()) {
|
203
|
self::formDefaults($form, $form_state);
|
204
|
$form_state += array('rules_element' => $this->element);
|
205
|
|
206
|
// Add the help to the top of the form.
|
207
|
$help = $this->element->help();
|
208
|
$form['help'] = is_array($help) ? $help : array('#markup' => $help);
|
209
|
|
210
|
// We use $form_state['element_settings'] to store the settings of both
|
211
|
// parameter modes. That way one can switch between the parameter modes
|
212
|
// without losing the settings of those.
|
213
|
$form_state += array('element_settings' => $this->element->settings);
|
214
|
$settings = $this->element->settings + $form_state['element_settings'];
|
215
|
|
216
|
$form['parameter'] = array(
|
217
|
'#tree' => TRUE,
|
218
|
);
|
219
|
|
220
|
foreach ($this->element->pluginParameterInfo() as $name => $parameter) {
|
221
|
if ($parameter['type'] == 'hidden') {
|
222
|
continue;
|
223
|
}
|
224
|
|
225
|
$form['parameter'][$name] = array(
|
226
|
'#type' => 'fieldset',
|
227
|
'#title' => check_plain($parameter['label']),
|
228
|
'#description' => filter_xss(isset($parameter['description']) ? $parameter['description'] : ''),
|
229
|
);
|
230
|
|
231
|
// Init the parameter input mode.
|
232
|
$form_state['parameter_mode'][$name] = !isset($form_state['parameter_mode'][$name]) ? NULL : $form_state['parameter_mode'][$name];
|
233
|
$form['parameter'][$name] += $this->getParameterForm($name, $parameter, $settings, $form_state['parameter_mode'][$name]);
|
234
|
}
|
235
|
|
236
|
// Provide a form for editing the label and name of provided variables.
|
237
|
$settings = $this->element->settings;
|
238
|
foreach ($this->element->pluginProvidesVariables() as $var_name => $var_info) {
|
239
|
$form['provides'][$var_name] = array(
|
240
|
'#type' => 'fieldset',
|
241
|
'#title' => check_plain($var_info['label']),
|
242
|
'#description' => filter_xss(isset($var_info['description']) ? $var_info['description'] : ''),
|
243
|
);
|
244
|
$form['provides'][$var_name]['label'] = array(
|
245
|
'#type' => 'textfield',
|
246
|
'#title' => t('Variable label'),
|
247
|
'#default_value' => isset($settings[$var_name . ':label']) ? $settings[$var_name . ':label'] : $var_info['label'],
|
248
|
'#required' => TRUE,
|
249
|
);
|
250
|
$form['provides'][$var_name]['var'] = array(
|
251
|
'#type' => 'textfield',
|
252
|
'#title' => t('Variable name'),
|
253
|
'#default_value' => isset($settings[$var_name . ':var']) ? $settings[$var_name . ':var'] : $var_name,
|
254
|
'#description' => t('The variable name must contain only lowercase letters, numbers, and underscores and must be unique in the current scope.'),
|
255
|
'#element_validate' => array('rules_ui_element_machine_name_validate'),
|
256
|
'#required' => TRUE,
|
257
|
);
|
258
|
}
|
259
|
if (!empty($form['provides'])) {
|
260
|
$help = '<div class="description">' . t('Adjust the names and labels of provided variables, but note that renaming of already utilizied variables invalidates the existing uses.') . '</div>';
|
261
|
$form['provides'] += array(
|
262
|
'#tree' => TRUE,
|
263
|
'#prefix' => '<h4 class="rules-form-heading">' . t('Provided variables') . '</h4>' . $help,
|
264
|
);
|
265
|
}
|
266
|
|
267
|
// Add settings form, if specified.
|
268
|
if (!empty($options['show settings'])) {
|
269
|
$this->settingsForm($form, $form_state);
|
270
|
}
|
271
|
// Add submit button, if specified.
|
272
|
if (!empty($options['button'])) {
|
273
|
$form['submit'] = array(
|
274
|
'#type' => 'submit',
|
275
|
'#value' => t('Save'),
|
276
|
'#weight' => 10,
|
277
|
);
|
278
|
}
|
279
|
}
|
280
|
|
281
|
/**
|
282
|
* Actually generates the parameter form for the given data type.
|
283
|
*/
|
284
|
protected function getParameterForm($name, $info, $settings, &$mode) {
|
285
|
$class = $this->getDataTypeClass($info['type'], $info);
|
286
|
$supports_input_mode = in_array('RulesDataDirectInputFormInterface', class_implements($class));
|
287
|
|
288
|
// Init the mode.
|
289
|
if (!isset($mode)) {
|
290
|
if (isset($settings[$name . ':select'])) {
|
291
|
$mode = 'selector';
|
292
|
}
|
293
|
elseif (isset($settings[$name]) && $supports_input_mode) {
|
294
|
$mode = 'input';
|
295
|
}
|
296
|
elseif (isset($info['restriction'])) {
|
297
|
$mode = $info['restriction'];
|
298
|
}
|
299
|
else {
|
300
|
// Allow the parameter to define the 'default mode' and fallback to the
|
301
|
// data type default.
|
302
|
$mode = !empty($info['default mode']) ? $info['default mode'] : call_user_func(array($class, 'getDefaultMode'));
|
303
|
}
|
304
|
}
|
305
|
|
306
|
// For translatable parameters, pre-populate an internal translation source
|
307
|
// key so data type forms or input evaluators (i18n) may produce suiting
|
308
|
// help.
|
309
|
if (drupal_multilingual() && !empty($info['translatable'])) {
|
310
|
$parameter = $this->element->pluginParameterInfo();
|
311
|
$info['custom translation language'] = !empty($parameter['language']);
|
312
|
}
|
313
|
|
314
|
// Add the parameter form.
|
315
|
if ($mode == 'input' && $supports_input_mode) {
|
316
|
$form['settings'] = call_user_func(array($class, 'inputForm'), $name, $info, $settings, $this->element);
|
317
|
}
|
318
|
else {
|
319
|
$form['settings'] = call_user_func(array($class, 'selectionForm'), $name, $info, $settings, $this->element);
|
320
|
}
|
321
|
|
322
|
// Add a link for switching the input mode when JS is enabled and a button
|
323
|
// to switch it without javascript, in case switching is possible.
|
324
|
if ($supports_input_mode && empty($info['restriction'])) {
|
325
|
$value = $mode == 'selector' ? t('Switch to the direct input mode') : t('Switch to data selection');
|
326
|
|
327
|
$form['switch_button'] = array(
|
328
|
'#type' => 'submit',
|
329
|
'#name' => 'param_' . $name,
|
330
|
'#attributes' => array('class' => array('rules-switch-button')),
|
331
|
'#parameter' => $name,
|
332
|
'#value' => $value,
|
333
|
'#submit' => array('rules_ui_parameter_replace_submit'),
|
334
|
'#ajax' => rules_ui_form_default_ajax('none'),
|
335
|
// Do not validate!
|
336
|
'#limit_validation_errors' => array(),
|
337
|
);
|
338
|
}
|
339
|
return $form;
|
340
|
}
|
341
|
|
342
|
/**
|
343
|
* Implements RulesPluginUIInterface.
|
344
|
*/
|
345
|
public function form_validate($form, &$form_state) {
|
346
|
$this->form_extract_values($form, $form_state);
|
347
|
$form_values = RulesPluginUI::getFormStateValues($form, $form_state);
|
348
|
|
349
|
if (isset($form_values['provides'])) {
|
350
|
$vars = $this->element->availableVariables();
|
351
|
foreach ($form_values['provides'] as $name => $values) {
|
352
|
if (isset($vars[$values['var']])) {
|
353
|
form_error($form['provides'][$name]['var'], t('The variable name %name is already taken.', array('%name' => $values['var'])));
|
354
|
}
|
355
|
}
|
356
|
}
|
357
|
// Settings have been updated, so process them now.
|
358
|
$this->element->processSettings(TRUE);
|
359
|
|
360
|
// Make sure the current user really has access to configure this element
|
361
|
// as well as the used input evaluators and data processors.
|
362
|
if (!user_access('bypass rules access') && !$this->element->root()->access()) {
|
363
|
form_set_error('', t('Access violation! You have insufficient access permissions to edit this configuration.'));
|
364
|
}
|
365
|
if (!empty($form['settings'])) {
|
366
|
$this->settingsFormValidate($form, $form_state);
|
367
|
}
|
368
|
}
|
369
|
|
370
|
/**
|
371
|
* Applies the values of the form to the element.
|
372
|
*/
|
373
|
public function form_extract_values($form, &$form_state) {
|
374
|
$this->element->settings = array();
|
375
|
$form_values = RulesPluginUI::getFormStateValues($form, $form_state);
|
376
|
if (isset($form_values['parameter'])) {
|
377
|
foreach ($form_values['parameter'] as $name => $values) {
|
378
|
$this->element->settings += $values['settings'];
|
379
|
}
|
380
|
}
|
381
|
if (isset($form_values['provides'])) {
|
382
|
foreach ($form_values['provides'] as $name => $values) {
|
383
|
$this->element->settings[$name . ':label'] = $values['label'];
|
384
|
$this->element->settings[$name . ':var'] = $values['var'];
|
385
|
}
|
386
|
}
|
387
|
if (!empty($form['settings'])) {
|
388
|
$this->settingsFormExtractValues($form, $form_state);
|
389
|
}
|
390
|
}
|
391
|
|
392
|
/**
|
393
|
* Implements RulesPluginUIInterface.
|
394
|
*/
|
395
|
public function form_submit($form, &$form_state) {
|
396
|
if (!empty($form['settings'])) {
|
397
|
$this->settingsFormSubmit($form, $form_state);
|
398
|
}
|
399
|
$this->element->save();
|
400
|
}
|
401
|
|
402
|
/**
|
403
|
* Adds the configuration settings form (label, tags, description, ..).
|
404
|
*/
|
405
|
public function settingsForm(&$form, &$form_state) {
|
406
|
$form_values = RulesPluginUI::getFormStateValues($form, $form_state);
|
407
|
// Add the settings in a separate fieldset below.
|
408
|
$form['settings'] = array(
|
409
|
'#type' => 'fieldset',
|
410
|
'#title' => t('Settings'),
|
411
|
'#collapsible' => TRUE,
|
412
|
'#collapsed' => empty($form_values['settings']['vars']['more']),
|
413
|
'#weight' => 5,
|
414
|
'#tree' => TRUE,
|
415
|
);
|
416
|
$form['settings']['label'] = array(
|
417
|
'#type' => 'textfield',
|
418
|
'#title' => t('Name'),
|
419
|
'#default_value' => $this->element->label(),
|
420
|
'#required' => TRUE,
|
421
|
'#weight' => -5,
|
422
|
);
|
423
|
// @todo: For Drupal 8 use "owner" for generating machine names and
|
424
|
// module only for the modules providing default configurations.
|
425
|
if (!empty($this->element->module) && !empty($this->element->name) && $this->element->module == 'rules' && strpos($this->element->name, 'rules_') === 0) {
|
426
|
// Remove the Rules module prefix from the machine name.
|
427
|
$machine_name = substr($this->element->name, strlen($this->element->module) + 1);
|
428
|
}
|
429
|
else {
|
430
|
$machine_name = $this->element->name;
|
431
|
}
|
432
|
$form['settings']['name'] = array(
|
433
|
'#type' => 'machine_name',
|
434
|
'#default_value' => isset($machine_name) ? $machine_name : '',
|
435
|
// The string 'rules_' is pre-pended to machine names, so the
|
436
|
// maxlength must be less than the field length of 64 characters.
|
437
|
'#maxlength' => 58,
|
438
|
'#disabled' => entity_has_status('rules_config', $this->element, ENTITY_IN_CODE) && !(isset($form_state['op']) && $form_state['op'] == 'clone'),
|
439
|
'#machine_name' => array(
|
440
|
'exists' => 'rules_config_load',
|
441
|
'source' => array('settings', 'label'),
|
442
|
),
|
443
|
'#required' => TRUE,
|
444
|
'#description' => t('The machine-readable name of this configuration is used by rules internally to identify the configuration. This name must contain only lowercase letters, numbers, and underscores and must be unique.'),
|
445
|
);
|
446
|
$form['settings']['tags'] = array(
|
447
|
'#type' => 'textfield',
|
448
|
'#title' => t('Tags'),
|
449
|
'#default_value' => isset($this->element->tags) ? drupal_implode_tags($this->element->tags) : '',
|
450
|
'#autocomplete_path' => 'admin/config/workflow/rules/autocomplete_tags',
|
451
|
'#description' => t('Tags associated with this configuration, used for filtering in the admin interface. Separate multiple tags with commas.'),
|
452
|
);
|
453
|
|
454
|
// Show a form for editing variables for components.
|
455
|
if (($plugin_info = $this->element->pluginInfo()) && !empty($plugin_info['component'])) {
|
456
|
if ($this->element->hasStatus(ENTITY_IN_CODE)) {
|
457
|
$description = t('The variables used by the component. They can not be edited for configurations that are provided in code.');
|
458
|
}
|
459
|
else {
|
460
|
$description = t('Variables are normally input <em>parameters</em> for the component – data that should be available for the component to act on. Additionaly, action components may <em>provide</em> variables back to the caller. Each variable must have a specified data type, a label and a unique machine readable name containing only lowercase alphanumeric characters and underscores. See <a href="@url">the online documentation</a> for more information about variables.',
|
461
|
array('@url' => rules_external_help('variables'))
|
462
|
);
|
463
|
}
|
464
|
$form['settings']['vars'] = array(
|
465
|
'#prefix' => '<div id="rules-component-variables">',
|
466
|
'#suffix' => '</div>',
|
467
|
'#tree' => TRUE,
|
468
|
'#element_validate' => array('rules_ui_element_variable_form_validate'),
|
469
|
'#theme' => 'rules_ui_variable_form',
|
470
|
'#title' => t('Variables'),
|
471
|
'#description' => $description,
|
472
|
// Variables can not be edited on configurations in code.
|
473
|
'#disabled' => $this->element->hasStatus(ENTITY_IN_CODE),
|
474
|
);
|
475
|
|
476
|
$weight = 0;
|
477
|
$provides = $this->element->providesVariables();
|
478
|
foreach ($this->element->componentVariables() as $name => $var_info) {
|
479
|
$form['settings']['vars']['items'][$name] = RulesPluginUI::getVariableForm($name, $var_info, isset($provides[$name]));
|
480
|
$form['settings']['vars']['items'][$name]['weight']['#default_value'] = $weight++;
|
481
|
}
|
482
|
// Always add three empty forms.
|
483
|
for ($i = 0; $i < 3; $i++) {
|
484
|
$form['settings']['vars']['items'][$i] = RulesPluginUI::getVariableForm();
|
485
|
$form['settings']['vars']['items'][$i]['weight']['#default_value'] = $weight++;
|
486
|
}
|
487
|
$form['settings']['vars']['more'] = array(
|
488
|
'#type' => 'submit',
|
489
|
'#value' => t('Add more'),
|
490
|
// Enable AJAX once #756762 is fixed.
|
491
|
// '#ajax' => rules_ui_form_default_ajax('none'),
|
492
|
'#limit_validation_errors' => array(array('vars')),
|
493
|
'#submit' => array('rules_form_submit_rebuild'),
|
494
|
);
|
495
|
if (!empty($this->element->id)) {
|
496
|
// Display a setting to manage access.
|
497
|
$form['settings']['access'] = array(
|
498
|
'#weight' => 50,
|
499
|
);
|
500
|
$plugin_type = $this->element instanceof RulesActionInterface ? t('action') : t('condition');
|
501
|
$form['settings']['access']['access_exposed'] = array(
|
502
|
'#type' => 'checkbox',
|
503
|
'#title' => t('Configure access for using this component with a permission.'),
|
504
|
'#default_value' => !empty($this->element->access_exposed),
|
505
|
'#description' => t('By default, the @plugin-type for using this component may be only used by users that have access to configure the component. If checked, access is determined by a permission instead.', array('@plugin-type' => $plugin_type))
|
506
|
);
|
507
|
$form['settings']['access']['permissions'] = array(
|
508
|
'#type' => 'container',
|
509
|
'#states' => array(
|
510
|
'visible' => array(
|
511
|
':input[name="settings[access][access_exposed]"]' => array('checked' => TRUE),
|
512
|
),
|
513
|
),
|
514
|
);
|
515
|
$form['settings']['access']['permissions']['matrix'] = $this->settingsFormPermissionMatrix();
|
516
|
}
|
517
|
}
|
518
|
|
519
|
// TODO: Attach field form thus description.
|
520
|
}
|
521
|
|
522
|
/**
|
523
|
* Provides a matrix permission for the component based in the existing roles.
|
524
|
*
|
525
|
* @return
|
526
|
* Form elements with the matrix of permissions for a component.
|
527
|
*/
|
528
|
protected function settingsFormPermissionMatrix() {
|
529
|
$form['#theme'] = 'user_admin_permissions';
|
530
|
$status = array();
|
531
|
$options = array();
|
532
|
|
533
|
$role_names = user_roles();
|
534
|
$role_permissions = user_role_permissions($role_names);
|
535
|
$component_permission = rules_permissions_by_component(array($this->element));
|
536
|
$component_permission_name = key($component_permission);
|
537
|
|
538
|
$form['permission'][$component_permission_name] = array(
|
539
|
'#type' => 'item',
|
540
|
'#markup' => $component_permission[$component_permission_name]['title'],
|
541
|
);
|
542
|
$options[$component_permission_name] = '';
|
543
|
foreach ($role_names as $rid => $name) {
|
544
|
if (isset($role_permissions[$rid][$component_permission_name])) {
|
545
|
$status[$rid][] = $component_permission_name;
|
546
|
}
|
547
|
}
|
548
|
|
549
|
// Build the checkboxes for each role.
|
550
|
foreach ($role_names as $rid => $name) {
|
551
|
$form['checkboxes'][$rid] = array(
|
552
|
'#type' => 'checkboxes',
|
553
|
'#options' => $options,
|
554
|
'#default_value' => isset($status[$rid]) ? $status[$rid] : array(),
|
555
|
'#attributes' => array('class' => array('rid-' . $rid)),
|
556
|
);
|
557
|
$form['role_names'][$rid] = array('#markup' => check_plain($name), '#tree' => TRUE);
|
558
|
}
|
559
|
|
560
|
// Attach the default permissions page JavaScript.
|
561
|
$form['#attached']['js'][] = drupal_get_path('module', 'user') . '/user.permissions.js';
|
562
|
|
563
|
return $form;
|
564
|
}
|
565
|
|
566
|
public function settingsFormExtractValues($form, &$form_state) {
|
567
|
$form_values = RulesPluginUI::getFormStateValues($form['settings'], $form_state);
|
568
|
$this->element->label = $form_values['label'];
|
569
|
// If the name was changed we have to redirect to the URL that contains
|
570
|
// the new name, instead of rebuilding on the old URL with the old name
|
571
|
if ($form['settings']['name']['#default_value'] != $form_values['name']) {
|
572
|
$module = isset($this->element->module) ? $this->element->module : 'rules';
|
573
|
$this->element->name = $module . '_' . $form_values['name'];
|
574
|
$form_state['redirect'] = RulesPluginUI::path($this->element->name, 'edit', $this->element);
|
575
|
}
|
576
|
$this->element->tags = empty($form_values['tags']) ? array() : drupal_explode_tags($form_values['tags']);
|
577
|
|
578
|
if (isset($form_values['vars']['items'])) {
|
579
|
$vars = &$this->element->componentVariables();
|
580
|
$vars = array();
|
581
|
if ($this->element instanceof RulesActionContainer) {
|
582
|
$provides = &$this->element->componentProvidesVariables();
|
583
|
$provides = array();
|
584
|
}
|
585
|
|
586
|
usort($form_values['vars']['items'], 'rules_element_sort_helper');
|
587
|
foreach ($form_values['vars']['items'] as $item) {
|
588
|
if ($item['type'] && $item['name'] && $item['label']) {
|
589
|
$vars[$item['name']] = array('label' => $item['label'], 'type' => $item['type']);
|
590
|
if (!$item['usage'][0]) {
|
591
|
$vars[$item['name']]['parameter'] = FALSE;
|
592
|
}
|
593
|
if ($item['usage'][1] && isset($provides)) {
|
594
|
$provides[] = $item['name'];
|
595
|
}
|
596
|
}
|
597
|
}
|
598
|
// Disable FAPI persistence for the variable form so renumbering works.
|
599
|
$input = &$form_state['input'];
|
600
|
foreach ($form['settings']['#parents'] as $parent) {
|
601
|
$input = &$input[$parent];
|
602
|
}
|
603
|
unset($input['vars']);
|
604
|
}
|
605
|
$this->element->access_exposed = isset($form_values['access']['access_exposed']) ? $form_values['access']['access_exposed'] : FALSE;
|
606
|
}
|
607
|
|
608
|
public function settingsFormValidate($form, &$form_state) {
|
609
|
$form_values = RulesPluginUI::getFormStateValues($form['settings'], $form_state);
|
610
|
if ($form['settings']['name']['#default_value'] != $form_values['name'] && rules_config_load($this->element->name)) {
|
611
|
form_error($form['settings']['name'], t('The machine-readable name %name is already taken.', array('%name' => $form_values['name'])));
|
612
|
}
|
613
|
}
|
614
|
|
615
|
public function settingsFormSubmit($form, &$form_state) {
|
616
|
if (isset($form_state['values']['settings']['access']) && !empty($this->element->access_exposed)) {
|
617
|
// Save the permission matrix.
|
618
|
foreach ($form_state['values']['settings']['access']['permissions']['matrix']['checkboxes'] as $rid => $value) {
|
619
|
user_role_change_permissions($rid, $value);
|
620
|
}
|
621
|
}
|
622
|
}
|
623
|
|
624
|
/**
|
625
|
* Returns the form for configuring the info of a single variable.
|
626
|
*/
|
627
|
public function getVariableForm($name = '', $info = array(), $provided = FALSE) {
|
628
|
$form['type'] = array(
|
629
|
'#type' => 'select',
|
630
|
'#options' => array(0 => '--') + RulesPluginUI::getOptions('data'),
|
631
|
'#default_value' => isset($info['type']) ? $info['type'] : 0,
|
632
|
);
|
633
|
$form['label'] = array(
|
634
|
'#type' => 'textfield',
|
635
|
'#size' => 40,
|
636
|
'#default_value' => isset($info['label']) ? $info['label'] : '',
|
637
|
);
|
638
|
$form['name'] = array(
|
639
|
'#type' => 'textfield',
|
640
|
'#size' => 40,
|
641
|
'#default_value' => $name,
|
642
|
'#element_validate' => array('rules_ui_element_machine_name_validate'),
|
643
|
);
|
644
|
|
645
|
$usage[0] = !isset($info['parameter']) || $info['parameter'] ? 1 : 0;
|
646
|
$usage[1] = $provided ? 1 : 0;
|
647
|
|
648
|
$form['usage'] = array(
|
649
|
'#type' => 'select',
|
650
|
'#default_value' => implode('', $usage),
|
651
|
'#options' => array(
|
652
|
'10' => t('Parameter'),
|
653
|
'11' => t('Parameter + Provided'),
|
654
|
'01' => t('Provided'),
|
655
|
),
|
656
|
);
|
657
|
if ($this->element instanceof RulesConditionContainer) {
|
658
|
$form['usage']['#disabled'] = TRUE;
|
659
|
}
|
660
|
|
661
|
// Just set the weight #default_value for the returned form.
|
662
|
$form['weight'] = array(
|
663
|
'#type' => 'weight',
|
664
|
);
|
665
|
return $form;
|
666
|
}
|
667
|
|
668
|
/**
|
669
|
* Returns the name of class for the given data type.
|
670
|
*
|
671
|
* @param $data_type
|
672
|
* The name of the data typ
|
673
|
* @param $parameter_info
|
674
|
* (optional) An array of info about the to be configured parameter. If
|
675
|
* given, this array is complemented with data type defaults also.
|
676
|
*/
|
677
|
public function getDataTypeClass($data_type, &$parameter_info = array()) {
|
678
|
$cache = rules_get_cache();
|
679
|
$data_info = $cache['data_info'];
|
680
|
// Add in data-type defaults.
|
681
|
if (empty($parameter_info['ui class'])) {
|
682
|
$parameter_info['ui class'] = (is_string($data_type) && isset($data_info[$data_type]['ui class'])) ? $data_info[$data_type]['ui class'] : 'RulesDataUI';
|
683
|
}
|
684
|
if (is_subclass_of($parameter_info['ui class'], 'RulesDataInputOptionsListInterface')) {
|
685
|
$parameter_info['options list'] = array($parameter_info['ui class'], 'optionsList');
|
686
|
}
|
687
|
return $parameter_info['ui class'];
|
688
|
}
|
689
|
|
690
|
/**
|
691
|
* Implements RulesPluginUIInterface.
|
692
|
* Show a preview of the configuration settings.
|
693
|
*/
|
694
|
public function buildContent() {
|
695
|
$config_name = $this->element->root()->name;
|
696
|
$content['label'] = array(
|
697
|
'#type' => 'link',
|
698
|
'#title' => $this->element->label(),
|
699
|
'#href' => $this->element->isRoot() ? RulesPluginUI::path($config_name) : RulesPluginUI::path($config_name, 'edit', $this->element),
|
700
|
'#prefix' => '<div class="rules-element-label">',
|
701
|
'#suffix' => '</div>'
|
702
|
);
|
703
|
// Put the elements below in a "description" div.
|
704
|
$content['description'] = array(
|
705
|
'#prefix' => '<div class="description">',
|
706
|
);
|
707
|
$content['description']['parameter'] = array(
|
708
|
'#caption' => t('Parameter'),
|
709
|
'#theme' => 'rules_content_group',
|
710
|
);
|
711
|
foreach ($this->element->pluginParameterInfo() as $name => $parameter) {
|
712
|
$element = array();
|
713
|
if (!empty($this->element->settings[$name . ':select'])) {
|
714
|
$element['content'] = array(
|
715
|
'#markup' => '[' . $this->element->settings[$name . ':select'] . ']',
|
716
|
);
|
717
|
}
|
718
|
elseif (isset($this->element->settings[$name]) && (!isset($parameter['default value']) || $parameter['default value'] != $this->element->settings[$name])) {
|
719
|
$class = $this->getDataTypeClass($parameter['type'], $parameter);
|
720
|
$method = empty($parameter['options list']) ? 'render' : 'renderOptionsLabel';
|
721
|
// We cannot use method_exists() here as it would trigger a PHP bug,
|
722
|
// @see http://drupal.org/node/1258284
|
723
|
$element = call_user_func(array($class, $method), $this->element->settings[$name], $name, $parameter, $this->element);
|
724
|
}
|
725
|
// Only add parameters that are really configured / not default.
|
726
|
if ($element) {
|
727
|
$content['description']['parameter'][$name] = array(
|
728
|
'#theme' => 'rules_parameter_configuration',
|
729
|
'#info' => $parameter,
|
730
|
) + $element;
|
731
|
}
|
732
|
}
|
733
|
foreach ($this->element->providesVariables() as $name => $var_info) {
|
734
|
$content['description']['provides'][$name] = array(
|
735
|
'#theme' => 'rules_variable_view',
|
736
|
'#info' => $var_info,
|
737
|
'#name' => $name,
|
738
|
);
|
739
|
}
|
740
|
if (!empty($content['description']['provides'])) {
|
741
|
$content['description']['provides'] += array(
|
742
|
'#caption' => t('Provides variables'),
|
743
|
'#theme' => 'rules_content_group',
|
744
|
);
|
745
|
}
|
746
|
// Add integrity exception messages if there are any for this element.
|
747
|
try {
|
748
|
$this->element->integrityCheck();
|
749
|
// A configuration is still marked as dirty, but already works again.
|
750
|
if (!empty($this->element->dirty)) {
|
751
|
rules_config_update_dirty_flag($this->element);
|
752
|
$variables = array('%label' => $this->element->label(), '%name' => $this->element->name, '@plugin' => $this->element->plugin());
|
753
|
drupal_set_message(t('The @plugin %label (%name) was marked dirty, but passes the integrity check now and is active again.', $variables));
|
754
|
rules_clear_cache();
|
755
|
}
|
756
|
}
|
757
|
catch (RulesIntegrityException $e) {
|
758
|
$content['description']['integrity'] = array(
|
759
|
'#theme' => 'rules_content_group',
|
760
|
'#caption' => t('Error'),
|
761
|
'#attributes' => array('class' => array('rules-content-group-integrity-error')),
|
762
|
'error' => array(
|
763
|
'#markup' => filter_xss($e->getMessage()),
|
764
|
),
|
765
|
);
|
766
|
// Also make sure the rule is marked as dirty.
|
767
|
if (empty($this->element->dirty)) {
|
768
|
rules_config_update_dirty_flag($this->element);
|
769
|
rules_clear_cache();
|
770
|
}
|
771
|
}
|
772
|
|
773
|
$content['#suffix'] = '</div>';
|
774
|
$content['#type'] = 'container';
|
775
|
$content['#attributes']['class'][] = 'rules-element-content';
|
776
|
return $content;
|
777
|
}
|
778
|
|
779
|
/**
|
780
|
* Implements RulesPluginUIInterface.
|
781
|
*/
|
782
|
public function operations() {
|
783
|
$name = $this->element->root()->name;
|
784
|
$render = array(
|
785
|
'#theme' => 'links__rules',
|
786
|
);
|
787
|
$render['#attributes']['class'][] = 'rules-operations';
|
788
|
$render['#attributes']['class'][] = 'action-links';
|
789
|
$render['#links']['edit'] = array(
|
790
|
'title' => t('edit'),
|
791
|
'href' => RulesPluginUI::path($name, 'edit', $this->element),
|
792
|
);
|
793
|
$render['#links']['delete'] = array(
|
794
|
'title' => t('delete'),
|
795
|
'href' => RulesPluginUI::path($name, 'delete', $this->element),
|
796
|
);
|
797
|
return $render;
|
798
|
}
|
799
|
|
800
|
/**
|
801
|
* Implements RulesPluginUIInterface.
|
802
|
*/
|
803
|
public function help() {}
|
804
|
|
805
|
|
806
|
/**
|
807
|
* Deprecated by the controllers overviewTable() method.
|
808
|
*/
|
809
|
public static function overviewTable($conditions = array(), $options = array()) {
|
810
|
return rules_ui()->overviewTable($conditions, $options);
|
811
|
}
|
812
|
|
813
|
/**
|
814
|
* Generates a path using the given operation for the element with the given
|
815
|
* id of the configuration with the given name.
|
816
|
*/
|
817
|
public static function path($name, $op = NULL, RulesPlugin $element = NULL, $parameter = FALSE) {
|
818
|
$element_id = isset($element) ? $element->elementId() : FALSE;
|
819
|
if (isset(self::$basePath)) {
|
820
|
$base_path = self::$basePath;
|
821
|
}
|
822
|
// Default to the paths used by 'rules_admin', so modules can easily re-use
|
823
|
// its UI.
|
824
|
else {
|
825
|
$base_path = isset($element) && $element instanceof RulesTriggerableInterface ? 'admin/config/workflow/rules/reaction' : 'admin/config/workflow/rules/components';
|
826
|
}
|
827
|
return implode('/', array_filter(array($base_path . '/manage', $name, $op, $element_id, $parameter)));
|
828
|
}
|
829
|
|
830
|
/**
|
831
|
* Determines the default redirect target for an edited/deleted element. This
|
832
|
* is a parent element which is either a rule or the configuration root.
|
833
|
*/
|
834
|
public static function defaultRedirect(RulesPlugin $element) {
|
835
|
while (!$element->isRoot()) {
|
836
|
if ($element instanceof Rule) {
|
837
|
return self::path($element->root()->name, 'edit', $element);
|
838
|
}
|
839
|
$element = $element->parentElement();
|
840
|
}
|
841
|
return self::path($element->name);
|
842
|
}
|
843
|
|
844
|
/**
|
845
|
* @see RulesUICategory::getOptions()
|
846
|
*/
|
847
|
public static function getOptions($item_type, $items = NULL) {
|
848
|
return RulesUICategory::getOptions($item_type, $items = NULL);
|
849
|
}
|
850
|
|
851
|
public static function formDefaults(&$form, &$form_state) {
|
852
|
form_load_include($form_state, 'inc', 'rules', 'ui/ui.forms');
|
853
|
// Add our own css.
|
854
|
$form['#attached']['css'][] = drupal_get_path('module', 'rules') . '/ui/rules.ui.css';
|
855
|
// Workaround for problems with jquery css in seven theme and the core
|
856
|
// autocomplete.
|
857
|
if ($GLOBALS['theme'] == 'seven') {
|
858
|
$form['#attached']['css'][] = drupal_get_path('module', 'rules') . '/ui/rules.ui.seven.css';
|
859
|
}
|
860
|
|
861
|
// Specify the wrapper div used by #ajax.
|
862
|
$form['#prefix'] = '<div id="rules-form-wrapper">';
|
863
|
$form['#suffix'] = '</div>';
|
864
|
|
865
|
// Preserve the base path in the form state. The after build handler will
|
866
|
// set self::$basePath again for cached forms.
|
867
|
if (isset(self::$basePath)) {
|
868
|
$form_state['_rules_base_path'] = RulesPluginUI::$basePath;
|
869
|
$form['#after_build'][] = 'rules_form_after_build_restore_base_path';
|
870
|
}
|
871
|
}
|
872
|
|
873
|
public static function getTags() {
|
874
|
$result = db_select('rules_tags')
|
875
|
->distinct()
|
876
|
->fields('rules_tags', array('tag'))
|
877
|
->groupBy('tag')
|
878
|
->execute()
|
879
|
->fetchCol('tag');
|
880
|
return drupal_map_assoc($result);
|
881
|
}
|
882
|
}
|
883
|
|
884
|
/**
|
885
|
* UI for abstract plugins (conditions & actions).
|
886
|
*/
|
887
|
class RulesAbstractPluginUI extends RulesPluginUI {
|
888
|
|
889
|
/**
|
890
|
* Overridden to invoke the abstract plugins form alter callback and to add
|
891
|
* the negation checkbox for conditions.
|
892
|
*/
|
893
|
public function form(&$form, &$form_state, $options = array()) {
|
894
|
parent::form($form, $form_state, $options);
|
895
|
|
896
|
if ($this->element instanceof RulesCondition) {
|
897
|
$form['negate'] = array(
|
898
|
'#title' => t('Negate'),
|
899
|
'#type' => 'checkbox',
|
900
|
'#description' => t('If checked, the condition result is negated such that it returns TRUE if it evaluates to FALSE.'),
|
901
|
'#default_value' => $this->element->isNegated(),
|
902
|
'#weight' => 5,
|
903
|
);
|
904
|
}
|
905
|
$this->element->call('form_alter', array(&$form, &$form_state, $options));
|
906
|
}
|
907
|
|
908
|
public function form_extract_values($form, &$form_state) {
|
909
|
parent::form_extract_values($form, $form_state);
|
910
|
$form_values = RulesPluginUI::getFormStateValues($form, $form_state);
|
911
|
if ($this->element instanceof RulesCondition && isset($form_values['negate'])) {
|
912
|
$this->element->negate($form_values['negate']);
|
913
|
}
|
914
|
}
|
915
|
|
916
|
public function form_validate($form, &$form_state) {
|
917
|
parent::form_validate($form, $form_state);
|
918
|
// Validate the edited element and throw validation errors if it fails.
|
919
|
try {
|
920
|
$this->element->integrityCheck();
|
921
|
}
|
922
|
catch (RulesIntegrityException $e) {
|
923
|
form_set_error(implode('][', $e->keys), $e->getMessage());
|
924
|
}
|
925
|
}
|
926
|
}
|
927
|
|
928
|
/**
|
929
|
* UI for Rules Container.
|
930
|
*/
|
931
|
class RulesContainerPluginUI extends RulesPluginUI {
|
932
|
|
933
|
/**
|
934
|
* Generates a table for editing the contained elements.
|
935
|
*/
|
936
|
public function form(&$form, &$form_state, $options = array(), $iterator = NULL) {
|
937
|
parent::form($form, $form_state, $options);
|
938
|
$form['elements'] = array(
|
939
|
// Hide during creation or for embedded elements.
|
940
|
'#access' => empty($options['init']) && $this->element->isRoot(),
|
941
|
'#tree' => TRUE,
|
942
|
'#theme' => 'rules_elements',
|
943
|
'#empty' => t('None'),
|
944
|
'#caption' => t('Elements')
|
945
|
);
|
946
|
$form['elements']['#attributes']['class'][] = 'rules-container-plugin';
|
947
|
|
948
|
// Recurse over all element childrens or use the provided iterator.
|
949
|
$iterator = isset($iterator) ? $iterator : $this->element->elements();
|
950
|
$root_depth = $this->element->depth();
|
951
|
foreach ($iterator as $key => $child) {
|
952
|
$id = $child->elementId();
|
953
|
|
954
|
// Do not render rules as container element when displayed in a rule set.
|
955
|
$is_container = $child instanceof RulesContainerPlugin && !($child instanceof Rule);
|
956
|
$form['elements'][$id] = array(
|
957
|
'#depth' => $child->depth() - $root_depth - 1,
|
958
|
'#container' => $is_container,
|
959
|
);
|
960
|
$form['elements'][$id]['label'] = $child->buildContent();
|
961
|
$form['elements'][$id]['weight'] = array(
|
962
|
'#type' => 'weight',
|
963
|
'#default_value' => $child->weight,
|
964
|
'#delta' => 50,
|
965
|
);
|
966
|
$form['elements'][$id]['parent_id'] = array(
|
967
|
'#type' => 'hidden',
|
968
|
// If another iterator is passed in, the childs parent may not equal
|
969
|
// the current element. Thus ask the child for its parent.
|
970
|
'#default_value' => $child->parentElement()->elementId(),
|
971
|
);
|
972
|
$form['elements'][$id]['element_id'] = array(
|
973
|
'#type' => 'hidden',
|
974
|
'#default_value' => $id,
|
975
|
);
|
976
|
$form['elements'][$id]['operations'] = $child->operations();
|
977
|
}
|
978
|
|
979
|
// Alter the submit button label.
|
980
|
if (!empty($options['button']) && !empty($options['init'])) {
|
981
|
$form['submit']['#value'] = t('Continue');
|
982
|
}
|
983
|
elseif (!empty($options['button']) && $this->element->isRoot()) {
|
984
|
$form['submit']['#value'] = t('Save changes');
|
985
|
}
|
986
|
}
|
987
|
|
988
|
/**
|
989
|
* Applies the values of the form to the given rule configuration.
|
990
|
*/
|
991
|
public function form_extract_values($form, &$form_state) {
|
992
|
parent::form_extract_values($form, $form_state);
|
993
|
$values = RulesPluginUI::getFormStateValues($form, $form_state);
|
994
|
// Now apply the new hierarchy.
|
995
|
if (isset($values['elements'])) {
|
996
|
foreach ($values['elements'] as $id => $data) {
|
997
|
$child = $this->element->elementMap()->lookup($id);
|
998
|
$child->weight = $data['weight'];
|
999
|
$parent = $this->element->elementMap()->lookup($data['parent_id']);
|
1000
|
$child->setParent($parent ? $parent : $this->element);
|
1001
|
}
|
1002
|
$this->element->sortChildren(TRUE);
|
1003
|
}
|
1004
|
}
|
1005
|
|
1006
|
public function operations() {
|
1007
|
$ops = parent::operations();
|
1008
|
$add_ops = self::addOperations();
|
1009
|
$ops['#links'] += $add_ops['#links'];
|
1010
|
return $ops;
|
1011
|
}
|
1012
|
|
1013
|
/**
|
1014
|
* Gets the Add-* operations for the given element.
|
1015
|
*/
|
1016
|
public function addOperations() {
|
1017
|
$name = $this->element->root()->name;
|
1018
|
$render = array(
|
1019
|
'#theme' => 'links__rules',
|
1020
|
);
|
1021
|
$render['#attributes']['class'][] = 'rules-operations-add';
|
1022
|
$render['#attributes']['class'][] = 'action-links';
|
1023
|
foreach (rules_fetch_data('plugin_info') as $plugin => $info) {
|
1024
|
if (!empty($info['embeddable']) && $this->element instanceof $info['embeddable']) {
|
1025
|
$render['#links']['add_' . $plugin] = array(
|
1026
|
'title' => t('Add !name', array('!name' => $plugin)),
|
1027
|
'href' => RulesPluginUI::path($name, 'add', $this->element, $plugin),
|
1028
|
);
|
1029
|
}
|
1030
|
}
|
1031
|
return $render;
|
1032
|
}
|
1033
|
|
1034
|
|
1035
|
public function buildContent() {
|
1036
|
$content = parent::buildContent();
|
1037
|
// Don't link the title for embedded container plugins, except for rules.
|
1038
|
if (!$this->element->isRoot() && !($this->element instanceof Rule)) {
|
1039
|
$content['label']['#type'] = 'markup';
|
1040
|
$content['label']['#markup'] = check_plain($content['label']['#title']);
|
1041
|
unset($content['label']['#title']);
|
1042
|
}
|
1043
|
elseif ($this->element->isRoot()) {
|
1044
|
$content['description']['settings'] = array(
|
1045
|
'#theme' => 'rules_content_group',
|
1046
|
'#weight' => -4,
|
1047
|
'machine_name' => array(
|
1048
|
'#markup' => t('Machine name') . ': ' . $this->element->name,
|
1049
|
),
|
1050
|
'weight' => array(
|
1051
|
'#access' => $this->element instanceof RulesTriggerableInterface,
|
1052
|
'#markup' => t('Weight') . ': ' . $this->element->weight,
|
1053
|
),
|
1054
|
);
|
1055
|
if (!empty($this->element->tags)) {
|
1056
|
$content['description']['tags'] = array(
|
1057
|
'#theme' => 'rules_content_group',
|
1058
|
'#caption' => t('Tags'),
|
1059
|
'tags' => array(
|
1060
|
'#markup' => check_plain(drupal_implode_tags($this->element->tags)),
|
1061
|
),
|
1062
|
);
|
1063
|
}
|
1064
|
if ($vars = $this->element->componentVariables()) {
|
1065
|
$content['description']['variables'] = array(
|
1066
|
'#caption' => t('Parameter'),
|
1067
|
'#theme' => 'rules_content_group',
|
1068
|
);
|
1069
|
foreach ($vars as $name => $info) {
|
1070
|
if (!isset($info['parameter']) || $info['parameter']) {
|
1071
|
$content['description']['variables'][$name] = array(
|
1072
|
'#theme' => 'rules_variable_view',
|
1073
|
'#info' => $info,
|
1074
|
'#name' => $name,
|
1075
|
);
|
1076
|
}
|
1077
|
}
|
1078
|
}
|
1079
|
}
|
1080
|
return $content;
|
1081
|
}
|
1082
|
}
|
1083
|
|
1084
|
/**
|
1085
|
* UI for Rules condition container.
|
1086
|
*/
|
1087
|
class RulesConditionContainerUI extends RulesContainerPluginUI {
|
1088
|
|
1089
|
public function form(&$form, &$form_state, $options = array(), $iterator = NULL) {
|
1090
|
parent::form($form, $form_state, $options, $iterator);
|
1091
|
// Add the add-* operation links.
|
1092
|
$form['elements']['#add'] = self::addOperations();
|
1093
|
$form['elements']['#attributes']['class'][] = 'rules-condition-container';
|
1094
|
$form['elements']['#caption'] = t('Conditions');
|
1095
|
|
1096
|
// By default skip
|
1097
|
if (!empty($options['init']) && !$this->element->isRoot()) {
|
1098
|
$config = $this->element->root();
|
1099
|
$form['init_help'] = array(
|
1100
|
'#type' => 'container',
|
1101
|
'#id' => 'rules-plugin-add-help',
|
1102
|
'content' => array(
|
1103
|
'#markup' => t('You are about to add a new @plugin to the @config-plugin %label. Use indentation to make conditions a part of this logic group. See <a href="@url">the online documentation</a> for more information on condition sets.',
|
1104
|
array('@plugin' => $this->element->plugin(),
|
1105
|
'@config-plugin' => $config->plugin(),
|
1106
|
'%label' => $config->label(),
|
1107
|
'@url' => rules_external_help('condition-components'))),
|
1108
|
),
|
1109
|
);
|
1110
|
}
|
1111
|
$form['negate'] = array(
|
1112
|
'#title' => t('Negate'),
|
1113
|
'#type' => 'checkbox',
|
1114
|
'#description' => t('If checked, the condition result is negated such that it returns TRUE if it evaluates to FALSE.'),
|
1115
|
'#default_value' => $this->element->isNegated(),
|
1116
|
'#weight' => 5,
|
1117
|
);
|
1118
|
}
|
1119
|
|
1120
|
public function form_extract_values($form, &$form_state) {
|
1121
|
parent::form_extract_values($form, $form_state);
|
1122
|
$form_values = RulesPluginUI::getFormStateValues($form, $form_state);
|
1123
|
if (isset($form_values['negate'])) {
|
1124
|
$this->element->negate($form_values['negate']);
|
1125
|
}
|
1126
|
}
|
1127
|
}
|
1128
|
|
1129
|
/**
|
1130
|
* UI for Rules action container.
|
1131
|
*/
|
1132
|
class RulesActionContainerUI extends RulesContainerPluginUI {
|
1133
|
|
1134
|
public function form(&$form, &$form_state, $options = array(), $iterator = NULL) {
|
1135
|
parent::form($form, $form_state, $options, $iterator);
|
1136
|
// Add the add-* operation links.
|
1137
|
$form['elements']['#add'] = self::addOperations();
|
1138
|
$form['elements']['#attributes']['class'][] = 'rules-action-container';
|
1139
|
$form['elements']['#caption'] = t('Actions');
|
1140
|
}
|
1141
|
}
|
1142
|
|
1143
|
/**
|
1144
|
* Class holding category related methods.
|
1145
|
*/
|
1146
|
class RulesUICategory {
|
1147
|
|
1148
|
/**
|
1149
|
* Gets info about all available categories, or about a specific category.
|
1150
|
*
|
1151
|
* @return array
|
1152
|
*/
|
1153
|
public static function getInfo($category = NULL) {
|
1154
|
$data = rules_fetch_data('category_info');
|
1155
|
if (isset($category)) {
|
1156
|
return $data[$category];
|
1157
|
}
|
1158
|
return $data;
|
1159
|
}
|
1160
|
|
1161
|
/**
|
1162
|
* Returns a group label, e.g. as usable for opt-groups in a select list.
|
1163
|
*
|
1164
|
* @param array $item_info
|
1165
|
* The info-array of an item, e.g. an entry of hook_rules_action_info().
|
1166
|
* @param bool $in_category
|
1167
|
* (optional) Whether group labels for grouping inside a category should be
|
1168
|
* return. Defaults to FALSE.
|
1169
|
*
|
1170
|
* @return string|boolean
|
1171
|
* The group label to use, or FALSE if none can be found.
|
1172
|
*/
|
1173
|
public static function getItemGroup($item_info, $in_category = FALSE) {
|
1174
|
if (isset($item_info['category']) && !$in_category) {
|
1175
|
return self::getCategory($item_info, 'label');
|
1176
|
}
|
1177
|
else if (!empty($item_info['group'])) {
|
1178
|
return $item_info['group'];
|
1179
|
}
|
1180
|
return FALSE;
|
1181
|
}
|
1182
|
|
1183
|
/**
|
1184
|
* Gets the category for the given item info array.
|
1185
|
*
|
1186
|
* @param array $item_info
|
1187
|
* The info-array of an item, e.g. an entry of hook_rules_action_info().
|
1188
|
* @param string|null $key
|
1189
|
* (optional) The key of the category info to return, e.g. 'label'. If none
|
1190
|
* is given the whole info array is returned.
|
1191
|
*
|
1192
|
* @return array|mixed|false
|
1193
|
* Either the whole category info array or the value of the given key. If
|
1194
|
* no category can be found, FALSE is returned.
|
1195
|
*/
|
1196
|
public static function getCategory($item_info, $key = NULL) {
|
1197
|
if (isset($item_info['category'])) {
|
1198
|
$info = self::getInfo($item_info['category']);
|
1199
|
return isset($key) ? $info[$key] : $info;
|
1200
|
}
|
1201
|
return FALSE;
|
1202
|
}
|
1203
|
|
1204
|
/**
|
1205
|
* Returns an array of options to use with a select for the items specified
|
1206
|
* in the given hook.
|
1207
|
*
|
1208
|
* @param $item_type
|
1209
|
* The item type to get options for. One of 'data', 'event', 'condition' and
|
1210
|
* 'action'.
|
1211
|
* @param $items
|
1212
|
* (optional) An array of items to restrict the options to.
|
1213
|
*
|
1214
|
* @return
|
1215
|
* An array of options.
|
1216
|
*/
|
1217
|
public static function getOptions($item_type, $items = NULL) {
|
1218
|
$sorted_data = array();
|
1219
|
$ungrouped = array();
|
1220
|
$data = $items ? $items : rules_fetch_data($item_type . '_info');
|
1221
|
foreach ($data as $name => $info) {
|
1222
|
// Verfiy the current user has access to use it.
|
1223
|
if (!user_access('bypass rules access') && !empty($info['access callback']) && !call_user_func($info['access callback'], $item_type, $name)) {
|
1224
|
continue;
|
1225
|
}
|
1226
|
if ($group = RulesUICategory::getItemGroup($info)) {
|
1227
|
$sorted_data[drupal_ucfirst($group)][$name] = drupal_ucfirst($info['label']);
|
1228
|
}
|
1229
|
else {
|
1230
|
$ungrouped[$name] = drupal_ucfirst($info['label']);
|
1231
|
}
|
1232
|
}
|
1233
|
asort($ungrouped);
|
1234
|
foreach ($sorted_data as $key => $choices) {
|
1235
|
asort($choices);
|
1236
|
$sorted_data[$key] = $choices;
|
1237
|
}
|
1238
|
|
1239
|
// Sort the grouped data by category weights, defaulting to weight 0 for
|
1240
|
// groups without a respective category.
|
1241
|
$sorted_groups = array();
|
1242
|
foreach (array_keys($sorted_data) as $label) {
|
1243
|
$sorted_groups[$label] = array('weight' => 0, 'label' => $label);
|
1244
|
}
|
1245
|
// Add in category weights.
|
1246
|
foreach (RulesUICategory::getInfo() as $info) {
|
1247
|
if (isset($sorted_groups[$info['label']])) {
|
1248
|
$sorted_groups[$info['label']] = $info;
|
1249
|
}
|
1250
|
}
|
1251
|
uasort($sorted_groups, '_rules_ui_sort_categories');
|
1252
|
|
1253
|
// Now replace weights with group content.
|
1254
|
foreach ($sorted_groups as $group => $weight) {
|
1255
|
$sorted_groups[$group] = $sorted_data[$group];
|
1256
|
}
|
1257
|
return $ungrouped + $sorted_groups;
|
1258
|
}
|
1259
|
}
|
1260
|
|
1261
|
/**
|
1262
|
* Helper for sorting categories.
|
1263
|
*/
|
1264
|
function _rules_ui_sort_categories($a, $b) {
|
1265
|
// @see element_sort()
|
1266
|
$a_weight = isset($a['weight']) ? $a['weight'] : 0;
|
1267
|
$b_weight = isset($b['weight']) ? $b['weight'] : 0;
|
1268
|
if ($a_weight == $b_weight) {
|
1269
|
// @see element_sort_by_title()
|
1270
|
$a_title = isset($a['label']) ? $a['label'] : '';
|
1271
|
$b_title = isset($b['label']) ? $b['label'] : '';
|
1272
|
return strnatcasecmp($a_title, $b_title);
|
1273
|
}
|
1274
|
return ($a_weight < $b_weight) ? -1 : 1;
|
1275
|
}
|