Skip to content

Commit

Permalink
feature #38662 [DoctrineBridge][Validator] Allow validating every cla…
Browse files Browse the repository at this point in the history
…ss against unique entity constraint (wkania)

This PR was merged into the 7.1 branch.

Discussion
----------

[DoctrineBridge][Validator] Allow validating every class against unique entity constraint

| Q             | A
| ------------- | ---
| Branch?       | 7.x <!-- see below -->
| Bug fix?      | no
| New feature?  | yes <!-- pleasedate src/**/CHANGELOG.md files -->
| Deprecations? | no <!-- please update UPGRADE-*.md and src/**/CHANGELOG.md files -->
| Tickets       | Fix #22592
| License       | MIT
| Doc PR        | symfony/symfony-docs#14458 <!-- required for new features -->

Yet another try to allow validating every class against unique entity constraint.
Based on the knowledge from issue #22592 and pull request #24974.

This constraint doesn’t provide any protection against race conditions, which is enough in most cases. You can always try-catch flush method. Let's not talk about this problem.

Current state:
- can be applied only to an entity,
- support entity inheritance,
- can validate unique combinations of multiple fields,
- meaningful errors related to entities,
- is valid during an update, when the only matched entity is the same as the entity being validated

New state:
- preserve the current state,
- all old tests pass (no changes in them),
- no breaking changes,
- can be applied to any class (like DTO),
- can map object fields to entity fields (optional),
- when the object update some entity, there is an option to provide the identifier field names to match that entity (optional)

Examples:
1. DTO adds a new entity.
```
namespace App\Message;

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

/**
 * `@UniqueEntity`(fields={"name"}, entityClass="App\Entity\User")
 */
class HireAnEmployee
{
    public $name;

    public function __construct($name)
    {
        $this->name = $name;
    }
}
```

2. DTO adds a new entity, but the name of the field in the entity is different.
```
namespace App\Message;

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

/**
 * `@UniqueEntity`(fields={"name": "username"}, entityClass="App\Entity\User")
 */
class HireAnEmployee
{
    public $name;

    public function __construct($name)
    {
        $this->name = $name;
    }
}
```

3. DTO updates an entity.
```
namespace App\Message;

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

/**
 * `@UniqueEntity`(fields={"name"}, entityClass="App\Entity\User", identifierFieldNames={"uid": "id"})
 */
class UpdateEmployeeProfile
{
    public $uid;
    public $name;

    public function __construct($uid, $name)
    {
        $this->uid = $uid;
        $this->name = $name;
    }
}
```

Commits
-------

adb9afa [DoctrineBridge][Validator] Allow validating every class against unique entity constraint
  • Loading branch information
fabpot committed May 2, 2024
2 parents 0302e1d + adb9afa commit 5bc490c
Show file tree
Hide file tree
Showing 10 changed files with 490 additions and 22 deletions.
1 change: 1 addition & 0 deletions src/Symfony/Bridge/Doctrine/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ CHANGELOG
* Deprecate the `DoctrineExtractor::getTypes()` method, use `DoctrineExtractor::getType()` instead
* Allow `EntityValueResolver` to return a list of entities
* Add support for auto-closing idle connections
* Allow validating every class against `UniqueEntity` constraint

7.0
---
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Bridge\Doctrine\Tests\Fixtures;

class CreateDoubleNameEntity
{
public $primaryName;
public $secondaryName;

public function __construct($primaryName, $secondaryName)
{
$this->primaryName = $primaryName;
$this->secondaryName = $secondaryName;
}
}
17 changes: 17 additions & 0 deletions src/Symfony/Bridge/Doctrine/Tests/Fixtures/Dto.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Bridge\Doctrine\Tests\Fixtures;

class Dto
{
public string $foo;
}
22 changes: 22 additions & 0 deletions src/Symfony/Bridge/Doctrine/Tests/Fixtures/HireAnEmployee.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Bridge\Doctrine\Tests\Fixtures;

class HireAnEmployee
{
public $name;

public function __construct($name)
{
$this->name = $name;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Bridge\Doctrine\Tests\Fixtures;

class UpdateCompositeIntIdEntity
{
public $id1;
public $id2;
public $name;

public function __construct($id1, $id2, $name)
{
$this->id1 = $id1;
$this->id2 = $id2;
$this->name = $name;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Bridge\Doctrine\Tests\Fixtures;

class UpdateCompositeObjectNoToStringIdEntity
{
/**
* @var SingleIntIdNoToStringEntity
*/
protected $object1;

/**
* @var SingleIntIdNoToStringEntity
*/
protected $object2;

public $name;

public function __construct(SingleIntIdNoToStringEntity $object1, SingleIntIdNoToStringEntity $object2, $name)
{
$this->object1 = $object1;
$this->object2 = $object2;
$this->name = $name;
}

public function getObject1(): SingleIntIdNoToStringEntity
{
return $this->object1;
}

public function getObject2(): SingleIntIdNoToStringEntity
{
return $this->object2;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Bridge\Doctrine\Tests\Fixtures;

class UpdateEmployeeProfile
{
public $id;
public $name;

public function __construct($id, $name)
{
$this->id = $id;
$this->name = $name;
}
}

0 comments on commit 5bc490c

Please sign in to comment.