diff --git a/core/lib/Drupal/Core/TypedData/Validation/EntityMetadata.php b/core/lib/Drupal/Core/TypedData/Validation/EntityMetadata.php index 99449a4..d33de7a 100644 --- a/core/lib/Drupal/Core/TypedData/Validation/EntityMetadata.php +++ b/core/lib/Drupal/Core/TypedData/Validation/EntityMetadata.php @@ -6,7 +6,19 @@ namespace Drupal\Core\TypedData\Validation; +use Symfony\Component\Validator\Mapping\CascadingStrategy; +use Symfony\Component\Validator\Mapping\TraversalStrategy; -class EntityMetadata { +/** + * Defines a class for entity metadata. + */ +class EntityMetadata extends PropertyContainerMetadata { + + /** + * {@inheritdoc} + */ + public function getCascadingStrategy() { + return CascadingStrategy::CASCADE; + } } diff --git a/core/lib/Drupal/Core/TypedData/Validation/Metadata.php b/core/lib/Drupal/Core/TypedData/Validation/Metadata.php index 23f1945..ef72f8c 100755 --- a/core/lib/Drupal/Core/TypedData/Validation/Metadata.php +++ b/core/lib/Drupal/Core/TypedData/Validation/Metadata.php @@ -7,6 +7,7 @@ namespace Drupal\Core\TypedData\Validation; +use Drupal\Core\TypedData\TypedDataInterface; use Symfony\Component\Validator\Exception\BadMethodCallException; use Symfony\Component\Validator\Mapping\CascadingStrategy; @@ -16,6 +17,13 @@ class Metadata extends MetadataBase { /** + * Property name for this metadata. + * + * @var string + */ + protected $propertyName; + + /** * {@inheritdoc} */ public function getConstrainedProperties() { @@ -44,10 +52,44 @@ public function getCascadingStrategy() { } /** + * Sets the typed data for this metadata. + * + * @param \Drupal\Core\TypedData\TypedDataInterface $typed_data + * The typed data to use for this metadata. + */ + public function setTypedData(TypedDataInterface $typed_data) { + $this->typedData = $typed_data; + } + + /** + * Overrides the property name for this metadata. + * + * @param string $property_name + * The new property name for this metadata. + */ + public function setPropertyName($property_name) { + $this->propertyName = $property_name; + } + + /** + * {@inheritdoc} + */ + public function getPropertyName() { + if (isset($this->propertyName)) { + return $this->propertyName; + } + return parent::getPropertyName(); + } + + /** * {@inheritdoc} */ - public function getTypedData() { - return $this->typedData->getParent(); + public function getConstraints() { + if (isset($this->propertyName)) { + return $this->constraints; + } + return parent::getConstraints(); } + } diff --git a/core/lib/Drupal/Core/TypedData/Validation/MetadataFactory.php b/core/lib/Drupal/Core/TypedData/Validation/MetadataFactory.php index 2d52915..b2cdcaa 100755 --- a/core/lib/Drupal/Core/TypedData/Validation/MetadataFactory.php +++ b/core/lib/Drupal/Core/TypedData/Validation/MetadataFactory.php @@ -7,6 +7,7 @@ namespace Drupal\Core\TypedData\Validation; +use Drupal\Core\Entity\Plugin\DataType\EntityAdapter; use Drupal\Core\TypedData\ComplexDataInterface; use Drupal\Core\TypedData\ListInterface; use Drupal\Core\TypedData\TypedDataInterface; @@ -27,8 +28,13 @@ public function getMetadataFor($typed_data) { if (!$typed_data instanceof TypedDataInterface) { throw new \InvalidArgumentException('The passed value must be a typed data object.'); } - $is_container = $typed_data instanceof ComplexDataInterface || $typed_data instanceof ListInterface; - $class = '\Drupal\Core\TypedData\Validation\\' . ($is_container ? 'PropertyContainerMetadata' : 'Metadata'); + $class = '\Drupal\Core\TypedData\Validation\Metadata'; + if ($typed_data instanceof ComplexDataInterface || $typed_data instanceof ListInterface) { + $class = '\Drupal\Core\TypedData\Validation\PropertyContainerMetadata'; + } + if ($typed_data instanceof EntityAdapter) { + $class = '\Drupal\Core\TypedData\Validation\EntityMetadata'; + } return new $class($typed_data, $this); } diff --git a/core/lib/Drupal/Core/TypedData/Validation/PropertyContainerMetadata.php b/core/lib/Drupal/Core/TypedData/Validation/PropertyContainerMetadata.php index 6f9f5d7..52f7ab2 100644 --- a/core/lib/Drupal/Core/TypedData/Validation/PropertyContainerMetadata.php +++ b/core/lib/Drupal/Core/TypedData/Validation/PropertyContainerMetadata.php @@ -7,8 +7,10 @@ namespace Drupal\Core\TypedData\Validation; +use Drupal\Core\Field\Plugin\DataType\FieldItem; use Drupal\Core\TypedData\ComplexDataInterface; use Drupal\Core\TypedData\ListInterface; +use Drupal\Core\TypedData\PrimitiveInterface; use Drupal\Core\TypedData\TypedDataInterface; use Drupal\Core\Validation\Plugin\Validation\Constraint\ComplexDataConstraint; use Symfony\Component\Validator\Exception\BadMethodCallException; @@ -84,7 +86,8 @@ public function hasPropertyMetadata($property_name) { public function getPropertyMetadata($property_name) { if ($this->typedData instanceof ListInterface || $this->typedData instanceof ComplexDataInterface) { /* @var \Drupal\Core\TypedData\Validation\MetadataBase $metadata */ - $metadata = $this->factory->getMetadataFor($this->typedData->get($property_name)); + $typed_data = $this->typedData->get($property_name); + $metadata = $this->factory->getMetadataFor($typed_data); // Merge in any applicable property constraints from // ComplexDataConstraints that were applied to this object. if (isset($this->propertyConstraints[$property_name])) { @@ -92,6 +95,14 @@ public function getPropertyMetadata($property_name) { $metadata->addPropertyConstraint($constraint); } } + if ($typed_data instanceof PrimitiveInterface) { + // If we're validating a primitive value here by way of a + // ComplexDataConstraint, pass on the ComplexDataInterface instead of + // the PrimitiveInterface. + /* @var \Drupal\Core\TypedData\Validation\Metadata $metadata */ + $metadata->setTypedData($this->typedData); + $metadata->setPropertyName($property_name); + } return [$metadata]; } else { @@ -120,7 +131,21 @@ public function getConstrainedProperties() { * {@inheritdoc} */ public function getCascadingStrategy() { - return CascadingStrategy::CASCADE; + // If we have property constraints, we need to cascade. + if ($this->propertyConstraints) { + return CascadingStrategy::CASCADE; + } + return CascadingStrategy::NONE; + } + + /** + * {@inheritdoc} + */ + public function getTraversalStrategy() { + if ($this->typedData instanceof ListInterface) { + return TraversalStrategy::IMPLICIT; + } + return parent::getTraversalStrategy(); } }