8000 bug #57188 [DoctrineBridge] Fix `UniqueEntityValidator` with proxy ob… · symfony/symfony@a2890a6 · GitHub
[go: up one dir, main page]

Skip to content

Commit a2890a6

Browse files
committed
bug #57188 [DoctrineBridge] Fix UniqueEntityValidator with proxy object (HypeMC)
This PR was merged into the 7.1 branch. Discussion ---------- [DoctrineBridge] Fix `UniqueEntityValidator` with proxy object | Q | A | ------------- | --- | Branch? | 7.1 | Bug fix? | yes | New feature? | no | Deprecations? | no | Issues | Fix #57075 | License | MIT Before #38662, `$fieldValue = $class->reflFields[$fieldName]->getValue($entity);` was used to get the value of a property, so it makes sense to keep using it when the object is an entity. Commits ------- 99f279b [DoctrineBridge] Fix `UniqueEntityValidator` with proxy object
2 parents 6644076 + 99f279b commit a2890a6

File tree

3 files changed

+80
-9
lines changed

3 files changed

+80
-9
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Bridge\Doctrine\Tests\Fixtures;
13+
14+
use Doctrine\ORM\Mapping\Column;
15+
use Doctrine\ORM\Mapping\Entity;
16+
use Doctrine\ORM\Mapping\Id;
17+
18+
#[Entity]
19+
class SingleIntIdWithPrivateNameEntity
20+
{
21+
public function __construct(
22+
#[Id, Column(type: 'integer')]
23+
protected int $id,
24+
25+
#[Column(type: 'string', nullable: true)]
26+
private ?string $name,
27+
) {
28+
}
29+
30+
public function getName(): ?string
31+
{
32+
return $this->name;
33+
}
34+
35+
public function __toString(): string
36+
{
37+
return (string) $this->name;
38+
}
39+
}

src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityValidatorTest.php

+38-8
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
use Symfony\Bridge\Doctrine\Tests\Fixtures\SingleIntIdEntity;
3737
use Symfony\Bridge\Doctrine\Tests\Fixtures\SingleIntIdNoToStringEntity;
3838
use Symfony\Bridge\Doctrine\Tests\Fixtures\SingleIntIdStringWrapperNameEntity;
39+
use Symfony\Bridge\Doctrine\Tests\Fixtures\SingleIntIdWithPrivateNameEntity;
3940
use Symfony\Bridge\Doctrine\Tests\Fixtures\SingleStringIdEntity;
4041
use Symfony\Bridge\Doctrine\Tests\Fixtures\Type\StringWrapper;
4142
use Symfony\Bridge\Doctrine\Tests\Fixtures\Type\StringWrapperType;
@@ -90,12 +91,17 @@ protected function createRegistryMock($em = null)
9091
return $registry;
9192
}
9293

93-
protected function createRepositoryMock()
94+
protected function createRepositoryMock(string $className)
9495
{
95-
return $this->getMockBuilder(MockableRepository::class)
96+
$repositoryMock = $this->getMockBuilder(MockableRepository::class)
9697
->disableOriginalConstructor()
9798
->onlyMethods(['find', 'findAll', 'findOneBy', 'findBy', 'getClassName', 'findByCustom'])
9899
->getMock();
100+
101+
$repositoryMock->method('getClassName')
102+
->willReturn($className);
103+
104+
return $repositoryMock;
99105
}
100106

