/** * {@inheritdoc} */ protected function getEditedExpression(RulesComponent $component) { $component_expression = $component->getExpression(); if (!$component_expression instanceof ExpressionContainerInterface) { throw new \LogicException('Cannot add expression to expression of type ' . $component_expression->getPluginId()); } if ($this->uuid && ($expression = $component_expression->getExpression($this->uuid))) { return $expression; } else { $expression = $this->expressionManager->createInstance($this->expressionId); $rule_expression = $component->getExpression(); $rule_expression->addExpressionObject($expression); return $expression; } }
/** * Tests auto saving after an action execution. */ public function testActionAutoSave() { $rule = $this->rulesExpressionManager->createRule(); // Just leverage the entity save action, which by default uses auto-saving. $rule->addAction('rules_entity_save', ContextConfig::create()->map('entity', 'entity')); $entity = $this->prophesizeEntity(EntityInterface::class); $entity->save()->shouldBeCalledTimes(1); RulesComponent::create($rule)->addContextDefinition('entity', ContextDefinition::create('entity'))->setContextValue('entity', $entity->reveal())->execute(); }
/** * @cover ::getState() */ public function testGetState() { $rule = $this->rulesExpressionManager->createRule(); $component = RulesComponent::create($rule); $this->assertInstanceOf(ExecutionStateInterface::class, $component->getState()); // Test that set context values are available in the state. $component->addContextDefinition('foo', ContextDefinition::create('string'))->setContextValue('foo', 'bar'); $this->assertEquals($component->getState()->getVariableValue('foo'), 'bar'); }
/** * Tests that NULL values for contexts are allowed if specified. */ public function testAllowNullValue() { // Configure a simple rule with the data set action which allows NULL // values. $action = $this->expressionManager->createInstance('rules_action', ContextConfig::create()->setConfigKey('action_id', 'rules_data_set')->map('data', 'null_variable')->map('value', 'new_value')->toArray()); $rule = $this->expressionManager->createRule()->addExpressionObject($action); $component = RulesComponent::create($rule)->addContextDefinition('null_variable', ContextDefinition::create('string'))->addContextDefinition('new_value', ContextDefinition::create('string'))->setContextValue('null_variable', NULL)->setContextValue('new_value', 'new value'); $component->execute(); $this->assertEquals('new value', $component->getState()->getVariableValue('null_variable')); }
/** * Tests that the loop list item is removed after the loop. */ public function testPrepareAfterLoop() { $rule = $this->rulesExpressionManager->createRule(); $loop = $this->rulesExpressionManager->createInstance('rules_loop', ['list' => 'string_list']); $action = $this->rulesExpressionManager->createAction('rules_test_string')->setConfiguration(ContextConfig::create()->setValue('text', 'x')->toArray()); $loop->addExpressionObject($action); $rule->addExpressionObject($loop); $state = RulesComponent::create($rule)->addContextDefinition('string_list', ContextDefinition::create('string')->setMultiple())->getMetadataState(); $found = $rule->prepareExecutionMetadataState($state); $this->assertFalse($state->hasDataDefinition('list_item')); $this->assertNull($found); }
/** * Tests that the numeric offset plugin works. */ public function testNumericOffset() { // Configure a simple rule with one action. $action = $this->expressionManager->createInstance('rules_action', ContextConfig::create()->map('message', 'message')->map('type', 'type')->process('message', 'rules_numeric_offset', ['offset' => 1])->setConfigKey('action_id', 'rules_system_message')->toArray()); $component = RulesComponent::create($this->expressionManager->createRule())->addContextDefinition('message', ContextDefinition::create('string'))->addContextDefinition('type', ContextDefinition::create('string'))->setContextValue('message', 1)->setContextValue('type', 'status'); $component->getExpression()->addExpressionObject($action); $component->execute(); $messages = drupal_set_message(); // The original value was 1 and the processor adds 1, so the result should // be 2. $this->assertEquals((string) $messages['status'][0], '2'); }
/** * Make sure that expressions using context definitions can be exported. */ public function testContextDefinitionExport() { $component = RulesComponent::create($this->expressionManager->createRule())->addContextDefinition('test', ContextDefinition::create('string')->setLabel('Test string')); $config_entity = $this->storage->create(['id' => 'test_rule'])->updateFromComponent($component); $config_entity->save(); $loaded_entity = $this->storage->load('test_rule'); // Create the Rules expression object from the configuration. $expression = $loaded_entity->getExpression(); $this->assertInstanceOf(Rule::class, $expression); $context_definitions = $loaded_entity->getContextDefinitions(); $this->assertEquals($context_definitions['test']->getDataType(), 'string', 'Data type of context definition is correct.'); $this->assertEquals($context_definitions['test']->getLabel(), 'Test string', 'Label of context definition is correct.'); }
/** * Tests that date tokens are formatted correctly. */ public function testSystemDateToken() { // Configure a simple rule with one action. and token replacements enabled. $action = $this->expressionManager->createInstance('rules_action', ContextConfig::create()->setValue('message', "The date is {{ date | format_date('custom', 'Y-m') }}!")->setValue('type', 'status')->process('message', 'rules_tokens')->setConfigKey('action_id', 'rules_system_message')->toArray()); $rule = $this->expressionManager->createRule(); $rule->addExpressionObject($action); RulesComponent::create($rule)->addContextDefinition('date', ContextDefinition::create('timestamp'))->setContextValue('date', REQUEST_TIME)->execute(); $messages = drupal_set_message(); /** @var \Drupal\Core\Datetime\DateFormatterInterface $date_formatter */ $date_formatter = $this->container->get('date.formatter'); $date = $date_formatter->format(REQUEST_TIME, 'custom', 'Y-m'); $this->assertEquals("The date is {$date}!", (string) $messages['status'][0]); }
/** * Tests that a condition can provide a value and another one can consume it. */ public function testProvidedVariables() { $rule = $this->expressionManager->createRule(); // The first condition provides a "provided_text" variable. $rule->addCondition('rules_test_provider'); // The second condition consumes the variable. $rule->addCondition('rules_test_string_condition', ContextConfig::create()->map('text', 'provided_text')); $rule->addAction('rules_test_log'); $component = RulesComponent::create($rule); $violations = $component->checkIntegrity(); $this->assertEquals(0, iterator_count($violations)); $component->execute(); // Test that the action logged something. $this->assertRulesLogEntryExists('action called'); }
/** * {@inheritdoc} */ public function validateForm(array &$form, FormStateInterface $form_state) { $this->lockValidateForm($form, $form_state); // In order to validdate the whole rule we need to invoke the submission // handler of the expression form. That way the expression is changed and we // can validate the change for integrity afterwards. $validation_config = clone $this->ruleConfig; $rule_expression = $validation_config->getExpression(); $expression = $rule_expression->getExpression($this->uuid); $form_handler = $expression->getFormHandler(); $form_handler->submitForm($form, $form_state); $all_violations = RulesComponent::create($rule_expression)->addContextDefinitionsFrom($validation_config)->checkIntegrity(); $local_violations = $all_violations->getFor($this->uuid); foreach ($local_violations as $violation) { $form_state->setError($form, $violation->getMessage()); } }
/** * Tests using provided variables with refined context. */ public function testUsingRefinedProvidedVariables() { $rule = $this->rulesExpressionManager->createRule(); $rule->addAction('rules_variable_add', ContextConfig::create()->setValue('type', 'string')->setValue('value', 'foo')); $rule->addAction('rules_system_message', ContextConfig::create()->map('message', 'variable_added')->setValue('type', 'status')); // The message action requires a string, thus if the context is not refined // it will end up as "any" and integrity check would fail. $violation_list = RulesComponent::create($rule)->checkIntegrity(); $this->assertEquals(0, iterator_count($violation_list)); }
/** * {@inheritdoc} */ public function updateFromComponent(RulesComponent $component) { // Note that the available context definitions stem from the configured // events, which are handled separately. $this->setExpression($component->getExpression()); return $this; }
/** * Tests asserted metadata of negated conditions is ignored. */ public function testAssertingOfNegatedConditions() { // Negate the condition only and make sure it is ignored. $rule = $this->expressionManager->createRule(); $rule->addCondition('rules_entity_is_of_bundle', ContextConfig::create()->map('entity', 'node')->setValue('type', 'node')->setValue('bundle', 'page'))->negate(TRUE); $rule->addAction('rules_system_message', ContextConfig::create()->map('message', 'node.field_text.value')->setValue('type', 'status')); $violation_list = RulesComponent::create($rule)->addContextDefinition('node', ContextDefinition::create('entity:node'))->checkIntegrity(); $this->assertEquals(1, iterator_count($violation_list)); // Add an negated AND and make sure it is ignored. $rule = $this->expressionManager->createRule(); $and = $this->expressionManager->createAnd(); $and->addCondition('rules_entity_is_of_bundle', ContextConfig::create()->map('entity', 'node')->setValue('type', 'node')->setValue('bundle', 'page')); $and->negate(TRUE); $rule->addExpressionObject($and); $rule->addAction('rules_system_message', ContextConfig::create()->map('message', 'node.field_text.value')->setValue('type', 'status')); $violation_list = RulesComponent::create($rule)->addContextDefinition('node', ContextDefinition::create('entity:node'))->checkIntegrity(); $this->assertEquals(1, iterator_count($violation_list)); }
/** * Sets the Rules component to be stored. * * @param \Drupal\rules\Engine\RulesComponent $component * The component. * * @return $this */ public function setComponent(\Drupal\rules\Engine\RulesComponent $component) { $this->setExpression($component->getExpression()); $this->setContextDefinitions($component->getContextDefinitions()); return $this; }
/** * Tests that an absent required context triggers a violation. */ public function testMissingRequiredContext() { $rule = $this->rulesExpressionManager->createRule(); // The condition is completely unconfigured, missing 2 required contexts. $rule->addCondition('rules_node_is_of_type'); $violation_list = RulesComponent::create($rule)->checkIntegrity(); $this->assertEquals(2, iterator_count($violation_list)); $this->assertEquals('The required context <em class="placeholder">Node</em> is missing.', (string) $violation_list[0]->getMessage()); $this->assertEquals('The required context <em class="placeholder">Content types</em> is missing.', (string) $violation_list[1]->getMessage()); }
/** * Tests using global context. */ public function testGlobalContext() { $account = User::create(['name' => 'hubert']); $account->save(); $this->container->get('current_user')->setAccount($account); $rule = $this->expressionManager->createRule()->addAction('rules_system_message', ContextConfig::create()->map('message', '@user.current_user_context:current_user.name.value')->setValue('type', 'status')); $component = RulesComponent::create($rule); $this->assertEquals(0, $component->checkIntegrity()->count()); // Ensure the execution-state is aware of global context. $result = $component->getState()->hasVariable('@user.current_user_context:current_user'); $this->assertTrue($result); // Test asking for non-existing variables. $this->assertFalse($component->getState()->hasVariable('@user.current_user_context:invalid')); $this->assertFalse($component->getState()->hasVariable('@user.invalid_service')); $this->assertFalse($component->getState()->hasVariable('invalid-var')); // Test using global context during execution. $component->execute(); $messages = drupal_set_message(); $this->assertEquals((string) $messages['status'][0], 'hubert'); }
/** * {@inheritdoc} */ public function getComponent() { $config = $this->getConfig(); if ($config instanceof RulesUiComponentProviderInterface) { return $config->getComponent(); } else { $configuration = $config->get($this->pluginDefinition->settings['config_key']); return RulesComponent::createFromConfiguration($configuration); } }
/** * Tests that auto saving is only triggered once with nested components. */ public function testAutosaveOnlyOnce() { $entity = $this->prophesizeEntity(EntityInterface::class); $nested_rule = $this->rulesExpressionManager->createRule(); $nested_rule->addAction('rules_entity_save', ContextConfig::create()->map('entity', 'entity')); $rules_config = new RulesComponentConfig(['id' => 'test_rule', 'label' => 'Test rule'], 'rules_component'); $rules_config->setExpression($nested_rule); $rules_config->setContextDefinitions(['entity' => ContextDefinition::create('entity')]); $this->prophesizeStorage([$rules_config]); // Create a rule with a nested rule. Overall there are 2 actions to set the // entity then. $rule = $this->rulesExpressionManager->createRule(); $rule->addAction('rules_component:test_rule', ContextConfig::create()->map('entity', 'entity')); $rule->addAction('rules_entity_save', ContextConfig::create()->map('entity', 'entity')); // Auto-saving should only be triggered once on the entity. $entity->save()->shouldBeCalledTimes(1); RulesComponent::create($rule)->addContextDefinition('entity', ContextDefinition::create('entity'))->setContextValue('entity', $entity->reveal())->execute(); }
/** * {@inheritdoc} */ public function updateFromComponent(RulesComponent $component) { $this->component = $component->getConfiguration(); $this->componentObject = $component; return $this; }
/** * Gets the currently edited expression from the given component. * * @param \Drupal\rules\Engine\RulesComponent $component * The component from which to get the expression. * * @return \Drupal\rules\Engine\ExpressionInterface|null * The expression object. */ protected function getEditedExpression(RulesComponent $component) { $rule_expression = $component->getExpression(); return $rule_expression->getExpression($this->uuid); }
/** * Tests that the loop list item variable is not available after the loop. * * @expectedException \Drupal\rules\Exception\RulesEvaluationException * * @expectedExceptionMessage Unable to get variable list_item, it is not defined. */ public function testOutOfScopeVariableExecution() { $rule = $this->rulesExpressionManager->createRule(); $loop = $this->rulesExpressionManager->createInstance('rules_loop', ['list' => 'string_list']); $rule->addExpressionObject($loop); $rule->addAction('rules_test_string', ContextConfig::create()->map('text', 'list_item')); RulesComponent::create($rule)->addContextDefinition('string_list', ContextDefinition::create('string')->setMultiple())->setContextValue('string_list', ['one', 'two'])->execute(); }