1 |
85ad3d82
|
Assos Assos
|
<?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 |
|
|
} |