/**
  * Tests ConfigurableEventHandlerEntityBundle.
  *
  * Test that rules are triggered correctly based upon the fully qualified
  * event name as well as the base event name.
  *
  * @todo Add integrity check that node.field_integer is detected by Rules.
  */
 public function testConfigurableEventHandler()
 {
     // Create rule1 with the 'rules_entity_presave:node--page' event.
     $rule1 = $this->expressionManager->createRule();
     $rule1->addAction('rules_test_log', ContextConfig::create()->map('message', 'node.field_integer.0.value'));
     $config_entity1 = $this->storage->create(['id' => 'test_rule1']);
     $config_entity1->set('events', [['event_name' => 'rules_entity_presave:node--page']]);
     $config_entity1->set('expression', $rule1->getConfiguration());
     $config_entity1->save();
     // Create rule2 with the 'rules_entity_presave:node' event.
     $rule2 = $this->expressionManager->createRule();
     $rule2->addAction('rules_test_log', ContextConfig::create()->map('message', 'node.field_integer.1.value'));
     $config_entity2 = $this->storage->create(['id' => 'test_rule2']);
     $config_entity2->set('events', [['event_name' => 'rules_entity_presave:node']]);
     $config_entity2->set('expression', $rule2->getConfiguration());
     $config_entity2->save();
     // The logger instance has changed, refresh it.
     $this->logger = $this->container->get('logger.channel.rules');
     // Add node.field_integer.0.value to rules log message, read result.
     $this->node->field_integer->setValue(['0' => 11, '1' => 22]);
     // Trigger node save.
     $entity_type_id = $this->node->getEntityTypeId();
     $event = new EntityEvent($this->node, [$entity_type_id => $this->node]);
     $event_dispatcher = \Drupal::service('event_dispatcher');
     $event_dispatcher->dispatch("rules_entity_presave:{$entity_type_id}", $event);
     // Test that the action in the rule1 logged node value.
     $this->assertRulesLogEntryExists(11, 1);
     // Test that the action in the rule2 logged node value.
     $this->assertRulesLogEntryExists(22, 0);
 }
예제 #2
0
 /**
  * Tests executing a rule providing context based upon given context.
  */
 public function testRuleExecutionWithContext()
 {
     $rule = $this->rulesExpressionManager->createRule();
     $rule->addAction('rules_test_string', ContextConfig::create()->map('text', 'text'));
     $result = RulesComponent::create($rule)->addContextDefinition('text', ContextDefinition::create('string'))->provideContext('concatenated')->setContextValue('text', 'foo')->execute();
     // Ensure the provided context is returned.
     $this->assertTrue(isset($result['concatenated']) && $result['concatenated'] == 'foofoo');
 }
예제 #3
0
 /**
  * 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();
 }
예제 #4
0
 /**
  * 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);
 }
예제 #6
0
 /**
  * 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');
 }
 /**
  * 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()->map('message', 'message')->map('type', 'type')->process('message', 'rules_tokens')->setConfigKey('action_id', 'rules_system_message')->toArray());
     $rule = $this->expressionManager->createRule(['context_definitions' => ['message' => ContextDefinition::create('string')->toArray(), 'type' => ContextDefinition::create('string')->toArray()]]);
     $rule->setContextValue('message', 'The date is [date:custom:Y-m]!');
     $rule->setContextValue('type', 'status');
     $rule->addExpressionObject($action);
     $rule->execute();
     $messages = drupal_set_message();
     $date = format_date(time(), 'custom', 'Y-m');
     $this->assertEqual((string) $messages['status'][0], "The date is {$date}!");
 }
예제 #8
0
 /**
  * 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]);
 }
 /**
  * Test that the user login hook triggers the Rules event listener.
  */
 public function testUserLoginEvent()
 {
     $rule = $this->expressionManager->createRule();
     $rule->addCondition('rules_test_true');
     $rule->addAction('rules_test_log', ContextConfig::create()->map('message', 'account.name.0.value'));
     $config_entity = $this->storage->create(['id' => 'test_rule', 'events' => [['event_name' => 'rules_user_login']], 'expression' => $rule->getConfiguration()]);
     $config_entity->save();
     // The logger instance has changed, refresh it.
     $this->logger = $this->container->get('logger.channel.rules');
     $account = User::create(['name' => 'test_user']);
     // Invoke the hook manually which should trigger the rule.
     rules_user_login($account);
     // Test that the action in the rule logged something.
     $this->assertRulesLogEntryExists('test_user');
 }
