class ContextDefinition

Same name in this branch
  1. 8.x-3.x src/Context/Annotation/ContextDefinition.php \Drupal\rules\Context\Annotation\ContextDefinition

Extends the core context definition class with useful methods.

This class overrides the core ContextDefinition to provide Rules-specific functionality, but also to preserve the Drupal 8 behavior of ContextDefinition without triggering deprecated code. Specifically, in Rules we need to be able to create a ContextDefinition for ANY typed data object, without prior knowledge of what that type is; we need to be able to say new ContextDefinition($type) or ContextDefinition::create($type) where $type may be 'integer', or 'string', or 'entity:node' etc.

This worked in Drupal 8, but in Drupal 9 we now have to use different classes for different types. Thus the core ContextDefinition::create($type) will work ONLY for non-entity types, and we have to use a different way to create context definitions for entities. This is a problem because now there is no factory method to create context definitions, and we have to test each type and just "know" the correct class to use for that type to create a context definition.

This Drupal 9 behavior is unworkable in a module like Rules where we rely on introspection and reflection to manipulate typed data. Without some way to programmatically create a context definition for an arbitrary data type, Rules will not work.

To work around this, we override the core ContextDefinition's __construct() and create() methods. In the parent::__construct(), there is an explicit assert that prevents ContextDefinition from being used for an entity. We remove that here - the __construct() method of this class is otherwise identical to the parent. We also override the core ContextDefinition's create() method to create a Rules version of EntityContextDefinition when ContextDefinition is created for an entity type. This is necessary because the core EntityContextDefinition doesn't have the necessary Rules extensions and there is no multiple inheritance in PHP so we have to extend ContextDefinition and EntityContextDefinition separately.

This is a poor solution that will work for existing core Rules use-cases, as EntityContextDefinition is never used directly in Rules, but this may not work for modules that extend Rules. A proper and permanent solution will require a change to core Drupal.

Hierarchy

Expanded class hierarchy of ContextDefinition

See also

\Drupal\rules\Context\EntityContextDefinition

https://www.drupal.org/project/rules/issues/3161582

https://www.drupal.org/project/drupal/issues/3126747

22 files declare their use of ContextDefinition
AutocompleteTest.php in tests/src/Kernel/Engine/AutocompleteTest.php
AutoSaveTest.php in tests/src/Unit/Integration/Engine/AutoSaveTest.php
ConfigEntityTest.php in tests/src/Kernel/ConfigEntityTest.php
ContextDefinition.php in src/Context/Annotation/ContextDefinition.php
ContextIntegrationTest.php in tests/src/Kernel/ContextIntegrationTest.php

... See full list

File

src/Context/ContextDefinition.php, line 52

Namespace

Drupal\rules\Context
View source
class ContextDefinition extends ContextDefinitionCore implements ContextDefinitionInterface {
    
    /**
     * {@inheritdoc}
     */
    public function __construct($data_type = 'any', $label = NULL, $required = TRUE, $multiple = FALSE, $description = NULL, $default_value = NULL) {
        $this->dataType = $data_type;
        $this->label = $label;
        $this->isRequired = $required;
        $this->isMultiple = $multiple;
        $this->description = $description;
        $this->defaultValue = $default_value;
    }
    
    /**
     * The created context definition object.
     */
    public static function create($data_type = 'any') {
        if (strpos($data_type, 'entity:') === 0) {
            return new EntityContextDefinition($data_type);
        }
        return new static($data_type);
    }
    
    /**
     * The mapping of config export keys to internal properties.
     *
     * @var array
     */
    protected static $nameMap = [
        'type' => 'dataType',
        'label' => 'label',
        'description' => 'description',
        'multiple' => 'isMultiple',
        'required' => 'isRequired',
        'default_value' => 'defaultValue',
        'constraints' => 'constraints',
        'getter' => 'getter',
        'allow_null' => 'allowNull',
        'assignment_restriction' => 'assignmentRestriction',
    ];
    
