/** * Performs the integrity check. * * @param CoreContextAwarePluginInterface $plugin * The plugin with its defined context. * @param \Drupal\rules\Engine\ExecutionMetadataStateInterface $metadata_state * The current configuration state with all defined variables that are * available. * * @return \Drupal\rules\Engine\IntegrityViolationList * The list of integrity violations. */ protected function doCheckIntegrity(CoreContextAwarePluginInterface $plugin, ExecutionMetadataStateInterface $metadata_state) { $violation_list = new IntegrityViolationList(); $context_definitions = $plugin->getContextDefinitions(); foreach ($context_definitions as $name => $context_definition) { // Check if a data selector is configured that maps to the state. if (isset($this->configuration['context_mapping'][$name])) { try { $data_definition = $metadata_state->fetchDefinitionByPropertyPath($this->configuration['context_mapping'][$name]); $this->checkDataTypeCompatible($context_definition, $data_definition, $name, $violation_list); } catch (RulesIntegrityException $e) { $violation = new IntegrityViolation(); $violation->setMessage($this->t('Data selector %selector for context %context_name is invalid. @message', ['%selector' => $this->configuration['context_mapping'][$name], '%context_name' => $context_definition->getLabel(), '@message' => $e->getMessage()])); $violation->setContextName($name); $violation_list->add($violation); } if ($context_definition instanceof RulesContextDefinitionInterface && $context_definition->getAssignmentRestriction() === RulesContextDefinitionInterface::ASSIGNMENT_RESTRICTION_INPUT) { $violation = new IntegrityViolation(); $violation->setMessage($this->t('The context %context_name may not be configured using a selector.', ['%context_name' => $context_definition->getLabel()])); $violation->setContextName($name); $violation_list->add($violation); } } elseif (isset($this->configuration['context_values'][$name])) { if ($context_definition instanceof RulesContextDefinitionInterface && $context_definition->getAssignmentRestriction() === RulesContextDefinitionInterface::ASSIGNMENT_RESTRICTION_SELECTOR) { $violation = new IntegrityViolation(); $violation->setMessage($this->t('The context %context_name may only be configured using a selector.', ['%context_name' => $context_definition->getLabel()])); $violation->setContextName($name); $violation_list->add($violation); } } elseif ($context_definition->isRequired()) { $violation = new IntegrityViolation(); $violation->setMessage($this->t('The required context %context_name is missing.', ['%context_name' => $context_definition->getLabel()])); $violation->setContextName($name); $violation_list->add($violation); } } if ($plugin instanceof ContextProviderInterface) { $provided_context_definitions = $plugin->getProvidedContextDefinitions(); foreach ($provided_context_definitions as $name => $context_definition) { if (isset($this->configuration['provides_mapping'][$name])) { if (!preg_match('/^[0-9a-zA-Z_]*$/', $this->configuration['provides_mapping'][$name])) { $violation = new IntegrityViolation(); $violation->setMessage($this->t('Provided variable name %name contains not allowed characters.', ['%name' => $this->configuration['provides_mapping'][$name]])); $violation->setContextName($name); $violation_list->add($violation); } // Populate the state with the new variable that is provided by this // plugin. That is necessary so that the integrity check in subsequent // actions knows about the variable and does not throw violations. $metadata_state->setDataDefinition($this->configuration['provides_mapping'][$name], $context_definition->getDataDefinition()); } else { $metadata_state->setDataDefinition($name, $context_definition->getDataDefinition()); } } } return $violation_list; }
/** * Performs the integrity check. * * @param CoreContextAwarePluginInterface $plugin * The plugin with its defined context. * @param \Drupal\rules\Engine\ExecutionMetadataStateInterface $metadata_state * The current configuration state with all defined variables that are * available. * * @return \Drupal\rules\Engine\IntegrityViolationList * The list of integrity violations. */ protected function checkContextConfigIntegrity(CoreContextAwarePluginInterface $plugin, ExecutionMetadataStateInterface $metadata_state) { $violation_list = new IntegrityViolationList(); $context_definitions = $plugin->getContextDefinitions(); // Make sure that all provided variables by this plugin are added to the // execution metadata state. $this->addProvidedContextDefinitions($plugin, $metadata_state); foreach ($context_definitions as $name => $context_definition) { // Check if a data selector is configured that maps to the state. if (isset($this->configuration['context_mapping'][$name])) { try { $data_definition = $this->getMappedDefinition($name, $metadata_state); $this->checkDataTypeCompatible($context_definition, $data_definition, $name, $violation_list); } catch (RulesIntegrityException $e) { $violation = new IntegrityViolation(); $violation->setMessage($this->t('Data selector %selector for context %context_name is invalid. @message', ['%selector' => $this->configuration['context_mapping'][$name], '%context_name' => $context_definition->getLabel(), '@message' => $e->getMessage()])); $violation->setContextName($name); $violation->setUuid($this->getUuid()); $violation_list->add($violation); } if ($context_definition instanceof RulesContextDefinitionInterface && $context_definition->getAssignmentRestriction() === RulesContextDefinitionInterface::ASSIGNMENT_RESTRICTION_INPUT) { $violation = new IntegrityViolation(); $violation->setMessage($this->t('The context %context_name may not be configured using a selector.', ['%context_name' => $context_definition->getLabel()])); $violation->setContextName($name); $violation->setUuid($this->getUuid()); $violation_list->add($violation); } } elseif (isset($this->configuration['context_values'][$name])) { if ($context_definition instanceof RulesContextDefinitionInterface && $context_definition->getAssignmentRestriction() === RulesContextDefinitionInterface::ASSIGNMENT_RESTRICTION_SELECTOR) { $violation = new IntegrityViolation(); $violation->setMessage($this->t('The context %context_name may only be configured using a selector.', ['%context_name' => $context_definition->getLabel()])); $violation->setContextName($name); $violation->setUuid($this->getUuid()); $violation_list->add($violation); } } elseif ($context_definition->isRequired() && $context_definition->getDefaultValue() === NULL) { $violation = new IntegrityViolation(); $violation->setMessage($this->t('The required context %context_name is missing.', ['%context_name' => $context_definition->getLabel()])); $violation->setContextName($name); $violation->setUuid($this->getUuid()); $violation_list->add($violation); } } if ($plugin instanceof ContextProviderInterface) { $provided_context_definitions = $plugin->getProvidedContextDefinitions(); foreach ($provided_context_definitions as $name => $context_definition) { if (isset($this->configuration['provides_mapping'][$name]) && !preg_match('/^[0-9a-zA-Z_]*$/', $this->configuration['provides_mapping'][$name])) { $violation = new IntegrityViolation(); $violation->setMessage($this->t('Provided variable name %name contains not allowed characters.', ['%name' => $this->configuration['provides_mapping'][$name]])); $violation->setContextName($name); $violation->setUuid($this->getUuid()); $violation_list->add($violation); } } } return $violation_list; }
/** * {@inheritdoc} */ public function applyContextMapping(ContextAwarePluginInterface $plugin, $contexts, $mappings = array()) { $mappings += $plugin->getContextMapping(); // Loop through each of the expected contexts. foreach (array_keys($plugin->getContextDefinitions()) as $plugin_context_id) { // If this context was given a specific name, use that. $context_id = isset($mappings[$plugin_context_id]) ? $mappings[$plugin_context_id] : $plugin_context_id; if (!empty($contexts[$context_id])) { // This assignment has been used, remove it. unset($mappings[$plugin_context_id]); $plugin->setContextValue($plugin_context_id, $contexts[$context_id]->getContextValue()); } } // If there are any mappings that were not satisfied, throw an exception. if (!empty($mappings)) { throw new ContextException(String::format('Assigned contexts were not satisfied: @mappings', ['@mappings' => implode(',', array_keys($mappings))])); } }
/** * {@inheritdoc} */ public function applyContextMapping(ContextAwarePluginInterface $plugin, $contexts, $mappings = array()) { /** @var $contexts \Drupal\Core\Plugin\Context\ContextInterface[] */ $mappings += $plugin->getContextMapping(); // Loop through each of the expected contexts. $missing_value = []; foreach ($plugin->getContextDefinitions() as $plugin_context_id => $plugin_context_definition) { // If this context was given a specific name, use that. $context_id = isset($mappings[$plugin_context_id]) ? $mappings[$plugin_context_id] : $plugin_context_id; if (!empty($contexts[$context_id])) { // This assignment has been used, remove it. unset($mappings[$plugin_context_id]); // Plugins have their on context objects, only the value is applied. // They also need to know about the cacheability metadata of where that // value is coming from, so pass them through to those objects. $plugin_context = $plugin->getContext($plugin_context_id); if ($plugin_context instanceof ContextInterface && $contexts[$context_id] instanceof CacheableDependencyInterface) { $plugin_context->addCacheableDependency($contexts[$context_id]); } // Pass the value to the plugin if there is one. if ($contexts[$context_id]->hasContextValue()) { $plugin->setContextValue($plugin_context_id, $contexts[$context_id]->getContextData()); } elseif ($plugin_context_definition->isRequired()) { // Collect required contexts that exist but are missing a value. $missing_value[] = $plugin_context_id; } } elseif ($plugin_context_definition->isRequired()) { // Collect required contexts that are missing. $missing_value[] = $plugin_context_id; } else { // Ignore mappings for optional missing context. unset($mappings[$plugin_context_id]); } } // If there are any required contexts without a value, throw an exception. if ($missing_value) { throw new ContextException(sprintf('Required contexts without a value: %s.', implode(', ', $missing_value))); } // If there are any mappings that were not satisfied, throw an exception. if (!empty($mappings)) { throw new ContextException('Assigned contexts were not satisfied: ' . implode(',', array_keys($mappings))); } }
/** * Process data context on the plugin, usually before it gets executed. * * @param \Drupal\Core\Plugin\ContextAwarePluginInterface $plugin * The plugin to process the context data on. * @param \Drupal\rules\Engine\RulesStateInterface $rules_state * The current Rules execution state with context variables. */ protected function processData(CoreContextAwarePluginInterface $plugin, RulesStateInterface $rules_state) { if (isset($this->configuration['context_processors'])) { foreach ($this->configuration['context_processors'] as $context_name => $processors) { $value = $plugin->getContextValue($context_name); foreach ($processors as $processor_plugin_id => $configuration) { $data_processor = $this->processorManager->createInstance($processor_plugin_id, $configuration); $value = $data_processor->process($value, $rules_state); } $plugin->setContextValue($context_name, $value); } } }