예제 #10
0
 /**
  * Tests that a missing required context triggers an exception.
  *
  * @covers ::mapContext
  *
  * @expectedException \Drupal\rules\Exception\RulesEvaluationException
  *
  * @expectedExceptionMessage Required context test is missing for plugin testplugin.
  */
 public function testMissingContext()
 {
     // Set 'getContextValue' as mocked method.
     $trait = $this->getMockForTrait(ContextHandlerTrait::class, [], '', TRUE, TRUE, TRUE, ['getContextValue']);
     $context_definition = $this->prophesize(ContextDefinitionInterface::class);
     // Let the trait work with an empty configuration.
     $trait->configuration = ContextConfig::create()->toArray();
     // Make the context required in the definition.
     $context_definition->isRequired()->willReturn(TRUE)->shouldBeCalledTimes(1);
     $plugin = $this->prophesize(ContextAwarePluginInterface::class);
     $plugin->getContextDefinitions()->willReturn(['test' => $context_definition->reveal()])->shouldBeCalled(1);
     $plugin->getPluginId()->willReturn('testplugin')->shouldBeCalledTimes(1);
     $state = $this->prophesize(ExecutionStateInterface::class);
     // Make the 'mapContext' method visible.
     $reflection = new \ReflectionClass($trait);
     $method = $reflection->getMethod('mapContext');
     $method->setAccessible(TRUE);
     $method->invokeArgs($trait, [$plugin->reveal(), $state->reveal()]);
 }
예제 #11
0
 /**
  * Tests that context values get data processed with processor mappings.
  */
 public function testDataProcessor()
 {
     $condition = new RulesCondition(['condition_id' => 'test_condition'] + ContextConfig::create()->process('test', 'foo', [])->toArray(), '', [], $this->conditionManager->reveal(), $this->processorManager->reveal());
     // Build some mocked context and definitions for our mock condition.
     $context = $this->prophesize(ContextInterface::class);
     $condition->setContext('test', $context->reveal());
     $this->trueCondition->getContextDefinitions()->willReturn(['test' => $this->prophesize(ContextDefinitionInterface::class)->reveal()])->shouldBeCalledTimes(2);
     $this->trueCondition->getProvidedContextDefinitions()->willReturn([])->shouldBeCalledTimes(1);
     // Mock some original old value that will be replaced by the data processor.
     $this->trueCondition->getContextValue('test')->willReturn('old_value')->shouldBeCalledTimes(1);
     // The outcome of the data processor needs to get set on the condition.
     $this->trueCondition->setContextValue('test', 'new_value')->shouldBeCalledTimes(1);
     $this->trueCondition->refineContextDefinitions()->shouldBeCalledTimes(1);
     $this->conditionManager->createInstance('test_condition', ['negate' => FALSE])->willReturn($this->trueCondition->reveal())->shouldBeCalledTimes(1);
     $this->conditionManager->createInstance('test_condition')->willReturn($this->trueCondition->reveal())->shouldBeCalledTimes(1);
     $data_processor = $this->prophesize(DataProcessorInterface::class);
     $data_processor->process('old_value', Argument::any())->willReturn('new_value')->shouldBeCalledTimes(1);
     $this->processorManager->createInstance('foo', [])->willReturn($data_processor->reveal())->shouldBeCalledTimes(1);
     $this->assertTrue($condition->execute());
 }
예제 #12
0
 /**
  * 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 addCondition($condition_id, ContextConfig $config = NULL)
 {
     return $this->addExpressionObject($this->expressionManager->createCondition($condition_id)->setConfiguration($config ? $config->toArray() : []));
 }
예제 #14
0
 /**
  * {@inheritdoc}
  */
 public function submitForm(array &$form, FormStateInterface $form_state)
 {
     $context_config = ContextConfig::create();
     foreach ($form_state->getValue('context') as $context_name => $value) {
         if ($form_state->get("context_{$context_name}") == 'selector') {
             $context_config->map($context_name, $value['setting']);
         } else {
             $context_config->setValue($context_name, $value['setting']);
         }
     }
     $configuration = $context_config->toArray();
     $configuration['action_id'] = $form_state->getValue('action');
     $this->actionExpression->setConfiguration($configuration);
 }