    /**
     * Name of getter function for this context variable.
     *
     * Only applicable for events.
     *
     * @var string
     */
    protected $getter = NULL;
    
    /**
     * Whether the context value is allowed to be NULL or not.
     *
     * @var bool
     */
    protected $allowNull = FALSE;
    
    /**
     * The assignment restriction of this context.
     *
     * @var string|null
     *
     * @see \Drupal\rules\Context\ContextDefinitionInterface::getAssignmentRestriction()
     */
    protected $assignmentRestriction = NULL;
    
    /**
     * {@inheritdoc}
     */
    public function toArray() {
        $values = [];
        $defaults = get_class_vars(__CLASS__);
        foreach (static::$nameMap as $key => $property_name) {
            // Only export values for non-default properties.
            if ($this->{$property_name} !== $defaults[$property_name]) {
                $values[$key] = $this->{$property_name};
            }
        }
        return $values;
    }
    
    /**
     * Creates a definition object from an exported array of values.
     *
     * @param array $values
     *   The array of values, as returned by toArray().
     *
     * @return static
     *   The created definition.
     *
     * @throws \Drupal\Component\Plugin\Exception\ContextException
     *   If the required classes are not implemented.
     */
    public static function createFromArray(array $values) {
        if (isset($values['class']) && !in_array(ContextDefinitionInterface::class, class_implements($values['class']))) {
            throw new ContextException('ContextDefinition class must implement ' . ContextDefinitionInterface::class . '.');
        }
        // Default to Rules context definition class.
        $values['class'] = $values['class'] ?? ContextDefinition::class;
        if (!isset($values['value'])) {
            $values['value'] = 'any';
        }
        $definition = $values['class']::create($values['value']);
        foreach (array_intersect_key(static::$nameMap, $values) as $key => $name) {
            $definition->{$name} = $values[$key];
        }
        return $definition;
    }
    
    /**
     * {@inheritdoc}
     */
    public function hasGetter() {
        return !is_null($this->getter);
    }
    
    /**
     * {@inheritdoc}
     */
    public function getGetter() {
        return $this->getter;
    }
    
    /**
     * {@inheritdoc}
     */
    public function isAllowedNull() {
        return $this->allowNull;
    }
    
    /**
     * {@inheritdoc}
     */
    public function setAllowNull($null_allowed) {
        $this->allowNull = $null_allowed;
        return $this;
    }
    
    /**
     * {@inheritdoc}
     */
    public function getAssignmentRestriction() {
        return $this->assignmentRestriction;
    }
    
    /**
     * {@inheritdoc}
     */
    public function setAssignmentRestriction($restriction) {
        $this->assignmentRestriction = $restriction;
        return $this;
    }

}

Members