101107
protected function createEntityManagerMock($repositoryMock)
@@ -109,6 +115,10 @@ protected function createEntityManagerMock($repositoryMock)
109115
$classMetadata = $this->createMock(
110116
class_exists(ClassMetadataInfo::class) ? ClassMetadataInfo::class : ClassMetadata::class
111117
);
118+
$classMetadata
119+
->method('getName')
120+
->willReturn($repositoryMock->getClassName())
121+
;
112122
$classMetadata
113123
->expects($this->any())
114124
->method('hasField')
@@ -138,6 +148,7 @@ private function createSchema($em)
138148
$schemaTool = new SchemaTool($em);
139149
$schemaTool->createSchema([
140150
$em->getClassMetadata(SingleIntIdEntity::class),
151+
$em->getClassMetadata(SingleIntIdWithPrivateNameEntity::class),
141152
$em->getClassMetadata(SingleIntIdNoToStringEntity::class),
142153
$em->getClassMetadata(DoubleNameEntity::class),
143154
$em->getClassMetadata(DoubleNullableNameEntity::class),
@@ -194,6 +205,25 @@ public static function provideUniquenessConstraints(): iterable
194205
yield 'Named arguments' => [new UniqueEntity(message: 'myMessage', fields: ['name'], em: 'foo')];
195206
}
196207

208+
public function testValidateEntityWithPrivatePropertyAndProxyObject()
209+
{
210+
$entity = new SingleIntIdWithPrivateNameEntity(1, 'Foo');
211+
$this->em->persist($entity);
212+
$this->em->flush();
213+
214+
$this->em->clear();
215+
216+
// this will load a proxy object
217+
$entity = $this->em->getReference(SingleIntIdWithPrivateNameEntity::class, 1);
218+
219+
$this->validator->validate($entity, new UniqueEntity([
220+
'fields' => ['name'],
221+
'em' => self::EM_NAME,
222+
]));
223+
224+
$this->assertNoViolation();
225+
}
226+
197227
/**
198228
* @dataProvider provideConstraintsWithCustomErrorPath
199229
*/
@@ -387,7 +417,7 @@ public function testValidateUniquenessWithValidCustomErrorPath()
387417
*/
388418
public function testValidateUniquenessUsingCustomRepositoryMethod(UniqueEntity $constraint)
389419
{
390-
$repository = $this->createRepositoryMock();
420+
$repository = $this->createRepositoryMock(SingleIntIdEntity::class);
391421
$repository->expects($this->once())
392422
->method('findByCustom')
393423
->willReturn([])
@@ -411,7 +441,7 @@ public function testValidateUniquenessWithUnrewoundArray(UniqueEntity $constrain
411441
{
412442
$entity = new SingleIntIdEntity(1, 'foo');
413443

414-
$repository = $this->createRepositoryMock();
444+
$repository = $this->createRepositoryMock(SingleIntIdEntity::class);
415445
$repository->expects($this->once())
416446
->method('findByCustom')
417447
->willReturnCallback(
@@ -459,7 +489,7 @@ public function testValidateResultTypes($entity1, $result)
459489
'repositoryMethod' => 'findByCustom',
460490
]);
461491

462-
$repository = $this->createRepositoryMock();
492+
$repository = $this->createRepositoryMock($entity1::class);
463493
$repository->expects($this->once())
464494
->method('findByCustom')
465495
->willReturn($result)
@@ -581,7 +611,7 @@ public function testAssociatedEntityWithNull()
581611

582612
public function testValidateUniquenessWithArrayValue()
583613
{
584-
$repository = $this->createRepositoryMock();
614+
$repository = $this->createRepositoryMock(SingleIntIdEntity::class);
585615
$this->repositoryFactory->setRepository($this->em, SingleIntIdEntity::class, $repository);
586616

587617
$constraint = new UniqueEntity([
@@ -662,7 +692,7 @@ public function testEntityManagerNullObject()
662692

663693
public function testValidateUniquenessOnNullResult()
664694
{
665-
$repository = $this->createRepositoryMock();
695+
$repository = $this->createRepositoryMock(SingleIntIdEntity::class);
666696
$repository
667697
->method('find')
668698
->willReturn(null)
@@ -850,7 +880,7 @@ public function testValidateUniquenessWithEmptyIterator($entity, $result)
850880
'repositoryMethod' => 'findByCustom',
851881
]);
852882

853-
$repository = $this->createRepositoryMock();
883+
$repository = $this->createRepositoryMock($entity::class);
854884
$repository->expects($this->once())
855885
->method('findByCustom')
856886
->willReturn($result)

src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntityValidator.php

+3-1
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,9 @@ private function getFieldValues(mixed $object, ClassMetadata $class, array $fiel
287287
throw new ConstraintDefinitionException(sprintf('The field "%s" is not a property of class "%s".', $fieldName, $objectClass));
288288
}
289289

290-
$fieldValues[$entityFieldName] = $this->getPropertyValue($objectClass, $fieldName, $object);
290+
$fieldValues[$entityFieldName] = $isValueEntity && $object instanceof ($class->getName())
291+
? $class->reflFields[$fieldName]->getValue($object)
292+
: $this->getPropertyValue($objectClass, $fieldName, $object);
291293
}
292294

293295
return $fieldValues;

0 commit comments

Comments
 (0)
0