Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit a2890a6

Browse filesBrowse 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
Copy full SHA for a2890a6

File tree

Expand file treeCollapse file tree

3 files changed

+80
-9
lines changed
Filter options
Expand file treeCollapse file tree

3 files changed

+80
-9
lines changed
+39Lines changed: 39 additions & 0 deletions
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

Copy file name to clipboardExpand all lines: src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityValidatorTest.php
+38-8Lines changed: 38 additions & 8 deletions
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

Copy file name to clipboardExpand all lines: src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntityValidator.php
+3-1Lines changed: 3 additions & 1 deletion
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)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.