Title Sort descending Modifiers Object type Summary Member alias Overriden Title Overrides
ContextDefinition::$allowNull protected property Whether the context value is allowed to be NULL or not.
ContextDefinition::$assignmentRestriction protected property The assignment restriction of this context.
ContextDefinition::$constraints protected property An array of constraints.
ContextDefinition::$dataType protected property The data type of the data.
ContextDefinition::$defaultValue protected property The default value.
ContextDefinition::$description protected property The human-readable description.
ContextDefinition::$getter protected property Name of getter function for this context variable.
ContextDefinition::$isMultiple protected property Whether the data is multi-valued, i.e. a list of data items.
ContextDefinition::$isRequired protected property Determines whether a data value is required.
ContextDefinition::$label protected property The human-readable label.
ContextDefinition::$nameMap protected static property The mapping of config export keys to internal properties.
ContextDefinition::addConstraint public function Adds a validation constraint. Overrides ContextDefinitionInterface::addConstraint
ContextDefinition::create public static function The created context definition object. Overrides ContextDefinition::create
ContextDefinition::createFromArray public static function Creates a definition object from an exported array of values.
ContextDefinition::dataTypeMatches protected function Checks if this definition's data type matches that of the given context.
ContextDefinition::getAssignmentRestriction public function Determines if this context has an assignment restriction. Overrides ContextDefinitionInterface::getAssignmentRestriction
ContextDefinition::getConstraint public function Gets a validation constraint. Overrides ContextDefinitionInterface::getConstraint
ContextDefinition::getConstraintObjects protected function Extracts an array of constraints for a context definition object. 1
ContextDefinition::getConstraints public function Gets an array of validation constraints. Overrides ContextDefinitionInterface::getConstraints
ContextDefinition::getDataDefinition public function Returns the data definition of the defined context. Overrides ContextDefinitionInterface::getDataDefinition
ContextDefinition::getDataType public function Gets the data type needed by the context. Overrides ContextDefinitionInterface::getDataType
ContextDefinition::getDefaultValue public function Gets the default value for this context definition. Overrides ContextDefinitionInterface::getDefaultValue
ContextDefinition::getDescription public function Gets a human readable description. Overrides ContextDefinitionInterface::getDescription
ContextDefinition::getGetter public function
ContextDefinition::getLabel public function Gets a human readable label. Overrides ContextDefinitionInterface::getLabel
ContextDefinition::getSampleValues protected function Returns typed data objects representing this context definition. 1
ContextDefinition::hasGetter public function
ContextDefinition::isAllowedNull public function Determines if the context value is allowed to be NULL. Overrides ContextDefinitionInterface::isAllowedNull
ContextDefinition::isMultiple public function Determines whether the data is multi-valued, i.e. a list of data items. Overrides ContextDefinitionInterface::isMultiple
ContextDefinition::isRequired public function Determines whether the context is required. Overrides ContextDefinitionInterface::isRequired
ContextDefinition::isSatisfiedBy public function Determines if this definition is satisfied by a context object. Overrides ContextDefinitionInterface::isSatisfiedBy
ContextDefinition::setAllowNull public function Sets the "allow NULL value" behavior. Overrides ContextDefinitionInterface::setAllowNull
ContextDefinition::setAssignmentRestriction public function Sets the assignment restriction mode for this context. Overrides ContextDefinitionInterface::setAssignmentRestriction
ContextDefinition::setConstraints public function Sets the array of validation constraints. Overrides ContextDefinitionInterface::setConstraints
ContextDefinition::setDataType public function Sets the data type needed by the context. Overrides ContextDefinitionInterface::setDataType
ContextDefinition::setDefaultValue public function Sets the default data value. Overrides ContextDefinitionInterface::setDefaultValue
ContextDefinition::setDescription public function Sets the human readable description. Overrides ContextDefinitionInterface::setDescription
ContextDefinition::setLabel public function Sets the human readable label. Overrides ContextDefinitionInterface::setLabel
ContextDefinition::setMultiple public function Sets whether the data is multi-valued. Overrides ContextDefinitionInterface::setMultiple
ContextDefinition::setRequired public function Sets whether the data is required. Overrides ContextDefinitionInterface::setRequired
ContextDefinition::toArray public function Exports the definition as an array. Overrides ContextDefinitionInterface::toArray
ContextDefinition::__construct public function Constructs a new context definition object. Overrides ContextDefinition::__construct
ContextDefinitionInterface::ASSIGNMENT_RESTRICTION_INPUT constant Constants for the context assignment restriction mode.
ContextDefinitionInterface::ASSIGNMENT_RESTRICTION_SELECTOR constant
DependencySerializationTrait::$_entityStorages protected property
DependencySerializationTrait::$_serviceIds protected property
DependencySerializationTrait::__sleep public function Aliased as: traitSleep 1
DependencySerializationTrait::__wakeup public function 2
TypedDataTrait::$typedDataManager protected property The typed data manager used for creating the data types.
TypedDataTrait::getTypedDataManager public function Gets the typed data manager. 2
TypedDataTrait::setTypedDataManager public function Sets the typed data manager. 2