From d58ca7556dc167a0095cb0ffbe1a1172903e582f Mon Sep 17 00:00:00 2001 From: Daniel Sasser Date: Tue, 4 Oct 2016 13:25:59 -0700 Subject: [PATCH] #2799361 - Add drag and drop to actions and conditions from #2648334. --- config/schema/rules.expression.schema.yml | 18 +++ src/Engine/ExpressionBase.php | 42 +++++++ src/Engine/ExpressionInterface.php | 31 +++++ src/Form/Expression/ActionContainerForm.php | 108 ++++++++++++++---- .../Expression/ConditionContainerForm.php | 107 +++++++++++++---- src/Form/Expression/RuleForm.php | 10 ++ src/Form/ReactionRuleEditForm.php | 2 + src/Plugin/RulesExpression/ActionSet.php | 10 ++ src/Plugin/RulesExpression/RulesAnd.php | 10 ++ src/Plugin/RulesExpression/RulesLoop.php | 11 ++ src/Plugin/RulesExpression/RulesOr.php | 10 ++ 11 files changed, 316 insertions(+), 43 deletions(-) diff --git a/config/schema/rules.expression.schema.yml b/config/schema/rules.expression.schema.yml index ab6d4068..1af97121 100644 --- a/config/schema/rules.expression.schema.yml +++ b/config/schema/rules.expression.schema.yml @@ -7,6 +7,9 @@ rules_expression: uuid: type: string label: 'UUID' + weight: + type: integer + label: 'Weight' rules_expression.rules_condition: type: rules_expression @@ -18,6 +21,9 @@ rules_expression.rules_condition: uuid: type: string label: 'UUID' + weight: + type: integer + label: 'Weight' condition_id: type: string label: 'Condition plugin ID' @@ -47,6 +53,9 @@ rules_expression.rules_action: uuid: type: string label: 'UUID' + weight: + type: integer + label: 'Weight' action_id: type: string label: 'Action plugin ID' @@ -73,6 +82,9 @@ rules_expression.rules_and: uuid: type: string label: 'UUID' + weight: + type: integer + label: 'Weight' negate: type: boolean label: 'Negate' @@ -92,6 +104,9 @@ rules_expression.rules_action_set: uuid: type: string label: 'UUID' + weight: + type: integer + label: 'Weight' actions: type: sequence label: 'Actions' @@ -108,6 +123,9 @@ rules_expression.rules_rule: uuid: type: string label: 'UUID' + weight: + type: integer + label: 'Weight' conditions: type: rules_expression.[id] label: 'Conditions' diff --git a/src/Engine/ExpressionBase.php b/src/Engine/ExpressionBase.php index 7eb6d295..3f2b0df4 100644 --- a/src/Engine/ExpressionBase.php +++ b/src/Engine/ExpressionBase.php @@ -37,6 +37,13 @@ abstract class ExpressionBase extends PluginBase implements ExpressionInterface */ protected $uuid; + /** + * The weight of this expression. + * + * @var integer + */ + protected $weight; + /** * Constructor. * @@ -71,6 +78,7 @@ public function getConfiguration() { return [ 'id' => $this->getPluginId(), 'uuid' => $this->uuid, + 'weight' => $this->weight, ] + $this->configuration; } @@ -82,6 +90,13 @@ public function setConfiguration(array $configuration) { if (isset($configuration['uuid'])) { $this->uuid = $configuration['uuid']; } + if (isset($configuration['weight'])) { + $this->weight = $configuration['weight']; + } + else { + $this->weight = 0; + } + return $this; } @@ -148,4 +163,31 @@ public function setUuid($uuid) { $this->uuid = $uuid; } + /** + * {@inheritdoc} + */ + public function getWeight() { + return $this->weight; + } + + /** + * {@inheritdoc} + */ + public function setWeight($weight) { + $this->weight = $weight; + } + + /** + * {@inheritdoc} + */ + public function expressionSortHelper(ExpressionInterface $a, ExpressionInterface $b) { + $a_weight = $a->getWeight(); + $b_weight = $b->getWeight(); + if ($a_weight == $b_weight) { + return 0; + } + + return ($a_weight < $b_weight) ? -1 : 1; + } + } diff --git a/src/Engine/ExpressionInterface.php b/src/Engine/ExpressionInterface.php index a3c43b60..5c4875cb 100644 --- a/src/Engine/ExpressionInterface.php +++ b/src/Engine/ExpressionInterface.php @@ -79,6 +79,37 @@ public function getUuid(); */ public function setUuid($uuid); + /** + * Returns the weight of this expression. + * + * @return int + * The weight of this expression. + */ + public function getWeight(); + + /** + * Sets the weight of this expression in an expression tree. + * + * @param int $weight + * The weight to set. + */ + public function setWeight($weight); + + /** + * Sorts an array of expressions by 'weight' property. + * + * Callback for uasort(). + * + * @param \Drupal\rules\Engine\ExpressionInterface $a + * First item for comparison. + * @param \Drupal\rules\Engine\ExpressionInterface $b + * Second item for comparison. + * + * @return int + * The comparison result for uasort(). + */ + public function expressionSortHelper(ExpressionInterface $a, ExpressionInterface $b); + /** * Verifies that this expression is configured correctly. * diff --git a/src/Form/Expression/ActionContainerForm.php b/src/Form/Expression/ActionContainerForm.php index 254793ba..9eb0a69e 100644 --- a/src/Form/Expression/ActionContainerForm.php +++ b/src/Form/Expression/ActionContainerForm.php @@ -39,31 +39,75 @@ public function form(array $form, FormStateInterface $form_state) { ]; $form['action_table']['table'] = [ - '#theme' => 'table', - '#caption' => $this->t('Actions'), - '#header' => [$this->t('Elements'), $this->t('Operations')], - '#empty' => t('None'), + '#type' => 'table', + '#header' => [ + $this->t('Elements'), + $this->t('Weight'), + [ + 'data' => $this->t('Operations'), + 'colspan' => 3, + ], + ], + '#attributes' => [ + 'id' => 'rules_actions_table', + ], + '#tabledrag' => [ + [ + 'action' => 'order', + 'relationship' => 'sibling', + 'group' => 'action-weight', + ], + ], ]; + $form['action_table']['table']['#empty'] = $this->t('None'); + + // Get hold of actions. + // @todo See if we can add getExpressions method of ExpressionContainerBase. + $actions = []; foreach ($this->actionSet as $action) { - $form['action_table']['table']['#rows'][] = [ - 'element' => $action->getLabel(), - 'operations' => [ - 'data' => [ - '#type' => 'dropbutton', - '#links' => [ - 'edit' => [ - 'title' => $this->t('Edit'), - 'url' => $this->getRulesUiHandler()->getUrlFromRoute('expression.edit', [ - 'uuid' => $action->getUuid(), - ]), - ], - 'delete' => [ - 'title' => $this->t('Delete'), - 'url' => $this->getRulesUiHandler()->getUrlFromRoute('expression.delete', [ - 'uuid' => $action->getUuid(), - ]), - ], + $actions[] = $action; + } + + // Sort actions by weight. + @uasort($actions, [$this->actionSet, 'expressionSortHelper']); + + foreach ($actions as $action) { + /* @var $action \Drupal\rules\Engine\ExpressionInterface */ + $uuid = $action->getUuid(); + $row = &$form['action_table']['table'][$uuid]; + + // TableDrag: Mark the table row as draggable. + $row['#attributes']['class'][] = 'draggable'; + + // TableDrag: Sort the table row according to its existing weight. + $row['#weight'] = $action->getWeight(); + $row['title'] = ['#markup' => $action->getLabel()]; + + $row['weight'] = [ + '#type' => 'weight', + '#delta' => 50, + '#default_value' => $action->getWeight(), + '#attributes' => ['class' => ['action-weight']], + ]; + + // Operations (dropbutton) column. + $rules_ui_handler = $this->getRulesUiHandler(); + $row['operations'] = [ + 'data' => [ + '#type' => 'dropbutton', + '#links' => [ + 'edit' => [ + 'title' => $this->t('Edit'), + 'url' => $rules_ui_handler->getUrlFromRoute('expression.edit', [ + 'uuid' => $uuid, + ]), + ], + 'delete' => [ + 'title' => $this->t('Delete'), + 'url' => $rules_ui_handler->getUrlFromRoute('expression.delete', [ + 'uuid' => $uuid, + ]), ], ], ], @@ -85,4 +129,24 @@ public function form(array $form, FormStateInterface $form_state) { return $form; } + /** + * {@inheritdoc} + */ + public function submitForm(array &$form, FormStateInterface $form_state) { + $values = $form_state->getValue('table'); + $component = $this->getRulesUiHandler()->getComponent(); + /* @var $rule_expression \Drupal\rules\Plugin\RulesExpression\Rule */ + $rule_expression = $component->getExpression(); + + if ($values) { + foreach ($values as $uuid => $expression) { + $action = $rule_expression->getExpression($uuid); + $action->setWeight($expression['weight']); + $action->setConfiguration($action->getConfiguration()); + } + } + + $this->getRulesUiHandler()->updateComponent($component); + } + } diff --git a/src/Form/Expression/ConditionContainerForm.php b/src/Form/Expression/ConditionContainerForm.php index 6a23fbba..029c9244 100644 --- a/src/Form/Expression/ConditionContainerForm.php +++ b/src/Form/Expression/ConditionContainerForm.php @@ -39,31 +39,76 @@ public function form(array $form, FormStateInterface $form_state) { ]; $form['conditions']['table'] = [ - '#theme' => 'table', + '#type' => 'table', '#caption' => $this->t('Conditions'), - '#header' => [$this->t('Elements'), $this->t('Operations')], - '#empty' => t('None'), + '#header' => [ + $this->t('Elements'), + $this->t('Weight'), + [ + 'data' => $this->t('Operations'), + 'colspan' => 3, + ], + ], + '#attributes' => [ + 'id' => 'rules_conditions_table', + ], + '#tabledrag' => [ + [ + 'action' => 'order', + 'relationship' => 'sibling', + 'group' => 'condition-weight', + ], + ], ]; + $form['conditions']['table']['#empty'] = $this->t('None'); + + // Get hold of conditions. + // @todo See if we can add getExpressions method of ExpressionContainerBase. + $conditions = []; foreach ($this->conditionContainer as $condition) { - $form['conditions']['table']['#rows'][] = [ - 'element' => $condition->getLabel(), - 'operations' => [ - 'data' => [ - '#type' => 'dropbutton', - '#links' => [ - 'edit' => [ - 'title' => $this->t('Edit'), - 'url' => $this->getRulesUiHandler()->getUrlFromRoute('expression.edit', [ - 'uuid' => $condition->getUuid(), - ]), - ], - 'delete' => [ - 'title' => $this->t('Delete'), - 'url' => $this->getRulesUiHandler()->getUrlFromRoute('expression.delete', [ - 'uuid' => $condition->getUuid(), - ]), - ], + $conditions[] = $condition; + } + + // Sort conditions by weight. + @uasort($conditions, [$this->conditionContainer, 'expressionSortHelper']); + + foreach ($conditions as $condition) { + /* @var $condition \Drupal\rules\Engine\ExpressionInterface */ + $uuid = $condition->getUuid(); + $row = &$form['conditions']['table'][$uuid]; + + // TableDrag: Mark the table row as draggable. + $row['#attributes']['class'][] = 'draggable'; + + // TableDrag: Sort the table row according to its weight. + $row['#weight'] = $condition->getWeight(); + $row['title'] = ['#markup' => $condition->getLabel()]; + + $row['weight'] = [ + '#type' => 'weight', + '#delta' => 50, + '#default_value' => $condition->getWeight(), + '#attributes' => ['class' => ['condition-weight']], + ]; + + // Operations (dropbutton) column. + $rules_ui_handler = $this->getRulesUiHandler(); + $row['operations'] = [ + 'data' => [ + '#type' => 'dropbutton', + '#links' => [ + 'edit' => [ + 'title' => $this->t('Edit'), + 'url' => $rules_ui_handler->getUrlFromRoute('expression.edit', [ + 'uuid' => $condition->getUuid(), + ]), + ], + 'delete' => [ + 'title' => $this->t('Delete'), + 'url' => $rules_ui_handler->getUrlFromRoute('expression.delete', [ + 'uuid' => $condition->getUuid(), + ]), ], ], ], @@ -85,4 +130,24 @@ public function form(array $form, FormStateInterface $form_state) { return $form; } + /** + * {@inheritdoc} + */ + public function submitForm(array &$form, FormStateInterface $form_state) { + $values = $form_state->getValue('table'); + $component = $this->getRulesUiHandler()->getComponent(); + /* @var $rule_expression \Drupal\rules\Plugin\RulesExpression\Rule */ + $rule_expression = $component->getExpression(); + + if ($values) { + foreach ($values as $uuid => $expression) { + $action = $rule_expression->getExpression($uuid); + $action->setWeight($expression['weight']); + $action->setConfiguration($action->getConfiguration()); + } + } + + $this->getRulesUiHandler()->updateComponent($component); + } + } diff --git a/src/Form/Expression/RuleForm.php b/src/Form/Expression/RuleForm.php index 49c1635f..67cad998 100644 --- a/src/Form/Expression/RuleForm.php +++ b/src/Form/Expression/RuleForm.php @@ -41,4 +41,14 @@ public function form(array $form, FormStateInterface $form_state) { return $form; } + /** + * {@inheritdoc} + */ + public function submitForm(array &$form, FormStateInterface $form_state) { + $conditions = $this->rule->getConditions(); + $conditions->getFormHandler()->submitForm($form, $form_state); + $actions = $this->rule->getActions(); + $actions->getFormHandler()->submitForm($form, $form_state); + } + } diff --git a/src/Form/ReactionRuleEditForm.php b/src/Form/ReactionRuleEditForm.php index 1ef7235a..efae6581 100644 --- a/src/Form/ReactionRuleEditForm.php +++ b/src/Form/ReactionRuleEditForm.php @@ -113,6 +113,8 @@ protected function actions(array $form, FormStateInterface $form_state) { */ public function save(array $form, FormStateInterface $form_state) { $this->rulesUiHandler->getForm()->submitForm($form, $form_state); + $component = $this->rulesUiHandler->getComponent(); + $this->entity->updateFromComponent($component); // Persist changes by saving the entity. parent::save($form, $form_state); diff --git a/src/Plugin/RulesExpression/ActionSet.php b/src/Plugin/RulesExpression/ActionSet.php index 3284fa9b..9fae3797 100644 --- a/src/Plugin/RulesExpression/ActionSet.php +++ b/src/Plugin/RulesExpression/ActionSet.php @@ -27,7 +27,17 @@ protected function allowsMetadataAssertions() { * {@inheritdoc} */ public function executeWithState(ExecutionStateInterface $state) { + // Get hold of actions. + // @todo See if we can add getExpressions method of ExpressionContainerBase. + $actions = []; foreach ($this->actions as $action) { + $actions[] = $action; + } + + // Sort actions by weight. + @uasort($actions, [$this->actions, 'expressionSortHelper']); + foreach ($actions as $action) { + /* @var $action \Drupal\rules\Engine\ExpressionInterface */ $action->executeWithState($state); } } diff --git a/src/Plugin/RulesExpression/RulesAnd.php b/src/Plugin/RulesExpression/RulesAnd.php index f1e5b61f..1d509a51 100644 --- a/src/Plugin/RulesExpression/RulesAnd.php +++ b/src/Plugin/RulesExpression/RulesAnd.php @@ -32,7 +32,17 @@ public function isEmpty() { * {@inheritdoc} */ public function evaluate(ExecutionStateInterface $state) { + // Get hold of conditions. + // @todo See if we can add getExpressions method of ExpressionContainerBase. + $conditions = []; foreach ($this->conditions as $condition) { + $conditions[] = $condition; + } + + // Sort conditions by weight. + @uasort($conditions, [$this->conditions, 'expressionSortHelper']); + foreach ($conditions as $condition) { + /* @var $condition \Drupal\rules\Engine\ExpressionInterface */ if (!$condition->executeWithState($state)) { return FALSE; } diff --git a/src/Plugin/RulesExpression/RulesLoop.php b/src/Plugin/RulesExpression/RulesLoop.php index 892eb861..b0e2150f 100644 --- a/src/Plugin/RulesExpression/RulesLoop.php +++ b/src/Plugin/RulesExpression/RulesLoop.php @@ -38,7 +38,18 @@ public function executeWithState(ExecutionStateInterface $state) { foreach ($list_data as $item) { $state->setVariableData($list_item_name, $item); + + // Get hold of actions. + // @todo See if we can add getExpressions method of ExpressionContainerBase. + $actions = []; foreach ($this->actions as $action) { + $actions[] = $action; + } + + // Sort actions by weight. + @uasort($actions, [$this->actions, 'expressionSortHelper']); + foreach ($actions as $action) { + /* @var $action \Drupal\rules\Engine\ExpressionInterface */ $action->executeWithState($state); } } diff --git a/src/Plugin/RulesExpression/RulesOr.php b/src/Plugin/RulesExpression/RulesOr.php index a599161d..7eedca9b 100644 --- a/src/Plugin/RulesExpression/RulesOr.php +++ b/src/Plugin/RulesExpression/RulesOr.php @@ -19,7 +19,17 @@ class RulesOr extends ConditionExpressionContainer { * {@inheritdoc} */ public function evaluate(ExecutionStateInterface $state) { + // Get hold of conditions. + // @todo See if we can add getExpressions method of ExpressionContainerBase. + $conditions = []; foreach ($this->conditions as $condition) { + $conditions[] = $condition; + } + + // Sort conditions by weight. + @uasort($conditions, [$this->conditions, 'expressionSortHelper']); + foreach ($conditions as $condition) { + /* @var $condition \Drupal\rules\Engine\ExpressionInterface */ if ($condition->executeWithState($state)) { return TRUE; }