Wojciech Kania
Contributed by Wojciech Kania in #38662

In Symfony applications, the UniqueEntity constraint validates that some field (or fields) in a Doctrine entity is (are) unique. This is useful for example to prevent a new user to register using an email address that already exists in the system.

In Symfony 7.1, we're improving this constraint to also check uniqueness on any PHP class (e.g. DTOs) and not only on Doctrine entities. Consider the following Doctrine entity:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 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;
}

Instead of adding the UniqueEntity constraint to it, you can now check for uniqueness in other ways. For example, in a Messenger component message that creates User entities, you can now define the following:

1
2
3
4
5
6
7
8
9
10
11
12
namespace App\Message;

use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;

#[UniqueEntity(fields: ['username'], entityClass: User::class)]
class HireAnEmployee
{
    public function __construct(
        private string $username
    ) {
    }
}

Although the HireAnEmployee class is not a Doctrine entity, this constraint will effectively check that the given username value is unique for the User Doctrine class.

If the names of the unique properties in this class are different from the Doctrine entity property names, you can map them:

1
2
3
4
5
6
#[UniqueEntity(
    // 'userIdentifier' is the property name in the PHP class and
    // 'username' is the property name in the Doctrine entity
    fields: ['userIdentifier' => 'username'],
    entityClass: User::class,
)]

When updating an entity, use the identifierFieldNames option to define the class properties that are used as the Doctrine entity key (or composite key):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
namespace App\Message;

use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;

#[UniqueEntity(
    fields: ['name'],
    entityClass: User::class,
    // 'uid' is the property name in the PHP class and 'id' is the name of
    // the Doctrine entity property used as the primary key
    identifierFieldNames: ['uid' => 'id'],
)]
class UpdateEmployeeProfile
{
    public function __construct(
        private string $uid,
        private string $name,
    ) {
    }
}
Published in #Living on the edge