symfony: [DoctrineBridge] UniqueEntity validator problem with entityClass
Q | A |
---|---|
Bug report? | yes/no |
Feature request? | no |
BC Break report? | yes/no |
RFC? | yes |
Symfony version | 3.2.0 |
I wonder how this should work for very common example using DTOs for forms. I have applied validation to my DTO
AppBundle\Command\Register:
constraints:
- Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity:
fields: email
entityClass: AppBundle\Entity\User
em: default
With this configuration I get error: “The class ‘AppBundle\Command\Register’ was not found in the chain configured namespaces AppBundle\Entity”
The flow currently works like this I set em
for my entity: AppBundle\Entity\User
but in validator we have getting current class metadata for main entity (in my example AppBundle\Command\Register this is not an entity) $em->getClassMetadata(get_class($entity)); so this is why it fails.
# Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntityValidator
if ($constraint->em) {
$em = $this->registry->getManager($constraint->em);
if (!$em) {
throw new ConstraintDefinitionException(sprintf('Object manager "%s" does not exist.', $constraint->em));
}
} else {
$em = $this->registry->getManagerForClass(get_class($entity));
if (!$em) {
throw new ConstraintDefinitionException(sprintf('Unable to find the object manager associated with an entity of class "%s".', get_class($entity)));
}
}
$class = $em->getClassMetadata(get_class($entity));
/* @var $class \Doctrine\Common\Persistence\Mapping\ClassMetadata */
IMHO if we specify entityClass we should expect that everything will concern this entityClass. Another example of failure is when two entities: entity1 and entity2 belong to different entity managers. If this is an expected behaviour (IMHO it should work like this) we should at least add this information to documentation ?
About this issue
- Original URL
- State: closed
- Created 7 years ago
- Reactions: 44
- Comments: 33 (14 by maintainers)
Commits related to this issue
- feature #38662 [DoctrineBridge][Validator] Allow validating every class against unique entity constraint (wkania) This PR was merged into the 7.1 branch. Discussion ---------- [DoctrineBridge][Vali... — committed to symfony/symfony by fabpot 2 months ago
- feature #38662 [DoctrineBridge][Validator] Allow validating every class against unique entity constraint (wkania) This PR was merged into the 7.1 branch. Discussion ---------- [DoctrineBridge][Vali... — committed to symfony/doctrine-bridge by fabpot 2 months ago
The
UniqueEntity
does not work on non-entity objects afaik. However, I think a proper solution would would be to just try and insert, then catch the unique constraint exception and add a form error:Even when the purpose of the
entityClass
was to execute the query in a different repository (in some cases, such as when using Doctrine inheritance mapping), I wonder if we could expand its scope to applyUniqueEntity()
for non-entity objects (beingentityClass
mandatory in these case).The target of this constraint is validate that a particular field (or fields) in a Doctrine entity is (are) unique, so what if:
entityClass
option (if set) instead ofget_class($entity)
,PropertyAccess
component instead ofReflectionProperty
to read the field value from current object (maintain the metadata verification and the DTO fields must be readable too),We would have DTO’s with multiple
UniqueEntity
constraints so:Is it something we want/can to support?
https://github.com/symfony/symfony/issues/14917 related
ping @ogizanagi, @HeahDude
@yceruto I considered something similar in the past; I wasn’t sure about reusing the same constraint but now I’d say it makes sense. And the feature would be particularly useful for validating commands (command bus) for instance.
But we will also need a mapping between the DTOs fields and the targeted entity fields as their naming might slightly differ.
Foolish example:
Facing the same issue and definitely interested 👍
Personally I still think this is quite an important feature.
I’m coming back on this issue since I’m having it right away.
While working on my side-project, I wanted to create a DTO that would contain the
UniqueEntity
constraint associated with another class.For now, as a first solution, I suggest that we provide a quick “fix” (I think it’s an issue and not a feature to make sure we can properly use the constraint with DTO-like classes.
Next, on a second plan, I think we can provide another format for the
fields
mapping option in order to be able to associated DTO fields with entity fields if names differ.I can make a PR for the first one, since I started the work on it before discovering this issue.
Friendly ping @nicolas-grekas for a potential decision on the core-team side
That’s probably not enough. You also need to consider a way to determine whether or not a possible result is the object currently being modified (the current implementation checks for the object being returned to be the same as the one being validated).
@ogizanagi Perhaps this could help?
https://gist.github.com/webbertakken/569409670bfc7c079e276f79260105ed
A working mapping like you suggested.
While it may not display the errors in the WDT, the error will still be shown when you render the form.
This is true. However, 1ms after the form was valid (it was unique at the moment of validation) and after that moment, someone else just flushed their entity with the exact same value, your flush will now fail with a
UniqueConstraintException
.Another possible solution: https://gist.github.com/Xymanek/369f468d02069090770a1e4626d9f1e9
I can make a PR if it looks good
This breaks my DDD
I made my own like this. Not perfect, but it works fine so far.
Cheers
Hello @nickicool,
This won’t work if you intend to make an update of your entity.
Another good solution for validate DTO’s on unique field here
I just encountered the same issue and it should definitely be fixed as using a DTO is just cleaner than using the entity directly, especially with multiple APIs and possible necessary transformations.
Would be great if it would make it into 5.4
And the PR above https://github.com/symfony/symfony/pull/38662 seems to address and fix this issue already, it even takes possible property / field mappings into account, would be nice if it is merged or, if necessary, adjusted and merged so it can make it into 5.4 and 6.0
Wondering if this could be worked out (or worked-around) on Doctrine side.
Wouldn’t it make sense to configure/extend from Doctrine Bridge to make it aware that a DTO corresponds to a specific Entity?
This way the UniqueEntity constraints would work transparently and wouldn’t need to care if the variable is an actual Entity or a representation of that (DTO).
Facing the very same issue, this would be a must have feature