Updated Drupal to 8.6. This goes with the following updates because it's possible...
[yaffs-website] / web / core / lib / Drupal / Core / Plugin / Context / ContextDefinition.php
index 55336d55c98cb30db0ec2fb0a9b08c802bc6a8f4..9d8c81f588714182d5cb4de1ea695b73dd7396d8 100644 (file)
@@ -3,11 +3,6 @@
 namespace Drupal\Core\Plugin\Context;
 
 use Drupal\Core\DependencyInjection\DependencySerializationTrait;
-use Drupal\Core\Entity\ContentEntityStorageInterface;
-use Drupal\Core\Entity\Plugin\DataType\EntityAdapter;
-use Drupal\Core\Entity\Plugin\Validation\Constraint\BundleConstraint;
-use Drupal\Core\Entity\Plugin\Validation\Constraint\EntityTypeConstraint;
-use Drupal\Core\Entity\TypedData\EntityDataDefinition;
 use Drupal\Core\TypedData\TypedDataTrait;
 
 /**
@@ -15,7 +10,10 @@ use Drupal\Core\TypedData\TypedDataTrait;
  */
 class ContextDefinition implements ContextDefinitionInterface {
 
-  use DependencySerializationTrait;
+  use DependencySerializationTrait {
+    __sleep as traitSleep;
+    __wakeup as traitWakeup;
+  }
 
   use TypedDataTrait;
 
@@ -72,6 +70,38 @@ class ContextDefinition implements ContextDefinitionInterface {
    */
   protected $constraints = [];
 
+  /**
+   * An EntityContextDefinition instance, for backwards compatibility.
+   *
+   * If this context is created with a data type that starts with 'entity:',
+   * this property will be an instance of EntityContextDefinition, and certain
+   * methods of this object will delegate to their overridden counterparts in
+   * $this->entityContextDefinition.
+   *
+   * This property should be kept private so that it is only accessible to this
+   * class for backwards compatibility reasons. It will be removed in Drupal 9.
+   *
+   * @deprecated
+   *   Constructing a context definition for an entity type (i.e., the data type
+   *   begins with 'entity:') is deprecated in Drupal 8.6.0. Instead, use
+   *   the static factory methods of EntityContextDefinition to create context
+   *   definitions for entity types, or the static ::create() method of this
+   *   class for any other data type. See https://www.drupal.org/node/2976400
+   *   for more information.
+   *
+   * @see ::__construct()
+   * @see ::__sleep()
+   * @see ::__wakeup()
+   * @see ::getConstraintObjects()
+   * @see ::getSampleValues()
+   * @see ::initializeEntityContextDefinition()
+   * @see https://www.drupal.org/node/2932462
+   * @see https://www.drupal.org/node/2976400
+   *
+   * @var \Drupal\Core\Plugin\Context\EntityContextDefinition
+   */
+  private $entityContextDefinition;
+
   /**
    * Creates a new context definition.
    *
@@ -111,6 +141,11 @@ class ContextDefinition implements ContextDefinitionInterface {
     $this->isMultiple = $multiple;
     $this->description = $description;
     $this->defaultValue = $default_value;
+
+    if (strpos($data_type, 'entity:') === 0 && !($this instanceof EntityContextDefinition)) {
+      @trigger_error('Constructing a ContextDefinition object for an entity type is deprecated in Drupal 8.6.0. Use ' . __NAMESPACE__ . '\EntityContextDefinition instead. See https://www.drupal.org/node/2976400 for more information.', E_USER_DEPRECATED);
+      $this->initializeEntityContextDefinition();
+    }
   }
 
   /**
@@ -207,6 +242,11 @@ class ContextDefinition implements ContextDefinitionInterface {
    * {@inheritdoc}
    */
   public function getConstraints() {
+    // If the backwards compatibility layer is present, delegate to that.
+    if ($this->entityContextDefinition) {
+      return $this->entityContextDefinition->getConstraints();
+    }
+
     // @todo Apply defaults.
     return $this->constraints;
   }
@@ -215,6 +255,11 @@ class ContextDefinition implements ContextDefinitionInterface {
    * {@inheritdoc}
    */
   public function getConstraint($constraint_name) {
+    // If the backwards compatibility layer is present, delegate to that.
+    if ($this->entityContextDefinition) {
+      return $this->entityContextDefinition->getConstraint($constraint_name);
+    }
+
     $constraints = $this->getConstraints();
     return isset($constraints[$constraint_name]) ? $constraints[$constraint_name] : NULL;
   }
@@ -223,6 +268,11 @@ class ContextDefinition implements ContextDefinitionInterface {
    * {@inheritdoc}
    */
   public function setConstraints(array $constraints) {
+    // If the backwards compatibility layer is present, delegate to that.
+    if ($this->entityContextDefinition) {
+      $this->entityContextDefinition->setConstraint();
+    }
+
     $this->constraints = $constraints;
     return $this;
   }
@@ -231,6 +281,11 @@ class ContextDefinition implements ContextDefinitionInterface {
    * {@inheritdoc}
    */
   public function addConstraint($constraint_name, $options = NULL) {
+    // If the backwards compatibility layer is present, delegate to that.
+    if ($this->entityContextDefinition) {
+      $this->entityContextDefinition->addConstraint($constraint_name, $options);
+    }
+
     $this->constraints[$constraint_name] = $options;
     return $this;
   }
@@ -273,8 +328,13 @@ class ContextDefinition implements ContextDefinitionInterface {
     if ($context->hasContextValue()) {
       $values = [$context->getContextData()];
     }
-    elseif ($definition instanceof static) {
-      $values = $definition->getSampleValues();
+    elseif ($definition instanceof self) {
+      if ($this->entityContextDefinition) {
+        $values = $this->entityContextDefinition->getSampleValues();
+      }
+      else {
+        $values = $definition->getSampleValues();
+      }
     }
     else {
       $values = [];
@@ -282,7 +342,14 @@ class ContextDefinition implements ContextDefinitionInterface {
 
     $validator = $this->getTypedDataManager()->getValidator();
     foreach ($values as $value) {
-      $violations = $validator->validate($value, array_values($this->getConstraintObjects()));
+      $constraints = array_values($this->getConstraintObjects());
+      $violations = $validator->validate($value, $constraints);
+      foreach ($violations as $delta => $violation) {
+        // Remove any violation that does not correspond to the constraints.
+        if (!in_array($violation->getConstraint(), $constraints)) {
+          $violations->remove($delta);
+        }
+      }
       // If a value has no violations then the requirement is satisfied.
       if (!$violations->count()) {
         return TRUE;
@@ -302,33 +369,6 @@ class ContextDefinition implements ContextDefinitionInterface {
    *   The set of typed data object.
    */
   protected function getSampleValues() {
-    // @todo Move the entity specific logic out of this class in
-    //   https://www.drupal.org/node/2932462.
-    // Get the constraints from the context's definition.
-    $constraints = $this->getConstraintObjects();
-    // If constraints include EntityType, we generate an entity or adapter.
-    if (!empty($constraints['EntityType']) && $constraints['EntityType'] instanceof EntityTypeConstraint) {
-      $entity_type_manager = \Drupal::entityTypeManager();
-      $entity_type_id = $constraints['EntityType']->type;
-      $storage = $entity_type_manager->getStorage($entity_type_id);
-      // If the storage can generate a sample entity we might delegate to that.
-      if ($storage instanceof ContentEntityStorageInterface) {
-        if (!empty($constraints['Bundle']) && $constraints['Bundle'] instanceof BundleConstraint) {
-          foreach ($constraints['Bundle']->bundle as $bundle) {
-            // We have a bundle, we are bundleable and we can generate a sample.
-            yield EntityAdapter::createFromEntity($storage->createWithSampleValues($bundle));
-          }
-          return;
-        }
-      }
-
-      // Either no bundle, or not bundleable, so generate an entity adapter.
-      $definition = EntityDataDefinition::create($entity_type_id);
-      yield new EntityAdapter($definition);
-      return;
-    }
-
-    // No entity related constraints, so generate a basic typed data object.
     yield $this->getTypedDataManager()->create($this->getDataDefinition());
   }
 
@@ -339,16 +379,13 @@ class ContextDefinition implements ContextDefinitionInterface {
    *   A list of applied constraints for the context definition.
    */
   protected function getConstraintObjects() {
-    $constraint_definitions = $this->getConstraints();
-
-    // @todo Move the entity specific logic out of this class in
-    //   https://www.drupal.org/node/2932462.
-    // If the data type is an entity, manually add one to the constraints array.
-    if (strpos($this->getDataType(), 'entity:') === 0) {
-      $entity_type_id = substr($this->getDataType(), 7);
-      $constraint_definitions['EntityType'] = ['type' => $entity_type_id];
+    // If the backwards compatibility layer is present, delegate to that.
+    if ($this->entityContextDefinition) {
+      return $this->entityContextDefinition->getConstraintObjects();
     }
 
+    $constraint_definitions = $this->getConstraints();
+
     $validation_constraint_manager = $this->getTypedDataManager()->getValidationConstraintManager();
     $constraints = [];
     foreach ($constraint_definitions as $constraint_name => $constraint_definition) {
@@ -358,4 +395,41 @@ class ContextDefinition implements ContextDefinitionInterface {
     return $constraints;
   }
 
+  /**
+   * Implements magic __sleep() method.
+   */
+  public function __sleep() {
+    return array_diff($this->traitSleep(), ['entityContextDefinition']);
+  }
+
+  /**
+   * Implements magic __wakeup() method.
+   */
+  public function __wakeup() {
+    $this->traitWakeup();
+
+    if (strpos($this->getDataType(), 'entity:') === 0) {
+      $this->initializeEntityContextDefinition();
+    }
+  }
+
+  /**
+   * Initializes $this->entityContextDefinition for backwards compatibility.
+   *
+   * This method should be kept private so that it is only accessible to this
+   * class for backwards compatibility reasons. It will be removed in Drupal 9.
+   *
+   * @deprecated
+   */
+  private function initializeEntityContextDefinition() {
+    $this->entityContextDefinition = EntityContextDefinition::create()
+      ->setDataType($this->getDataType())
+      ->setLabel($this->getLabel())
+      ->setRequired($this->isRequired())
+      ->setMultiple($this->isMultiple())
+      ->setDescription($this->getDescription())
+      ->setConstraints($this->getConstraints())
+      ->setDefaultValue($this->getDefaultValue());
+  }
+
 }