Commit a98ce54b authored by Wolfgang Ziegler's avatar Wolfgang Ziegler
Browse files

Add foundational Context stuff from Rules.

parent f75e80c6
Loading
Loading
Loading
Loading
+37 −0
Changes for src/Context/AnnotatedClassDiscovery.php: 37 added lines, 0 removed lines.
Original line number Diff line number Diff line
<?php

namespace Drupal\typed_data\Context;

use Doctrine\Common\Annotations\SimpleAnnotationReader;
use \Drupal\Core\Plugin\Discovery\AnnotatedClassDiscovery as CoreAnnotatedClassDiscovery;

/**
 * Extends the annotation class discovery for usage with Typed data context.
 *
 * We modify the annotations classes for ContextDefinition and for Condition.
 * This class makes sure that our plugin managers apply these.
 */
class AnnotatedClassDiscovery extends CoreAnnotatedClassDiscovery {

  /**
   * {@inheritdoc}
   */
  protected function getAnnotationReader() {
    if (!isset($this->annotationReader)) {
      // Do not call out the parent, but re-configure the simple annotation
      // reader on our own, so we can control the order of namespaces.
      $this->annotationReader = new SimpleAnnotationReader();

      // Make sure to add our namespace first, so our ContextDefinition and
      // Condition annotations gets picked.
      $this->annotationReader->addNamespace('Drupal\typed_data\Context\Annotation');
      // Add the namespaces from the main plugin annotation, like @EntityType.
      $namespace = substr($this->pluginDefinitionAnnotationName, 0, strrpos($this->pluginDefinitionAnnotationName, '\\'));
      $this->annotationReader->addNamespace($namespace);
      // Add general core annotations like @Translation.
      $this->annotationReader->addNamespace('Drupal\Core\Annotation');
    }
    return $this->annotationReader;
  }

}
+51 −0
Changes for src/Context/Annotation/ContextDefinition.php: 51 added lines, 0 removed lines.
Original line number Diff line number Diff line
<?php

namespace Drupal\typed_data\Context\Annotation;

use Drupal\Core\Annotation\ContextDefinition as CoreContextDefinition;
use Drupal\Core\Annotation\Translation;
use Drupal\typed_data\Context\ContextDefinition as TypedDataContextDefinition;

/**
 * Extends the core context definition annotation object for Typed data.
 *
 * Ensures context definitions use
 * \Drupal\typed_data\Context\ContextDefinitionInterface.
 *
 * @Annotation
 *
 * @ingroup plugin_context
 */
class ContextDefinition extends CoreContextDefinition {

  /**
   * The ContextDefinitionInterface object.
   *
   * @var \Drupal\typed_data\Context\ContextDefinitionInterface
   */
  protected $definition;

  /**
   * {@inheritdoc}
   */
  public function __construct(array $values) {
    // Filter out any @Translation annotation objects.
    foreach ($values as $key => $value) {
      if ($value instanceof Translation) {
        $values[$key] = $value->get();
      }
    }
    $this->definition = TypedDataContextDefinition::createFromArray($values);
  }

  /**
   * Returns the value of an annotation.
   *
   * @return \Drupal\typed_data\Context\ContextDefinitionInterface
   *   Return the Typed data version of the ContextDefinitionInterface.
   */
  public function get() {
    return $this->definition;
  }

}
+120 −0
Changes for src/Context/ContextDefinition.php: 120 added lines, 0 removed lines.
Original line number Diff line number Diff line
<?php

namespace Drupal\typed_data\Context;

use \Drupal\Core\Plugin\Context\ContextDefinition as ContextDefinitionCore;
use \Drupal\Component\Plugin\Exception\ContextException;

/**
 * Extends the core context definition class with useful methods.
 */
class ContextDefinition extends ContextDefinitionCore implements ContextDefinitionInterface {

  /**
   * 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',
    'allow_null' => 'allowNull',
    'assignment_restriction' => 'assignmentRestriction',
  ];

  /**
   * 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\typed_data\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($values) {
    if (isset($values['class']) && !in_array(ContextDefinitionInterface::class, class_implements($values['class']))) {
      throw new ContextException('ContextDefinition class must implement ' . ContextDefinitionInterface::class . '.');
    }
    // Default to Typed data context definition class.
    $values['class'] = isset($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 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;
  }

}
+71 −0
Changes for src/Context/ContextDefinitionInterface.php: 71 added lines, 0 removed lines.
Original line number Diff line number Diff line
<?php

namespace Drupal\typed_data\Context;

use \Drupal\Core\Plugin\Context\ContextDefinitionInterface as CoreContextDefinitionInterfaceCore;

/**
 * Context definition information required by Typed data.
 *
 * The core interface is extended to add properties that are necessary for
 * Typed data.
 */
interface ContextDefinitionInterface extends CoreContextDefinitionInterfaceCore {

  /**
   * Constants for the context assignment restriction mode.
   *
   * @see ::getAssignmentRestriction()
   */
  const ASSIGNMENT_RESTRICTION_INPUT = 'input';
  const ASSIGNMENT_RESTRICTION_SELECTOR = 'selector';

  /**
   * Determines if the context value is allowed to be NULL.
   *
   * @return bool
   *   TRUE if NULL values are allowed, FALSE otherwise.
   */
  public function isAllowedNull();

  /**
   * Sets the "allow NULL value" behavior.
   *
   * @param bool $null_allowed
   *   TRUE if NULL values should be allowed, FALSE otherwise.
   *
   * @return $this
   */
  public function setAllowNull($null_allowed);

  /**
   * Determines if this context has an assignment restriction.
   *
   * @return string|null
   *   Either ASSIGNMENT_RESTRICTION_INPUT for contexts that are only allowed to
   *   be provided as input values, ASSIGNMENT_RESTRICTION_SELECTOR for contexts
   *   that must be provided as data selectors or NULL if there is no
   *   restriction for this context.
   */
  public function getAssignmentRestriction();

  /**
   * Sets the assignment restriction mode for this context.
   *
   * @param string|null $restriction
   *   Either ASSIGNMENT_RESTRICTION_INPUT for contexts that are only allowed to
   *   be provided as input values, ASSIGNMENT_RESTRICTION_SELECTOR for contexts
   *   that must be provided as data selectors or NULL if there is no
   *   restriction for this context.
   */
  public function setAssignmentRestriction($restriction);

  /**
   * Exports the definition as an array.
   *
   * @return array
   *   An array with values for all definition keys.
   */
  public function toArray();

}