Skip to content

Commit 744e54b

Browse files
committed
bug #54835 [DoctrineBridge]  fix setting validated fields not using the options array (xabbuh)
This PR was merged into the 7.1 branch. Discussion ---------- [DoctrineBridge]  fix setting validated fields not using the options array | Q | A | ------------- | --- | Branch? | 7.1 | Bug fix? | yes | New feature? | no | Deprecations? | no | Issues | | License | MIT Commits ------- d19dfaf fix setting validated fields not using the options array
2 parents 14a104a + d19dfaf commit 744e54b

File tree

2 files changed

+241
-2
lines changed

2 files changed

+241
-2
lines changed

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

Lines changed: 239 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -951,6 +951,40 @@ public function rewind(): void
951951
}
952952

953953
public function testValidateDTOUniqueness()
954+
{
955+
$constraint = new UniqueEntity(
956+
message: 'myMessage',
957+
fields: ['name'],
958+
em: self::EM_NAME,
959+
entityClass: Person::class,
960+
);
961+
962+
$entity = new Person(1, 'Foo');
963+
$dto = new HireAnEmployee('Foo');
964+
965+
$this->validator->validate($entity, $constraint);
966+
967+
$this->assertNoViolation();
968+
969+
$this->em->persist($entity);
970+
$this->em->flush();
971+
972+
$this->validator->validate($entity, $constraint);
973+
974+
$this->assertNoViolation();
975+
976+
$this->validator->validate($dto, $constraint);
977+
978+
$this->buildViolation('myMessage')
979+
->atPath('property.path.name')
980+
->setInvalidValue('Foo')
981+
->setCode(UniqueEntity::NOT_UNIQUE_ERROR)
982+
->setCause([$entity])
983+
->setParameters(['{{ value }}' => '"Foo"'])
984+
->assertRaised();
985+
}
986+
987+
public function testValidateDTOUniquenessDoctrineStyle()
954988
{
955989
$constraint = new UniqueEntity([
956990
'message' => 'myMessage',
@@ -985,6 +1019,32 @@ public function testValidateDTOUniqueness()
9851019
}
9861020

9871021
public function testValidateMappingOfFieldNames()
1022+
{
1023+
$constraint = new UniqueEntity(
1024+
message: 'myMessage',
1025+
fields: ['primaryName' => 'name', 'secondaryName' => 'name2'],
1026+
em: self::EM_NAME,
1027+
entityClass: DoubleNameEntity::class,
1028+
);
1029+
1030+
$entity = new DoubleNameEntity(1, 'Foo', 'Bar');
1031+
$dto = new CreateDoubleNameEntity('Foo', 'Bar');
1032+
1033+
$this->em->persist($entity);
1034+
$this->em->flush();
1035+
1036+
$this->validator->validate($dto, $constraint);
1037+
1038+
$this->buildViolation('myMessage')
1039+
->atPath('property.path.name')
1040+
->setParameter('{{ value }}', '"Foo"')
1041+
->setInvalidValue('Foo')
1042+
->setCause([$entity])
1043+
->setCode(UniqueEntity::NOT_UNIQUE_ERROR)
1044+
->assertRaised();
1045+
}
1046+
1047+
public function testValidateMappingOfFieldNamesDoctrineStyle()
9881048
{
9891049
$constraint = new UniqueEntity([
9901050
'message' => 'myMessage',
@@ -1011,6 +1071,21 @@ public function testValidateMappingOfFieldNames()
10111071
}
10121072

10131073
public function testInvalidateDTOFieldName()
1074+
{
1075+
$this->expectException(ConstraintDefinitionException::class);
1076+
$this->expectExceptionMessage('The field "primaryName" is not a property of class "Symfony\Bridge\Doctrine\Tests\Fixtures\HireAnEmployee".');
1077+
$constraint = new UniqueEntity(
1078+
message: 'myMessage',
1079+
fields: ['primaryName' => 'name'],
1080+
em: self::EM_NAME,
1081+
entityClass: SingleStringIdEntity::class,
1082+
);
1083+
1084+
$dto = new HireAnEmployee('Foo');
1085+
$this->validator->validate($dto, $constraint);
1086+
}
1087+
1088+
public function testInvalidateDTOFieldNameDoctrineStyle()
10141089
{
10151090
$this->expectException(ConstraintDefinitionException::class);
10161091
$this->expectExceptionMessage('The field "primaryName" is not a property of class "Symfony\Bridge\Doctrine\Tests\Fixtures\HireAnEmployee".');
@@ -1026,6 +1101,21 @@ public function testInvalidateDTOFieldName()
10261101
}
10271102

10281103
public function testInvalidateEntityFieldName()
1104+
{
1105+
$this->expectException(ConstraintDefinitionException::class);
1106+
$this->expectExceptionMessage('The field "name2" is not mapped by Doctrine, so it cannot be validated for uniqueness.');
1107+
$constraint = new UniqueEntity(
1108+
message: 'myMessage',
1109+
fields: ['name2'],
1110+
em: self::EM_NAME,
1111+
entityClass: SingleStringIdEntity::class,
1112+
);
1113+
1114+
$dto = new HireAnEmployee('Foo');
1115+
$this->validator->validate($dto, $constraint);
1116+
}
1117+
1118+
public function testInvalidateEntityFieldNameDoctrineStyle()
10291119
{
10301120
$this->expectException(ConstraintDefinitionException::class);
10311121
$this->expectExceptionMessage('The field "name2" is not mapped by Doctrine, so it cannot be validated for uniqueness.');
@@ -1041,6 +1131,36 @@ public function testInvalidateEntityFieldName()
10411131
}
10421132

10431133
public function testValidateDTOUniquenessWhenUpdatingEntity()
1134+
{
1135+
$constraint = new UniqueEntity(
1136+
message: 'myMessage',
1137+
fields: ['name'],
1138+
em: self::EM_NAME,
1139+
entityClass: Person::class,
1140+
identifierFieldNames: ['id'],
1141+
);
1142+
1143+
$entity1 = new Person(1, 'Foo');
1144+
$entity2 = new Person(2, 'Bar');
1145+
1146+
$this->em->persist($entity1);
1147+
$this->em->persist($entity2);
1148+
$this->em->flush();
1149+
1150+
$dto = new UpdateEmployeeProfile(2, 'Foo');
1151+
1152+
$this->validator->validate($dto, $constraint);
1153+
1154+
$this->buildViolation('myMessage')
1155+
->atPath('property.path.name')
1156+
->setInvalidValue('Foo')
1157+
->setCode(UniqueEntity::NOT_UNIQUE_ERROR)
1158+
->setCause([$entity1])
1159+
->setParameters(['{{ value }}' => '"Foo"'])
1160+
->assertRaised();
1161+
}
1162+
1163+
public function testValidateDTOUniquenessWhenUpdatingEntityDoctrineStyle()
10441164
{
10451165
$constraint = new UniqueEntity([
10461166
'message' => 'myMessage',
@@ -1071,6 +1191,28 @@ public function testValidateDTOUniquenessWhenUpdatingEntity()
10711191
}
10721192

10731193
public function testValidateDTOUniquenessWhenUpdatingEntityWithTheSameValue()
1194+
{
1195+
$constraint = new UniqueEntity(
1196+
message: 'myMessage',
1197+
fields: ['name'],
1198+
em: self::EM_NAME,
1199+
entityClass: CompositeIntIdEntity::class,
1200+
identifierFieldNames: ['id1', 'id2'],
1201+
);
1202+
1203+
$entity = new CompositeIntIdEntity(1, 2, 'Foo');
1204+
1205+
$this->em->persist($entity);
1206+
$this->em->flush();
1207+
1208+
$dto = new UpdateCompositeIntIdEntity(1, 2, 'Foo');
1209+
1210+
$this->validator->validate($dto, $constraint);
1211+
1212+
$this->assertNoViolation();
1213+
}
1214+
1215+
public function testValidateDTOUniquenessWhenUpdatingEntityWithTheSameValueDoctrineStyle()
10741216
{
10751217
$constraint = new UniqueEntity([
10761218
'message' => 'myMessage',
@@ -1093,6 +1235,35 @@ public function testValidateDTOUniquenessWhenUpdatingEntityWithTheSameValue()
10931235
}
10941236

10951237
public function testValidateIdentifierMappingOfFieldNames()
1238+
{
1239+
$constraint = new UniqueEntity(
1240+
message: 'myMessage',
1241+
fields: ['object1' => 'objectOne', 'object2' => 'objectTwo'],
1242+
em: self::EM_NAME,
1243+
entityClass: CompositeObjectNoToStringIdEntity::class,
1244+
identifierFieldNames: ['object1' => 'objectOne', 'object2' => 'objectTwo'],
1245+
);
1246+
1247+
$objectOne = new SingleIntIdNoToStringEntity(1, 'foo');
1248+
$objectTwo = new SingleIntIdNoToStringEntity(2, 'bar');
1249+
1250+
$this->em->persist($objectOne);
1251+
$this->em->persist($objectTwo);
1252+
$this->em->flush();
1253+
1254+
$entity = new CompositeObjectNoToStringIdEntity($objectOne, $objectTwo);
1255+
1256+
$this->em->persist($entity);
1257+
$this->em->flush();
1258+
1259+
$dto = new UpdateCompositeObjectNoToStringIdEntity($objectOne, $objectTwo, 'Foo');
1260+
1261+
$this->validator->validate($dto, $constraint);
1262+
1263+
$this->assertNoViolation();
1264+
}
1265+
1266+
public function testValidateIdentifierMappingOfFieldNamesDoctrineStyle()
10961267
{
10971268
$constraint = new UniqueEntity([
10981269
'message' => 'myMessage',
@@ -1122,6 +1293,34 @@ public function testValidateIdentifierMappingOfFieldNames()
11221293
}
11231294

11241295
public function testInvalidateMissingIdentifierFieldName()
1296+
{
1297+
$this->expectException(ConstraintDefinitionException::class);
1298+
$this->expectExceptionMessage('The "Symfony\Bridge\Doctrine\Tests\Fixtures\CompositeObjectNoToStringIdEntity" entity identifier field names should be "objectOne, objectTwo", not "objectTwo".');
1299+
$constraint = new UniqueEntity(
1300+
message: 'myMessage',
1301+
fields: ['object1' => 'objectOne', 'object2' => 'objectTwo'],
1302+
em: self::EM_NAME,
1303+
entityClass: CompositeObjectNoToStringIdEntity::class,
1304+
identifierFieldNames: ['object2' => 'objectTwo'],
1305+
);
1306+
1307+
$objectOne = new SingleIntIdNoToStringEntity(1, 'foo');
1308+
$objectTwo = new SingleIntIdNoToStringEntity(2, 'bar');
1309+
1310+
$this->em->persist($objectOne);
1311+
$this->em->persist($objectTwo);
1312+
$this->em->flush();
1313+
1314+
$entity = new CompositeObjectNoToStringIdEntity($objectOne, $objectTwo);
1315+
1316+
$this->em->persist($entity);
1317+
$this->em->flush();
1318+
1319+
$dto = new UpdateCompositeObjectNoToStringIdEntity($objectOne, $objectTwo, 'Foo');
1320+
$this->validator->validate($dto, $constraint);
1321+
}
1322+
1323+
public function testInvalidateMissingIdentifierFieldNameDoctrineStyle()
11251324
{
11261325
$this->expectException(ConstraintDefinitionException::class);
11271326
$this->expectExceptionMessage('The "Symfony\Bridge\Doctrine\Tests\Fixtures\CompositeObjectNoToStringIdEntity" entity identifier field names should be "objectOne, objectTwo", not "objectTwo".');
@@ -1150,6 +1349,25 @@ public function testInvalidateMissingIdentifierFieldName()
11501349
}
11511350

11521351
public function testUninitializedValueThrowException()
1352+
{
1353+
$this->expectExceptionMessage('Typed property Symfony\Bridge\Doctrine\Tests\Fixtures\Dto::$foo must not be accessed before initialization');
1354+
$constraint = new UniqueEntity(
1355+
message: 'myMessage',
1356+
fields: ['foo' => 'name'],
1357+
em: self::EM_NAME,
1358+
entityClass: DoubleNameEntity::class,
1359+
);
1360+
1361+
$entity = new DoubleNameEntity(1, 'Foo', 'Bar');
1362+
$dto = new Dto();
1363+
1364+
$this->em->persist($entity);
1365+
$this->em->flush();
1366+
1367+
$this->validator->validate($dto, $constraint);
1368+
}
1369+
1370+
public function testUninitializedValueThrowExceptionDoctrineStyle()
11531371
{
11541372
$this->expectExceptionMessage('Typed property Symfony\Bridge\Doctrine\Tests\Fixtures\Dto::$foo must not be accessed before initialization');
11551373
$constraint = new UniqueEntity([
@@ -1169,6 +1387,27 @@ public function testUninitializedValueThrowException()
11691387
}
11701388

11711389
public function testEntityManagerNullObjectWhenDTO()
1390+
{
1391+
$this->expectException(ConstraintDefinitionException::class);
1392+
$this->expectExceptionMessage('Unable to find the object manager associated with an entity of class "Symfony\Bridge\Doctrine\Tests\Fixtures\Person"');
1393+
$constraint = new UniqueEntity(
1394+
message: 'myMessage',
1395+
fields: ['name'],
1396+
entityClass: Person::class,
1397+
// no "em" option set
1398+
);
1399+
1400+
$this->em = null;
1401+
$this->registry = $this->createRegistryMock($this->em);
1402+
$this->validator = $this->createValidator();
1403+
$this->validator->initialize($this->context);
1404+
1405+
$dto = new HireAnEmployee('Foo');
1406+
1407+
$this->validator->validate($dto, $constraint);
1408+
}
1409+
1410+
public function testEntityManagerNullObjectWhenDTODoctrineStyle()
11721411
{
11731412
$this->expectException(ConstraintDefinitionException::class);
11741413
$this->expectExceptionMessage('Unable to find the object manager associated with an entity of class "Symfony\Bridge\Doctrine\Tests\Fixtures\Person"');

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,9 @@ public function __construct(
6060
$payload = null,
6161
array $options = [],
6262
) {
63-
if (\is_array($fields) && \is_string(key($fields))) {
63+
if (\is_array($fields) && \is_string(key($fields)) && [] === array_diff(array_keys($fields), array_keys(get_class_vars(static::class)))) {
6464
$options = array_merge($fields, $options);
65-
} elseif (null !== $fields) {
65+
} else {
6666
$options['fields'] = $fields;
6767
}
6868

0 commit comments

Comments
 (0)