*/
class ContextDefinition implements ContextDefinitionInterface {
- use DependencySerializationTrait;
+ use DependencySerializationTrait {
+ __sleep as traitSleep;
+ __wakeup as traitWakeup;
+ }
use TypedDataTrait;
/**
* The data type of the data.
*
- * @return string
+ * @var string
* The data type.
*/
protected $dataType;
/**
* The human-readable label.
*
- * @return string
+ * @var string
* The label.
*/
protected $label;
/**
* The human-readable description.
*
- * @return string|null
+ * @var string|null
* The description, or NULL if no description is available.
*/
protected $description;
*/
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.
*
$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();
+ }
}
/**
* {@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;
}
* {@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;
}
* {@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;
}
* {@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;
}
return $definition;
}
+ /**
+ * {@inheritdoc}
+ */
+ public function isSatisfiedBy(ContextInterface $context) {
+ $definition = $context->getContextDefinition();
+ // If the data types do not match, this context is invalid unless the
+ // expected data type is any, which means all data types are supported.
+ if ($this->getDataType() != 'any' && $definition->getDataType() != $this->getDataType()) {
+ return FALSE;
+ }
+
+ // Get the value for this context, either directly if possible or by
+ // introspecting the definition.
+ if ($context->hasContextValue()) {
+ $values = [$context->getContextData()];
+ }
+ elseif ($definition instanceof self) {
+ if ($this->entityContextDefinition) {
+ $values = $this->entityContextDefinition->getSampleValues();
+ }
+ else {
+ $values = $definition->getSampleValues();
+ }
+ }
+ else {
+ $values = [];
+ }
+
+ $validator = $this->getTypedDataManager()->getValidator();
+ foreach ($values as $value) {
+ $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;
+ }
+ }
+
+ return FALSE;
+ }
+
+ /**
+ * Returns typed data objects representing this context definition.
+ *
+ * This should return as many objects as needed to reflect the variations of
+ * the constraints it supports.
+ *
+ * @yield \Drupal\Core\TypedData\TypedDataInterface
+ * The set of typed data object.
+ */
+ protected function getSampleValues() {
+ yield $this->getTypedDataManager()->create($this->getDataDefinition());
+ }
+
+ /**
+ * Extracts an array of constraints for a context definition object.
+ *
+ * @return \Symfony\Component\Validator\Constraint[]
+ * A list of applied constraints for the context definition.
+ */
+ protected function getConstraintObjects() {
+ // 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) {
+ $constraints[$constraint_name] = $validation_constraint_manager->create($constraint_name, $constraint_definition);
+ }
+
+ 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());
+ }
+
}