diff --git a/core/lib/Drupal/Core/TypedData/TypedDataManager.php b/core/lib/Drupal/Core/TypedData/TypedDataManager.php index cd7ad17..78b9888 100644 --- a/core/lib/Drupal/Core/TypedData/TypedDataManager.php +++ b/core/lib/Drupal/Core/TypedData/TypedDataManager.php @@ -335,7 +335,7 @@ public function getValidator() { ->setMetadataFactory(new MetadataFactory($this)) ->setTranslator(new DrupalTranslator()) ->setConstraintValidatorFactory(new ConstraintValidatorFactory($this->classResolver)) - ->setApiVersion(Validation::API_VERSION_2_4) + ->setApiVersion(Validation::API_VERSION_2_5) ->getValidator(); } return $this->validator; diff --git a/core/lib/Drupal/Core/TypedData/Validation/GenericMetadata.php b/core/lib/Drupal/Core/TypedData/Validation/GenericMetadata.php new file mode 100755 index 0000000..a8eedd8 --- /dev/null +++ b/core/lib/Drupal/Core/TypedData/Validation/GenericMetadata.php @@ -0,0 +1,46 @@ +typedData); + } + + /** + * {@inheritdoc} + */ + public function getCascadingStrategy() { + return CascadingStrategy::NONE; + } + + /** + * {@inheritdoc} + */ + public function getPropertyValue($container) { + return $this->typedData; + } + + /** + * {@inheritdoc} + */ + public function getPropertyName() { + return $this->typedData->getName(); + } + +} diff --git a/core/lib/Drupal/Core/TypedData/Validation/Metadata.php b/core/lib/Drupal/Core/TypedData/Validation/Metadata.php deleted file mode 100644 index 6fe5255..0000000 --- a/core/lib/Drupal/Core/TypedData/Validation/Metadata.php +++ /dev/null @@ -1,115 +0,0 @@ -typedData = $typed_data; - $this->name = $name; - $this->factory = $factory; - $this->typedDataManager = $typed_data_manager; - } - - /** - * Implements MetadataInterface::accept(). - */ - public function accept(ValidationVisitorInterface $visitor, $typed_data, $group, $propertyPath) { - - // @todo: Do we have to care about groups? Symfony class metadata has - // $propagatedGroup. - - $visitor->visit($this, $this->typedDataManager->getCanonicalRepresentation($typed_data), $group, $propertyPath); - } - - /** - * Implements MetadataInterface::findConstraints(). - */ - public function findConstraints($group) { - return $this->typedData->getConstraints(); - } - - /** - * Returns the name of the property. - * - * @return string The property name. - */ - public function getPropertyName() { - return $this->name; - } - - /** - * Extracts the value of the property from the given container. - * - * @param mixed $container The container to extract the property value from. - * - * @return mixed The value of the property. - */ - public function getPropertyValue($container) { - return $this->typedDataManager->getCanonicalRepresentation($this->typedData); - } - - /** - * Returns the typed data object. - * - * @return \Drupal\Core\TypedData\TypedDataInterface - * The typed data object. - */ - public function getTypedData() { - return $this->typedData; - } -} diff --git a/core/lib/Drupal/Core/TypedData/Validation/MetadataBase.php b/core/lib/Drupal/Core/TypedData/Validation/MetadataBase.php new file mode 100755 index 0000000..424632a --- /dev/null +++ b/core/lib/Drupal/Core/TypedData/Validation/MetadataBase.php @@ -0,0 +1,158 @@ +typedData = $typed_data; + $this->typedDataManager = $typed_data_manager; + } + + /** + * {@inheritdoc} + */ + public function getTypedData() { + return $this->typedData; + } + + /** + * {@inheritdoc} + */ + public function preprocessValue(&$value) { + if (!$value instanceof TypedDataInterface) { + throw new \LogicException('This class may be used with Typed Data objects only.'); + } + // Pass the canonical representation to validators. + $value = $this->typedDataManager->getCanonicalRepresentation($value); + } + + /** + * {@inheritdoc} + */ + public function accept(ValidationVisitorInterface $visitor, $typed_data, $group, $propertyPath) { + throw new BadMethodCallException('Not supported.'); + } + + /** + * {@inheritdoc} + */ + public function findConstraints($group) { + return $this->getConstraints(); + } + + /** + * {@inheritdoc} + */ + public function getConstraints() { + return array_merge($this->typedData->getConstraints(), $this->extraConstraints); + } + + /** + * {@inheritdoc} + */ + public function getTraversalStrategy() { + return TraversalStrategy::NONE; + } + + /** + * {@inheritdoc} + */ + public function addExtraConstraints(array $constraints) { + $this->extraConstraints = array_merge($this->extraConstraints, $constraints); + } + + /** + * {@inheritdoc} + */ + public function getClassName() { + return get_class($this->typedData); + } + + /** + * {@inheritdoc} + */ + public function getGroupSequence() { + return NULL; + } + + /** + * {@inheritdoc} + */ + public function hasGroupSequence() { + return FALSE; + } + + /** + * {@inheritdoc} + */ + public function isGroupSequenceProvider() { + return FALSE; + } + + /** + * {@inheritdoc} + */ + public function getConstrainedProperties() { + return []; + } + + /** + * {@inheritdoc} + */ + public function hasPropertyMetadata($property) { + return FALSE; + } + + /** + * {@inheritdoc} + */ + public function getPropertyMetadata($property) { + return []; + } + +} diff --git a/core/lib/Drupal/Core/TypedData/Validation/MetadataFactory.php b/core/lib/Drupal/Core/TypedData/Validation/MetadataFactory.php old mode 100644 new mode 100755 index fcd0557..9a6a47f --- a/core/lib/Drupal/Core/TypedData/Validation/MetadataFactory.php +++ b/core/lib/Drupal/Core/TypedData/Validation/MetadataFactory.php @@ -11,7 +11,7 @@ use Drupal\Core\TypedData\ListInterface; use Drupal\Core\TypedData\TypedDataInterface; use Drupal\Core\TypedData\TypedDataManager; -use Symfony\Component\Validator\MetadataFactoryInterface; +use Symfony\Component\Validator\Mapping\Factory\MetadataFactoryInterface; /** * Typed data implementation of the validator MetadataFactoryInterface. @@ -39,24 +39,25 @@ public function __construct(TypedDataManager $typed_data_manager) { * {@inheritdoc} * * @param \Drupal\Core\TypedData\TypedDataInterface $typed_data - * Some typed data object containing the value to validate. - * @param $name - * (optional) The name of the property to get metadata for. Leave empty, if - * the data is the root of the typed data tree. + * A typed data object containing the value to validate. */ - public function getMetadataFor($typed_data, $name = '') { + 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'); - return new $class($typed_data, $name, $this, $this->typedDataManager); + $class = '\Drupal\Core\TypedData\Validation\GenericMetadata'; + if ($typed_data instanceof ComplexDataInterface || $typed_data instanceof ListInterface) { + // When validation is started on a container, we need its class metadata. + $class = '\Drupal\Core\TypedData\Validation\PropertyContainerClassMetadata'; + } + return new $class($typed_data, $this->typedDataManager); } /** - * Implements MetadataFactoryInterface::hasMetadataFor(). + * {@inheritdoc} */ public function hasMetadataFor($value) { return $value instanceof TypedDataInterface; } + } diff --git a/core/lib/Drupal/Core/TypedData/Validation/PropertyContainerClassMetadata.php b/core/lib/Drupal/Core/TypedData/Validation/PropertyContainerClassMetadata.php new file mode 100644 index 0000000..b917684 --- /dev/null +++ b/core/lib/Drupal/Core/TypedData/Validation/PropertyContainerClassMetadata.php @@ -0,0 +1,97 @@ +typedData->isEmpty()) { + // Do not continue cascading down the tree if a data structure is empty. + return []; + } + if ($this->typedData instanceof ListInterface) { + // @todo: When https://www.drupal.org/node/2164601 gets committed, + // simplify this to return the list indexes based on the list count. + return array_keys(iterator_to_array($this->typedData)); + } + elseif ($this->typedData instanceof ComplexDataInterface) { + return array_keys($this->typedData->getProperties()); + } + else { + throw new \LogicException("This class should be only used for property containers."); + } + } + + /** + * {@inheritdoc} + */ + public function hasPropertyMetadata($property_name) { + if ($this->typedData instanceof ComplexDataInterface) { + return (bool) $this->typedData->getDataDefinition()->getPropertyDefinition($property_name); + } + elseif ($this->typedData instanceof ListInterface) { + try { + $item = $this->typedData->get($property_name); + return TRUE; + } + catch (\InvalidArgumentException $exception) { + return FALSE; + } + } + else { + throw new \LogicException("This class should be only used for property containers."); + } + } + + /** + * {@inheritdoc} + */ + public function getPropertyMetadata($property_name) { + if (!isset($this->propertyMetadata[$property_name])) { + $property = $this->typedData->get($property_name); + $class = '\Drupal\Core\TypedData\Validation\GenericMetadata'; + + if ($property instanceof ComplexDataInterface || $property instanceof ListInterface) { + $class = '\Drupal\Core\TypedData\Validation\PropertyContainerPropertyMetadata'; + } + $this->propertyMetadata[$property_name] = new $class($property, $this->typedDataManager); + } + return [ + $this->propertyMetadata[$property_name] + ]; + } + + /** + * {@inheritdoc} + */ + public function getCascadingStrategy() { + return CascadingStrategy::CASCADE; + } + +} diff --git a/core/lib/Drupal/Core/TypedData/Validation/PropertyContainerMetadata.php b/core/lib/Drupal/Core/TypedData/Validation/PropertyContainerMetadata.php deleted file mode 100644 index 80d3320..0000000 --- a/core/lib/Drupal/Core/TypedData/Validation/PropertyContainerMetadata.php +++ /dev/null @@ -1,72 +0,0 @@ -isEmpty()) { - $data = NULL; - } - else { - $data = $this->typedDataManager->getCanonicalRepresentation($typed_data); - } - $visitor->visit($this, $data, $group, $propertyPath); - $pathPrefix = isset($propertyPath) && $propertyPath !== '' ? $propertyPath . '.' : ''; - - // Only continue validating if the data is not empty. - if ($data) { - foreach ($typed_data as $name => $data) { - $metadata = $this->factory->getMetadataFor($data, $name); - $metadata->accept($visitor, $data, $group, $pathPrefix . $name); - } - } - } - - /** - * Implements PropertyMetadataContainerInterface::hasPropertyMetadata(). - */ - public function hasPropertyMetadata($property_name) { - try { - $exists = (bool)$this->getPropertyMetadata($property_name); - } - catch (\LogicException $e) { - $exists = FALSE; - } - return $exists; - } - - /** - * Implements PropertyMetadataContainerInterface::getPropertyMetadata(). - */ - public function getPropertyMetadata($property_name) { - if ($this->typedData instanceof ListInterface) { - return array(new Metadata($this->typedData[$property_name], $property_name, $this->factory, $this->typedDataManager)); - } - elseif ($this->typedData instanceof ComplexDataInterface) { - return array(new Metadata($this->typedData->get($property_name), $property_name, $this->factory, $this->typedDataManager)); - } - else { - throw new \LogicException("There are no known properties."); - } - } -} diff --git a/core/lib/Drupal/Core/TypedData/Validation/PropertyContainerPropertyMetadata.php b/core/lib/Drupal/Core/TypedData/Validation/PropertyContainerPropertyMetadata.php new file mode 100644 index 0000000..0ddd54e --- /dev/null +++ b/core/lib/Drupal/Core/TypedData/Validation/PropertyContainerPropertyMetadata.php @@ -0,0 +1,51 @@ +extraConstraints; + } + + /** + * {@inheritdoc} + */ + public function getPropertyValue($container) { + return $this->typedData; + } + + /** + * {@inheritdoc} + */ + public function getPropertyName() { + return $this->typedData->getName(); + } + +} diff --git a/core/lib/Drupal/Core/TypedData/Validation/TypedDataAwareValidatorTrait.php b/core/lib/Drupal/Core/TypedData/Validation/TypedDataAwareValidatorTrait.php new file mode 100644 index 0000000..4b61207 --- /dev/null +++ b/core/lib/Drupal/Core/TypedData/Validation/TypedDataAwareValidatorTrait.php @@ -0,0 +1,36 @@ +context; + /** @var \Symfony\Component\Validator\Context\ExecutionContextInterface $context */ + $metadata = $context->getMetadata(); + if ($metadata instanceof TypedDataMetadataInterface) { + return $metadata->getTypedData(); + } + else { + throw new \LogicException("The validator is not using the Typed Data metadata classes."); + } + } + +} diff --git a/core/lib/Drupal/Core/TypedData/Validation/TypedDataMetadataInterface.php b/core/lib/Drupal/Core/TypedData/Validation/TypedDataMetadataInterface.php new file mode 100644 index 0000000..aad790a --- /dev/null +++ b/core/lib/Drupal/Core/TypedData/Validation/TypedDataMetadataInterface.php @@ -0,0 +1,39 @@ +discovery->setDefinition('Null', array( - 'label' => new TranslationWrapper('Null'), - 'class' => '\Symfony\Component\Validator\Constraints\Null', - 'type' => FALSE, - )); - $this->discovery->setDefinition('NotNull', array( - 'label' => new TranslationWrapper('Not null'), - 'class' => '\Symfony\Component\Validator\Constraints\NotNull', - 'type' => FALSE, - )); $this->discovery->setDefinition('Blank', array( 'label' => new TranslationWrapper('Blank'), 'class' => '\Symfony\Component\Validator\Constraints\Blank', diff --git a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/AllowedValuesConstraintValidator.php b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/AllowedValuesConstraintValidator.php index efc6906..ef1fce8 100644 --- a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/AllowedValuesConstraintValidator.php +++ b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/AllowedValuesConstraintValidator.php @@ -7,25 +7,46 @@ namespace Drupal\Core\Validation\Plugin\Validation\Constraint; +use Drupal\Core\DependencyInjection\ContainerInjectionInterface; +use Drupal\Core\Session\AccountInterface; use Drupal\Core\TypedData\OptionsProviderInterface; use Drupal\Core\TypedData\ComplexDataInterface; +use Drupal\Core\TypedData\Validation\TypedDataAwareValidatorTrait; +use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\Constraints\ChoiceValidator; /** * Validates the AllowedValues constraint. */ -class AllowedValuesConstraintValidator extends ChoiceValidator { +class AllowedValuesConstraintValidator extends ChoiceValidator implements ContainerInjectionInterface { + + use TypedDataAwareValidatorTrait; + + /** + * The current user. + * + * @var \Drupal\Core\Session\AccountInterface + */ + protected $currentUser; + + /** + * Constructs a new AllowedValuesConstraintValidator. + * + * @param \Drupal\Core\Session\AccountInterface $current_user + * The current user. + */ + public function __construct(AccountInterface $current_user) { + $this->currentUser = $current_user; + } /** * {@inheritdoc} */ public function validate($value, Constraint $constraint) { - $typed_data = $this->context->getMetadata()->getTypedData(); - + $typed_data = $this->getTypedData(); if ($typed_data instanceof OptionsProviderInterface) { - $account = \Drupal::currentUser(); - $allowed_values = $typed_data->getSettableValues($account); + $allowed_values = $typed_data->getSettableValues($this->currentUser); $constraint->choices = $allowed_values; // If the data is complex, we have to validate its main property. @@ -49,4 +70,11 @@ public function validate($value, Constraint $constraint) { parent::validate($value, $constraint); } + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container) { + return new static($container->get('current_user')); + } + } diff --git a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/ComplexDataConstraintValidator.php b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/ComplexDataConstraintValidator.php old mode 100644 new mode 100755 index add46eb..aab0e7e --- a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/ComplexDataConstraintValidator.php +++ b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/ComplexDataConstraintValidator.php @@ -9,6 +9,8 @@ use Drupal\Core\TypedData\ComplexDataInterface; use Drupal\Core\TypedData\TypedDataInterface; +use Drupal\Core\TypedData\Validation\TypedDataAwareValidatorTrait; +use Drupal\Core\TypedData\Validation\TypedDataPropertyValidationEnvelope; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\ConstraintValidator; use Symfony\Component\Validator\Exception\UnexpectedTypeException; @@ -18,6 +20,8 @@ */ class ComplexDataConstraintValidator extends ConstraintValidator { + use TypedDataAwareValidatorTrait; + /** * {@inheritdoc} */ @@ -28,25 +32,18 @@ public function validate($value, Constraint $constraint) { // If un-wrapped data has been passed, fetch the typed data object first. if (!$value instanceof TypedDataInterface) { - $value = $this->context->getMetadata()->getTypedData(); + $value = $this->getTypedData(); } if (!$value instanceof ComplexDataInterface) { throw new UnexpectedTypeException($value, 'ComplexData'); } - $group = $this->context->getGroup(); - + $metadata = $this->context->getMetadata(); foreach ($constraint->properties as $name => $constraints) { - $property = $value->get($name); - $is_container = $property instanceof ComplexDataInterface || $property instanceof ListInterface; - if (!$is_container) { - $property = $property->getValue(); - } - elseif ($property->isEmpty()) { - // @see \Drupal\Core\TypedData\Validation\PropertyContainerMetadata::accept(); - $property = NULL; - } - $this->context->validateValue($property, $constraints, $name, $group); + $result = $metadata->getPropertyMetadata($name); + $property_metadata = reset($result); + $property_metadata->addExtraConstraints($constraints); } } + } diff --git a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/NotNullConstraint.php b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/NotNullConstraint.php new file mode 100644 index 0000000..cdf1b63 --- /dev/null +++ b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/NotNullConstraint.php @@ -0,0 +1,25 @@ +getTypedData(); + if (($typed_data instanceof ListInterface || $typed_data instanceof ComplexDataInterface) && $typed_data->isEmpty()) { + $value = NULL; + } + parent::validate($value, $constraint); + } + +} diff --git a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/NullConstraint.php b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/NullConstraint.php new file mode 100644 index 0000000..3d87128 --- /dev/null +++ b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/NullConstraint.php @@ -0,0 +1,25 @@ +getTypedData(); + if (($typed_data instanceof ListInterface || $typed_data instanceof ComplexDataInterface) && $typed_data->isEmpty()) { + $value = NULL; + } + parent::validate($value, $constraint); + } + +} diff --git a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/PrimitiveTypeConstraintValidator.php b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/PrimitiveTypeConstraintValidator.php index d1bdc0f..d873820 100644 --- a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/PrimitiveTypeConstraintValidator.php +++ b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/PrimitiveTypeConstraintValidator.php @@ -15,6 +15,7 @@ use Drupal\Core\TypedData\Type\IntegerInterface; use Drupal\Core\TypedData\Type\StringInterface; use Drupal\Core\TypedData\Type\UriInterface; +use Drupal\Core\TypedData\Validation\TypedDataAwareValidatorTrait; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\ConstraintValidator; @@ -23,6 +24,8 @@ */ class PrimitiveTypeConstraintValidator extends ConstraintValidator { + use TypedDataAwareValidatorTrait; + /** * Implements \Symfony\Component\Validator\ConstraintValidatorInterface::validate(). */ @@ -32,7 +35,7 @@ public function validate($value, Constraint $constraint) { return; } - $typed_data = $this->context->getMetadata()->getTypedData(); + $typed_data = $this->getTypedData(); $valid = TRUE; if ($typed_data instanceof BinaryInterface && !is_resource($value)) { $valid = FALSE; diff --git a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/UniqueFieldValueValidator.php b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/UniqueFieldValueValidator.php index a5dde71..d6c3910 100644 --- a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/UniqueFieldValueValidator.php +++ b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/UniqueFieldValueValidator.php @@ -19,7 +19,7 @@ class UniqueFieldValueValidator extends ConstraintValidator { * {@inheritdoc} */ public function validate($items, Constraint $constraint) { - if (!isset($items)) { + if (!$item = $items->first()) { return; } $field_name = $items->getFieldDefinition()->getName(); @@ -31,13 +31,13 @@ public function validate($items, Constraint $constraint) { $value_taken = (bool) \Drupal::entityQuery($entity_type_id) // The id could be NULL, so we cast it to 0 in that case. ->condition($id_key, (int) $items->getEntity()->id(), '<>') - ->condition($field_name, $items->first()->value) + ->condition($field_name, $item->value) ->range(0, 1) ->count() ->execute(); if ($value_taken) { - $this->context->addViolation($constraint->message, array("%value" => $items->value)); + $this->context->addViolation($constraint->message, array("%value" => $item->value)); } } } diff --git a/core/modules/forum/src/Plugin/Validation/Constraint/ForumLeafConstraintValidator.php b/core/modules/forum/src/Plugin/Validation/Constraint/ForumLeafConstraintValidator.php index e4e9be2..f2d2400 100644 --- a/core/modules/forum/src/Plugin/Validation/Constraint/ForumLeafConstraintValidator.php +++ b/core/modules/forum/src/Plugin/Validation/Constraint/ForumLeafConstraintValidator.php @@ -20,10 +20,10 @@ class ForumLeafConstraintValidator extends ConstraintValidator { * {@inheritdoc} */ public function validate($items, Constraint $constraint) { - if (!isset($items)) { - return; - } $item = $items->first(); + if (!isset($item)) { + return NULL; + } // Verify that a term has been selected. if (!$item->entity) { diff --git a/core/modules/quickedit/src/Form/QuickEditFieldForm.php b/core/modules/quickedit/src/Form/QuickEditFieldForm.php index 2db50c4..68d96ed 100644 --- a/core/modules/quickedit/src/Form/QuickEditFieldForm.php +++ b/core/modules/quickedit/src/Form/QuickEditFieldForm.php @@ -17,7 +17,7 @@ use Drupal\Core\Entity\Entity\EntityFormDisplay; use Drupal\user\PrivateTempStoreFactory; use Symfony\Component\DependencyInjection\ContainerInterface; -use Symfony\Component\Validator\ValidatorInterface; +use Symfony\Component\Validator\Validator\ValidatorInterface; /** * Builds and process a form for editing a single entity field. @@ -48,7 +48,7 @@ class QuickEditFieldForm extends FormBase { /** * The typed data validator. * - * @var \Symfony\Component\Validator\ValidatorInterface + * @var \Symfony\Component\Validator\Validator\ValidatorInterface */ protected $validator; @@ -61,7 +61,7 @@ class QuickEditFieldForm extends FormBase { * The module handler. * @param \Drupal\Core\Entity\EntityStorageInterface $node_type_storage * The node type storage. - * @param \Symfony\Component\Validator\ValidatorInterface $validator + * @param \Symfony\Component\Validator\Validator\ValidatorInterface $validator * The typed data validator service. */ public function __construct(PrivateTempStoreFactory $temp_store_factory, ModuleHandlerInterface $module_handler, EntityStorageInterface $node_type_storage, ValidatorInterface $validator) { @@ -165,7 +165,7 @@ public function validateForm(array &$form, FormStateInterface $form_state) { // @todo: Improve this in https://www.drupal.org/node/2395831. $typed_entity = $entity->getTypedData(); $violations = $this->validator - ->validateValue($entity, $typed_entity->getConstraints()); + ->validate($entity, $typed_entity->getConstraints()); foreach ($violations as $violation) { $form_state->setErrorByName($violation->getPropertyPath(), $violation->getMessage()); diff --git a/core/modules/user/src/Plugin/Validation/Constraint/UserMailRequired.php b/core/modules/user/src/Plugin/Validation/Constraint/UserMailRequired.php index 76bc17d..6e9fa3b 100644 --- a/core/modules/user/src/Plugin/Validation/Constraint/UserMailRequired.php +++ b/core/modules/user/src/Plugin/Validation/Constraint/UserMailRequired.php @@ -8,6 +8,7 @@ namespace Drupal\user\Plugin\Validation\Constraint; use Drupal\Component\Utility\SafeMarkup; +use Drupal\Core\TypedData\Validation\TypedDataAwareValidatorTrait; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\ConstraintValidatorInterface; use Symfony\Component\Validator\ExecutionContextInterface; @@ -58,7 +59,7 @@ public function validatedBy() { public function validate($items, Constraint $constraint) { /** @var \Drupal\Core\Field\FieldItemListInterface $items */ /** @var \Drupal\user\UserInterface $account */ - $account = $this->context->getMetadata()->getTypedData()->getEntity(); + $account = $items->getEntity(); $existing_value = NULL; if ($account->id()) { $account_unchanged = \Drupal::entityManager() diff --git a/core/modules/user/src/Tests/UserValidationTest.php b/core/modules/user/src/Tests/UserValidationTest.php index ec44a79..172b79d 100644 --- a/core/modules/user/src/Tests/UserValidationTest.php +++ b/core/modules/user/src/Tests/UserValidationTest.php @@ -122,9 +122,9 @@ function testValidation() { // https://drupal.org/node/2023465. $this->assertEqual(count($violations), 2, 'Violations found when email is too long'); $this->assertEqual($violations[0]->getPropertyPath(), 'mail.0.value'); - $this->assertEqual($violations[0]->getMessage(), t('%name: the email address can not be longer than @max characters.', array('%name' => $user->get('mail')->getFieldDefinition()->getLabel(), '@max' => Email::EMAIL_MAX_LENGTH))); + $this->assertEqual($violations[0]->getMessage(), t('This value is not a valid email address.')); $this->assertEqual($violations[1]->getPropertyPath(), 'mail.0.value'); - $this->assertEqual($violations[1]->getMessage(), t('This value is not a valid email address.')); + $this->assertEqual($violations[1]->getMessage(), t('%name: the email address can not be longer than @max characters.', array('%name' => $user->get('mail')->getFieldDefinition()->getLabel(), '@max' => Email::EMAIL_MAX_LENGTH))); // Provoke an email collision with an existing user. $user->set('mail', 'existing@example.com'); diff --git a/core/tests/Drupal/Tests/Core/Validation/Plugin/Validation/Constraint/PrimitiveTypeConstraintValidatorTest.php b/core/tests/Drupal/Tests/Core/Validation/Plugin/Validation/Constraint/PrimitiveTypeConstraintValidatorTest.php index 0e90672..3a73b60 100644 --- a/core/tests/Drupal/Tests/Core/Validation/Plugin/Validation/Constraint/PrimitiveTypeConstraintValidatorTest.php +++ b/core/tests/Drupal/Tests/Core/Validation/Plugin/Validation/Constraint/PrimitiveTypeConstraintValidatorTest.php @@ -24,7 +24,7 @@ class PrimitiveTypeConstraintValidatorTest extends UnitTestCase { * @dataProvider provideTestValidate */ public function testValidate(PrimitiveInterface $typed_data, $value, $valid) { - $metadata = $this->getMockBuilder('Drupal\Core\TypedData\Validation\Metadata') + $metadata = $this->getMockBuilder('Drupal\Core\TypedData\Validation\GenericMetadata') ->disableOriginalConstructor() ->getMock(); $metadata->expects($this->any()) diff --git a/core/vendor/symfony/validator/Symfony/Component/Validator/Mapping/PreprocessingMetadataInterface.php b/core/vendor/symfony/validator/Symfony/Component/Validator/Mapping/PreprocessingMetadataInterface.php new file mode 100644 index 0000000..0ed57ae --- /dev/null +++ b/core/vendor/symfony/validator/Symfony/Component/Validator/Mapping/PreprocessingMetadataInterface.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Validator\Mapping; + +/** + * Interface for validation metadata that pre-processes values. + * + * Metadata implementing this interface is able to pre-process values before + * they are passed on the constraint validators. + * + * @since 2.7 + * @author Wolfgang Ziegler + * + * @see CascadingStrategy + * @see TraversalStrategy + */ +interface PreprocessingMetadataInterface extends MetadataInterface +{ + /** + * Pre-processes the value before validation. + * + * @param mixed $value The value to be validated. + */ + public function preprocessValue(&$value); + +} diff --git a/core/vendor/symfony/validator/Symfony/Component/Validator/Util/PropertyPath.php b/core/vendor/symfony/validator/Symfony/Component/Validator/Util/PropertyPath.php index 4d397a9..44b625c 100644 --- a/core/vendor/symfony/validator/Symfony/Component/Validator/Util/PropertyPath.php +++ b/core/vendor/symfony/validator/Symfony/Component/Validator/Util/PropertyPath.php @@ -42,7 +42,7 @@ public static function append($basePath, $subPath) return $basePath.$subPath; } - return $basePath ? $basePath.'.'.$subPath : $subPath; + return '' !== (string) $basePath ? $basePath.'.'.$subPath : $subPath; } return $basePath; diff --git a/core/vendor/symfony/validator/Symfony/Component/Validator/Validator/RecursiveContextualValidator.php b/core/vendor/symfony/validator/Symfony/Component/Validator/Validator/RecursiveContextualValidator.php index 191decd..6b12b82 100644 --- a/core/vendor/symfony/validator/Symfony/Component/Validator/Validator/RecursiveContextualValidator.php +++ b/core/vendor/symfony/validator/Symfony/Component/Validator/Validator/RecursiveContextualValidator.php @@ -24,6 +24,7 @@ use Symfony\Component\Validator\Mapping\ClassMetadataInterface; use Symfony\Component\Validator\Mapping\GenericMetadata; use Symfony\Component\Validator\Mapping\MetadataInterface; +use Symfony\Component\Validator\Mapping\PreprocessingMetadataInterface; use Symfony\Component\Validator\Mapping\PropertyMetadataInterface; use Symfony\Component\Validator\Mapping\TraversalStrategy; use Symfony\Component\Validator\MetadataFactoryInterface; @@ -482,6 +483,9 @@ private function validateEachObjectIn($collection, $propertyPath, array $groups, */ private function validateClassNode($object, $cacheKey, ClassMetadataInterface $metadata = null, $propertyPath, array $groups, $cascadedGroups, $traversalStrategy, ExecutionContextInterface $context) { + if ($metadata instanceof PreprocessingMetadataInterface) { + $metadata->preprocessValue($object); + } $context->setNode($object, $object, $metadata, $propertyPath); if (!$context->isObjectInitialized($cacheKey)) { @@ -590,9 +594,7 @@ private function validateClassNode($object, $cacheKey, ClassMetadataInterface $m $object, $cacheKey.':'.$propertyName, $propertyMetadata, - $propertyPath - ? $propertyPath.'.'.$propertyName - : $propertyName, + PropertyPath::append($propertyPath, $propertyName), $groups, $cascadedGroups, TraversalStrategy::IMPLICIT, @@ -676,6 +678,9 @@ private function validateClassNode($object, $cacheKey, ClassMetadataInterface $m */ private function validateGenericNode($value, $object, $cacheKey, MetadataInterface $metadata = null, $propertyPath, array $groups, $cascadedGroups, $traversalStrategy, ExecutionContextInterface $context) { + if ($metadata instanceof PreprocessingMetadataInterface) { + $metadata->preprocessValue($value); + } $context->setNode($value, $object, $metadata, $propertyPath); foreach ($groups as $key => $group) {