ConditionExpression.php

Namespace

Drupal\rules\Plugin\RulesExpression

File

src/Plugin/RulesExpression/ConditionExpression.php

View source
<?php

namespace Drupal\rules\Plugin\RulesExpression;

use Drupal\Core\Logger\LoggerChannelInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\rules\Context\DataProcessorManager;
use Drupal\rules\Context\ExecutionMetadataStateInterface;
use Drupal\rules\Context\ExecutionStateInterface;
use Drupal\rules\Core\ConditionManager;
use Drupal\rules\Engine\ConditionExpressionInterface;
use Drupal\rules\Engine\ExpressionBase;
use Drupal\rules\Engine\ExpressionInterface;
use Drupal\rules\Context\ContextHandlerIntegrityTrait;
use Drupal\rules\Engine\IntegrityViolationList;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Defines an executable condition expression.
 *
 * This plugin is used to wrap condition plugins and is responsible to setup all
 * the context necessary, instantiate the condition plugin and to execute it.
 *
 * @RulesExpression(
 *   id = "rules_condition",
 *   label = @Translation("Condition"),
 *   form_class = "\Drupal\rules\Form\Expression\ConditionForm"
 * )
 */
class ConditionExpression extends ExpressionBase implements ConditionExpressionInterface, ContainerFactoryPluginInterface {
    use ContextHandlerIntegrityTrait;
    
    /**
     * The condition manager used to instantiate the condition plugin.
     *
     * @var \Drupal\rules\Core\ConditionManager
     */
    protected $conditionManager;
    
    /**
     * The rules debug logger channel.
     *
     * @var \Drupal\Core\Logger\LoggerChannelInterface
     */
    protected $rulesDebugLogger;
    
    /**
     * Constructs a new class instance.
     *
     * @param array $configuration
     *   A configuration array containing information about the plugin instance.
     *   Contains the following entries:
     *   - condition_id: The condition plugin ID.
     * @param string $plugin_id
     *   The plugin ID for the plugin instance.
     * @param mixed $plugin_definition
     *   The plugin implementation definition.
     * @param \Drupal\rules\Core\ConditionManager $condition_manager
     *   The condition manager.
     * @param \Drupal\rules\Context\DataProcessorManager $processor_manager
     *   The data processor plugin manager.
     * @param \Drupal\Core\Logger\LoggerChannelInterface $logger
     *   The Rules debug logger channel.
     */
    public function __construct(array $configuration, $plugin_id, $plugin_definition, ConditionManager $condition_manager, DataProcessorManager $processor_manager, LoggerChannelInterface $logger) {
        // Make sure defaults are applied.
        $configuration += $this->defaultConfiguration();
        parent::__construct($configuration, $plugin_id, $plugin_definition);
        $this->conditionManager = $condition_manager;
        $this->processorManager = $processor_manager;
        $this->rulesDebugLogger = $logger;
    }
    
    /**
     * {@inheritdoc}
     */
    public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
        return new static($configuration, $plugin_id, $plugin_definition, $container->get('plugin.manager.condition'), $container->get('plugin.manager.rules_data_processor'), $container->get('logger.channel.rules_debug'));
    }
    
    /**
     * {@inheritdoc}
     */
    public function defaultConfiguration() {
        return [
            // Per default the result of this expression is not negated.
'negate' => FALSE,
        ];
    }
    
    /**
     * {@inheritdoc}
     */
    public function setConfiguration(array $configuration) {
        // If the plugin id has been set already, keep it if not specified.
        if (isset($this->configuration['condition_id'])) {
            $configuration += [
                'condition_id' => $this->configuration['condition_id'],
            ];
        }
        return parent::setConfiguration($configuration);
    }
    
    /**
     * {@inheritdoc}
     */
    public function executeWithState(ExecutionStateInterface $state) {
        $condition = $this->conditionManager
            ->createInstance($this->configuration['condition_id'], [
            'negate' => $this->configuration['negate'],
        ]);
        $this->prepareContext($condition, $state);
        $result = $condition->evaluate();
        if ($this->isNegated()) {
            $result = !$result;
        }
        $this->rulesDebugLogger
            ->info('The condition %name evaluated to %bool.', [
            '%name' => $this->getLabel(),
            '%bool' => $result ? 'TRUE' : 'FALSE',
            'element' => $this,
        ]);
        // Now that the condition has been executed it can provide additional
        // context which we will have to pass back in the evaluation state.
        $this->addProvidedContext($condition, $state);
        return $result;
    }
    
    /**
     * {@inheritdoc}
     */
    public function negate($negate = TRUE) {
        $this->configuration['negate'] = $negate;
        return $this;
    }
    
    /**
     * {@inheritdoc}
     */
    public function isNegated() {
        return !empty($this->configuration['negate']);
    }
    
    /**
     * {@inheritdoc}
     */
    public function getLabel() {
        if (!empty($this->configuration['condition_id'])) {
            $definition = $this->conditionManager
                ->getDefinition($this->configuration['condition_id']);
            if ($this->isNegated()) {
                return $this->t('@not @label', [
                    '@not' => $this->t('NOT'),
                    '@label' => $definition['label'],
                ]);
            }
            else {
                return $definition['label'];
            }
        }
        return parent::getLabel();
    }
    
    /**
     * {@inheritdoc}
     */
    public function getFormHandler() {
        if (isset($this->pluginDefinition['form_class'])) {
            $class_name = $this->pluginDefinition['form_class'];
            return new $class_name($this, $this->conditionManager);
        }
    }
    
    /**
     * {@inheritdoc}
     */
    public function checkIntegrity(ExecutionMetadataStateInterface $metadata_state, $apply_assertions = TRUE) {
        $violation_list = new IntegrityViolationList();
        if (empty($this->configuration['condition_id'])) {
            $violation_list->addViolationWithMessage($this->t('Condition plugin ID is missing'), $this->getUuid());
            return $violation_list;
        }
        if (!$this->conditionManager
            ->hasDefinition($this->configuration['condition_id'])) {
            $violation_list->addViolationWithMessage($this->t('Condition plugin %plugin_id does not exist', [
                '%plugin_id' => $this->configuration['condition_id'],
            ]), $this->getUuid());
            return $violation_list;
        }
        $condition = $this->conditionManager
            ->createInstance($this->configuration['condition_id'], [
            'negate' => $this->configuration['negate'],
        ]);
        // Prepare and refine the context before checking integrity, such that any
        // context definition changes are respected while checking.
        $this->prepareContextWithMetadata($condition, $metadata_state);
        $result = $this->checkContextConfigIntegrity($condition, $metadata_state);
        $this->prepareExecutionMetadataState($metadata_state, NULL, $apply_assertions);
        return $result;
    }
    
    /**
     * {@inheritdoc}
     */
    public function prepareExecutionMetadataState(ExecutionMetadataStateInterface $metadata_state, ExpressionInterface $until = NULL, $apply_assertions = TRUE) {
        if ($until && $this->getUuid() === $until->getUuid()) {
            return TRUE;
        }
        $condition = $this->conditionManager
            ->createInstance($this->configuration['condition_id'], [
            'negate' => $this->configuration['negate'],
        ]);
        // Make sure to refine context first, such that possibly refined definitions
        // of provided context are respected.
        $this->prepareContextWithMetadata($condition, $metadata_state);
        $this->addProvidedContextDefinitions($condition, $metadata_state);
        if ($apply_assertions && !$this->isNegated()) {
            $this->assertMetadata($condition, $metadata_state);
        }
    }

}

Classes

Title Deprecated Summary
ConditionExpression Defines an executable condition expression.