예제 #15
0
 /**
  * Tests that a complex data context is assigned something that matches.
  */
 public function testComplexTypeViolation()
 {
     $rule = $this->rulesExpressionManager->createRule();
     // The condition expects a node context but gets a list instead which cause
     // the violation.
     $rule->addCondition('rules_node_is_of_type', ContextConfig::create()->map('node', 'list_variable')->map('types', 'list_variable'));
     $violation_list = RulesComponent::create($rule)->addContextDefinition('list_variable', ContextDefinition::create('list'))->checkIntegrity();
     $this->assertEquals(1, iterator_count($violation_list));
     $this->assertEquals('Expected a complex data type for context <em class="placeholder">Node</em> but got a list data type instead.', (string) $violation_list[0]->getMessage());
 }
예제 #16
0
 /**
  * Tests that the data set action works on nodes.
  */
 public function testDataSet()
 {
     $entity_manager = $this->container->get('entity.manager');
     $entity_manager->getStorage('node_type')->create(['type' => 'page'])->save();
     $node = $entity_manager->getStorage('node')->create(['title' => 'test', 'type' => 'page']);
     // Configure a simple rule with one action.
     $action = $this->expressionManager->createInstance('rules_action', ContextConfig::create()->setConfigKey('action_id', 'rules_data_set')->map('data', 'node:title')->map('value', 'new_title')->toArray());
     $rule = $this->expressionManager->createRule(['context_definitions' => ['node' => ContextDefinition::create('entity:node')->toArray(), 'new_title' => ContextDefinition::create('string')->toArray()]]);
     $rule->setContextValue('node', $node);
     $rule->setContextValue('new_title', 'new title');
     $rule->addExpressionObject($action);
     $rule->execute();
     $this->assertEqual('new title', $node->getTitle());
     $this->assertNotNull($node->id(), 'Node ID is set, which means that the node has been auto-saved.');
 }
 /**
  * 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));
 }
 /**
  * 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();
 }
예제 #19
0
 /**
  * Tests that multiple actions can consume and provide context variables.
  */
 public function testActionProvidedContext()
 {
     // @todo: Convert the test to make use of actions instead of conditions.
     $rule = $this->expressionManager->createRule();
     // The condition provides a "provided_text" variable.
     $rule->addCondition('rules_test_provider');
     // The action provides a "concatenated" variable.
     $rule->addAction('rules_test_string', ContextConfig::create()->map('text', 'provided_text'));
     // Add the same action again which will provide a "concatenated2" variable
     // now.
     $rule->addAction('rules_test_string', ContextConfig::create()->map('text', 'concatenated')->provideAs('concatenated', 'concatenated2'));
     $state = ExecutionState::create();
     $rule->executeWithState($state);
     // Check that the created variables exists and have the provided values.
     $concatenated = $state->getVariable('concatenated');
     $this->assertEqual($concatenated->getValue(), 'test valuetest value');
     $concatenated2 = $state->getVariable('concatenated2');
     $this->assertEqual($concatenated2->getValue(), 'test valuetest valuetest valuetest value');
 }
예제 #20
0
 /**
  * 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));
 }
예제 #21
0
 /**
  * {@inheritdoc}
  */
 public function submitForm(array &$form, FormStateInterface $form_state)
 {
     // Nothing todo as long as the first step is not completed.
     if (!$form_state->get('condition_id')) {
         return;
     }
     $context_config = ContextConfig::create();
     foreach ($form_state->getValue('context') as $context_name => $value) {
         if ($form_state->get("context_{$context_name}") == 'selector') {
             $context_config->map($context_name, $value['setting']);
         } else {
             $context_config->setValue($context_name, $value['setting']);
         }
     }
     $configuration = $context_config->toArray();
     $configuration['condition_id'] = $form_state->get('condition_id');
     $this->conditionExpression->setConfiguration($configuration);
 }
 /**
  * {@inheritdoc}
  */
 public function addExpression($plugin_id, ContextConfig $config = NULL)
 {
     return $this->addExpressionObject($this->expressionManager->createInstance($plugin_id, $config ? $config->toArray() : []));
 }
예제 #23
0
 /**
  * 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();
 }