@@ -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" ' );
0 commit comments