From 8f8706f1fbf706d30af2e3e37b34a6c6522aeff1 Mon Sep 17 00:00:00 2001 From: Wojciech Kania Date: Mon, 12 Feb 2024 22:20:08 +0100 Subject: [PATCH] [DoctrineBridge][Validator] Allow validating every class against unique entity constraint --- reference/constraints/UniqueEntity.rst | 124 +++++++++++++++++++++++++ 1 file changed, 124 insertions(+) diff --git a/reference/constraints/UniqueEntity.rst b/reference/constraints/UniqueEntity.rst index ad7c09f1c31..c3974c0455f 100644 --- a/reference/constraints/UniqueEntity.rst +++ b/reference/constraints/UniqueEntity.rst @@ -5,6 +5,10 @@ Validates that a particular field (or fields) in a Doctrine entity is (are) unique. This is commonly used, for example, to prevent a new user to register using an email address that already exists in the system. +.. versionadded:: 7.1 + + Any class instance (like DTO) field (or fields) validation against entities persisted in the database was introduced in Symfony 7.1. + .. seealso:: If you want to validate that all the elements of the collection are unique @@ -162,6 +166,7 @@ the current class instance. However, in some cases, such as when using Doctrine inheritance mapping, you need to execute the query in a different repository. Use this option to define the fully-qualified class name (FQCN) of the Doctrine entity associated with the repository you want to use. +Another case is when the object being validated is not an entity. ``errorPath`` ~~~~~~~~~~~~~ @@ -274,6 +279,125 @@ each with a single field. .. include:: /reference/constraints/_groups-option.rst.inc +If object being validated field name(s) do not match the one(s) from the entity, +use key-value mapping; Where ``key`` is the name of the field in the object being +validated and ``value`` is the name of the field in the entity. +Field name(s) mapping only applies when the object being validated is not an entity. + +``identifierFieldNames`` +~~~~~~~~~~~~~~~~~~~~~~~~ + +**type**: ``array`` | ``string`` [:ref:`default option `] + +Use it only when the object being validated is not an entity and you need to update an +entity with it. +This option is the identifier field name that is the ``primary key`` or the identifier +field names that are ``composite keys`` in the entity class set by the `entityClass`_ +option. +If set, it won’t trigger a uniqueness constraint violation when the only not unique +entity identifier(s) value(s) will be matching corresponding value(s) from the +object being validated. +If object being validated field name(s) do not match the one(s) from the entity, +use key-value mapping; Where ``key`` is the name of the field in the object being +validated and ``value`` is the name of the field in the entity. + +Consider this example: + +.. configuration-block:: + + .. code-block:: php-attributes + + // src/Entity/User.php + namespace App\Entity; + + use Doctrine\ORM\Mapping as ORM; + + #[ORM\Entity] + class User + { + #[ORM\Column(type: 'string')] + public string $id; + + #[ORM\Column(type: 'string')] + public string $username; + } + + // src/Message/UpdateEmployeeProfile.php + namespace App\Message; + + use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; + + #[UniqueEntity( + fields: ['name' => 'username'], + entityClass: 'App\Entity\User', + identifierFieldNames: ['uid' => 'id'], + )] + class UpdateEmployeeProfile + { + public function __construct(public string $uid, public string $name) + { + } + } + + .. code-block:: yaml + + # config/validator/validation.yaml + App\Message\UpdateEmployeeProfile: + constraints: + - Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity: + fields: {name: username} + entityClass: 'App\Entity\User' + identifierFieldNames: {uid: id} + + .. code-block:: xml + + + + + + + + + + + + + + + + .. code-block:: php + + // src/Message/UpdateEmployeeProfile.php + namespace App\Message; + + use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; + use Symfony\Component\Validator\Mapping\ClassMetadata; + + class UpdateEmployeeProfile + { + public string $uid; + public string $name; + + public static function loadValidatorMetadata(ClassMetadata $metadata) + { + $metadata->addConstraint(new UniqueEntity([ + 'fields' => ['name' => 'username'], + 'entityClass' => 'App\Entity\User', + 'identifierFieldNames' => ['uid' => 'id'], + ])); + } + } + +.. versionadded:: 7.1 + + The option was introduced in Symfony 7.1. + ``ignoreNull`` ~~~~~~~~~~~~~~