From 4ab097eae7758be3802a773437c34be58164e52c Mon Sep 17 00:00:00 2001 From: jpayne Date: Thu, 16 Feb 2012 16:54:42 -0500 Subject: [PATCH] Issue #1421368 by acrazyanimal: Adding an update entity action so rules can modify multiple entity properties all at once. --- modules/entity.eval.inc | 52 ++++++++++++++++++++++ modules/entity.rules.inc | 108 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 160 insertions(+), 0 deletions(-) diff --git a/modules/entity.eval.inc b/modules/entity.eval.inc index 6ae5331..96e7f12 100644 --- a/modules/entity.eval.inc +++ b/modules/entity.eval.inc @@ -138,6 +138,58 @@ function rules_action_entity_delete($wrapper, $settings, $state, $element) { } /** + * Action: Update entity. + */ +function rules_action_entity_update($args, $element) { + $wrapper = $args['data']; + if ($wrapper instanceof EntityDrupalWrapper) { + foreach ($element->pluginParameterInfo() as $name => $info) { + if (($name != 'data') && ($name != 'props')) { + try { + // Update the value of each property, if possible. + $prop = $wrapper->get(substr($name, 6)); + $prop->set($args[$name]); + } + catch (EntityMetadataWrapperException $e) { + throw new RulesEvaluationException('Unable to update "@name" property data for "@selector": ' . $e->getMessage(), array('@name' => $name, '@selector' => $settings['data:select'])); + } + } + } + } +} + +/** + * Info alter callback for the entity_update action. + */ +function rules_action_entity_update_info_alter(&$element_info, $element) { + $element->settings += array('data:select' => NULL); + if ($wrapper = $element->applyDataSelector($element->settings['data:select'])) { + $label = $wrapper->type(); + if ($wrapper->getPropertyInfo()) { + $element_info['parameter']['props'] = array ( + 'type' => 'list', + 'label' => t('@label\'s parameter(s) to update', array('@label' => ($label) ? $label : 'Entity')), + //'label' => t('test'), + 'description' => t('Check the properties that you would like to update for this entity.'), + 'options list' => 'rules_action_entity_update_properties_list_options_list', + ); + } + if (isset($element->settings['props']) && !empty($element->settings['props'])) { + // Add the data type's needed parameter for loading to the parameter info. + foreach ($wrapper as $name => $child) { + $childinfo = $child->info(); + if (isset($element->settings['props'][$name])) { + $childinfo += array('type' => 'text'); + // Prefix parameter names to avoid name clashes with existing parameters. + $element_info['parameter']['param_' . $name] = array_intersect_key($childinfo, array_flip(array('type', 'label', 'description'))); + $element_info['parameter']['param_' . $name]['options list'] = $child->optionsList() ? 'rules_action_entity_update_parameter_options_list' : FALSE; + } + } + } + } +} + +/** * Condition: Entity is new. */ function rules_condition_entity_is_new($wrapper, $settings, $state, $element) { diff --git a/modules/entity.rules.inc b/modules/entity.rules.inc index d6ab083..6f6652c 100644 --- a/modules/entity.rules.inc +++ b/modules/entity.rules.inc @@ -162,6 +162,27 @@ function rules_entity_action_info() { 'access' => 'rules_action_entity_savedelete_access', ), ); + + $return['entity_update'] = array( + 'label' => t('Update entity'), + 'named parameter' => TRUE, + 'parameter' => array( + 'data' => array( + 'type' => 'entity', + 'label' => t('Entity'), + 'description' => t('Specifies the entity, for which you would like to update field/parameter values.'), + 'restriction' => 'selector', + 'wrapped' => TRUE, + ), + // Further needed parameters depends on the entity selected. + ), + 'group' => t('Entities'), + 'access callback' => 'rules_entity_action_access', + 'base' => 'rules_action_entity_update', + 'callbacks' => array( + 'access' => 'rules_action_entity_createfetch_access', + ), + ); return $return; } @@ -290,6 +311,93 @@ function rules_entity_type_options($key = NULL) { } /** + * Options list callback for a parameter of entity_update. + */ +function rules_action_entity_update_parameter_options_list(RulesPlugin $element, $param_name) { + // Remove the parameter name prefix 'param_'. + $property_name = substr($param_name, 6); + if ($wrapper = $element->applyDataSelector($element->settings['data:select'])) { + // The possible values of the "parameter" are those of the particular entity "property". + if (isset($wrapper->$property_name)) return $wrapper->$property_name->optionsList(); + } + return FALSE; +} + +/** + * Returns the options list of available properties for the chosen entity in entity_update. + */ +function rules_action_entity_update_properties_list_options_list(RulesAbstractPlugin $element, $parameter=null, $next=null) { + $options = array(); + if ($wrapper = $element->applyDataSelector($element->settings['data:select'])) { + foreach ($wrapper->getPropertyInfo() as $name => $info) { + $options[$name] = $info['label']; + } + } + return $options; +} + +/** + * Form alter callback for actions relying on the entity type or the data type. + */ +function rules_action_entity_update_form_alter(&$form, &$form_state, $options, RulesAbstractPlugin $element) { + $first_step = empty($element->settings['data:select']); + $second_step = (!$first_step && empty($element->settings['props'])); + $form['reload'] = array( + '#weight' => 5, + '#type' => 'submit', + '#name' => 'reload', + '#value' => $first_step ? t('Continue') : t('Reload form'), + '#limit_validation_errors' => array(array('parameter', 'data')), + '#submit' => array('rules_action_type_form_submit_rebuild'), + '#ajax' => rules_ui_form_default_ajax(), + '#description' => $first_step ? '' : t('Reload the form to correct the displayed property fields.'), + ); + // Use ajax and trigger as the reload button. + $form['parameter']['data']['settings']['data:select']['#ajax'] = $form['reload']['#ajax'] + array( + 'event' => 'change', + 'trigger_as' => array('name' => 'reload'), + ); + + if ($first_step || $second_step) { + // In the first step and second step only show relevant parameters. + foreach (element_children($form['parameter']) as $key) { + if (($key != 'data') && !($second_step && ($key == 'props'))) { + unset($form['parameter'][$key]); + } + } + unset($form['submit']); + } else { + // Remove parameters that should no longer be included in the form. + foreach (element_children($form['parameter']) as $key) { + if (($key != 'data') && ($key != 'props') && !isset($element->settings['props'][substr($key, 6)])) { + unset($form['parameter'][$key]); + } + } + // Change the data parameter to be not editable. + $form['parameter']['data']['settings']['#access'] = FALSE; + // TODO: improve display + $form['parameter']['data']['info'] = array( + '#prefix' => '

', + '#markup' => t('Selected data: %selector', array('%selector' => $element->settings['data:select'])), + '#suffix' => '

', + ); + // Hide the reload button in case js is enabled and it's not the first step. + $form['reload']['#attributes'] = array('class' => array('rules-hide-js')); + } + // Add #ajax to the property selection dropdown to reload the form. + if(isset($form['parameter']['props'])) { + $form['parameter']['props']['#ajax'] = rules_ui_form_default_ajax() + array( + 'event' => 'change', + 'trigger_as' => array('name' => 'reload'), + ); + } + + // Disable #ajax for the 'data:select' as it has troubles with lazy-loaded JS. + // @todo: Re-enable once JS lazy-loading is fixed in core. + unset($form['parameter']['data']['settings']['data:select']['#ajax']); +} + +/** * Entity actions access callback. * * Returns TRUE if at least one type is available for configuring the action. -- 1.7.2.3