@@ -61,7 +61,7 @@ public static function getValidValues()
61
61
/**
62
62
* @dataProvider getInvalidValues
63
63
*/
64
- public function testInvalidValues ($ value )
64
+ public function testInvalidValues ($ value, string $ expectedErrorPath )
65
65
{
66
66
$ constraint = new Unique ([
67
67
'message ' => 'myMessage ' ,
@@ -71,6 +71,7 @@ public function testInvalidValues($value)
71
71
$ this ->buildViolation ('myMessage ' )
72
72
->setParameter ('{{ value }} ' , 'array ' )
73
73
->setCode (Unique::IS_NOT_UNIQUE )
74
+ ->atPath ($ expectedErrorPath )
74
75
->assertRaised ();
75
76
}
76
77
@@ -79,12 +80,12 @@ public static function getInvalidValues()
79
80
$ object = new \stdClass ();
80
81
81
82
return [
82
- yield 'not unique booleans ' => [[true , true ]],
83
- yield 'not unique integers ' => [[1 , 2 , 3 , 3 ]],
84
- yield 'not unique floats ' => [[0.1 , 0.2 , 0.1 ]],
85
- yield 'not unique string ' => [['a ' , 'b ' , 'a ' ]],
86
- yield 'not unique arrays ' => [[[1 , 1 ], [2 , 3 ], [1 , 1 ]]],
87
- yield 'not unique objects ' => [[$ object , $ object ]],
83
+ yield 'not unique booleans ' => [[true , true ], ' property.path[1] ' ],
84
+ yield 'not unique integers ' => [[1 , 2 , 3 , 3 ], ' property.path[3] ' ],
85
+ yield 'not unique floats ' => [[0.1 , 0.2 , 0.1 ], ' property.path[2] ' ],
86
+ yield 'not unique string ' => [['a ' , 'b ' , 'a ' ], ' property.path[2] ' ],
87
+ yield 'not unique arrays ' => [[[1 , 1 ], [2 , 3 ], [1 , 1 ]], ' property.path[2] ' ],
88
+ yield 'not unique objects ' => [[$ object , $ object ], ' property.path[1] ' ],
88
89
];
89
90
}
90
91
@@ -96,6 +97,7 @@ public function testInvalidValueNamed()
96
97
$ this ->buildViolation ('myMessage ' )
97
98
->setParameter ('{{ value }} ' , 'array ' )
98
99
->setCode (Unique::IS_NOT_UNIQUE )
100
+ ->atPath ('property.path[3] ' )
99
101
->assertRaised ();
100
102
}
101
103
@@ -152,6 +154,7 @@ public function testExpectsNonUniqueObjects($callback)
152
154
$ this ->buildViolation ('myMessage ' )
153
155
->setParameter ('{{ value }} ' , 'array ' )
154
156
->setCode (Unique::IS_NOT_UNIQUE )
157
+ ->atPath ('property.path[2] ' )
155
158
->assertRaised ();
156
159
}
157
160
@@ -176,6 +179,7 @@ public function testExpectsInvalidNonStrictComparison()
176
179
$ this ->buildViolation ('myMessage ' )
177
180
->setParameter ('{{ value }} ' , 'array ' )
178
181
->setCode (Unique::IS_NOT_UNIQUE )
182
+ ->atPath ('property.path[1] ' )
179
183
->assertRaised ();
180
184
}
181
185
@@ -202,6 +206,7 @@ public function testExpectsInvalidCaseInsensitiveComparison()
202
206
$ this ->buildViolation ('myMessage ' )
203
207
->setParameter ('{{ value }} ' , 'array ' )
204
208
->setCode (Unique::IS_NOT_UNIQUE )
209
+ ->atPath ('property.path[1] ' )
205
210
->assertRaised ();
206
211
}
207
212
@@ -246,7 +251,7 @@ public static function getInvalidFieldNames(): array
246
251
/**
247
252
* @dataProvider getInvalidCollectionValues
248
253
*/
249
- public function testInvalidCollectionValues (array $ value , array $ fields )
254
+ public function testInvalidCollectionValues (array $ value , array $ fields, string $ expectedErrorPath )
250
255
{
251
256
$ this ->validator ->validate ($ value , new Unique ([
252
257
'message ' => 'myMessage ' ,
@@ -255,6 +260,7 @@ public function testInvalidCollectionValues(array $value, array $fields)
255
260
$ this ->buildViolation ('myMessage ' )
256
261
->setParameter ('{{ value }} ' , 'array ' )
257
262
->setCode (Unique::IS_NOT_UNIQUE )
263
+ ->atPath ($ expectedErrorPath )
258
264
->assertRaised ();
259
265
}
260
266
@@ -264,23 +270,25 @@ public static function getInvalidCollectionValues(): array
264
270
'unique string ' => [[
265
271
['lang ' => 'eng ' , 'translation ' => 'hi ' ],
266
272
['lang ' => 'eng ' , 'translation ' => 'hello ' ],
267
- ], ['lang ' ]],
273
+ ], ['lang ' ], ' property.path[1] ' ],
268
274
'unique floats ' => [[
269
275
['latitude ' => 51.509865 , 'longitude ' => -0.118092 , 'poi ' => 'capital ' ],
270
276
['latitude ' => 52.520008 , 'longitude ' => 13.404954 ],
271
277
['latitude ' => 51.509865 , 'longitude ' => -0.118092 ],
272
- ], ['latitude ' , 'longitude ' ]],
278
+ ], ['latitude ' , 'longitude ' ], ' property.path[2] ' ],
273
279
'unique int ' => [[
274
280
['id ' => 1 , 'email ' => 'bar@email.com ' ],
275
281
['id ' => 1 , 'email ' => 'foo@email.com ' ],
276
- ], ['id ' ]],
282
+ ], ['id ' ], ' property.path[1] ' ],
277
283
'unique null ' => [
278
284
[null , null ],
279
285
[],
286
+ 'property.path[1] ' ,
280
287
],
281
288
'unique field null ' => [
282
289
[['nullField ' => null ], ['nullField ' => null ]],
283
290
['nullField ' ],
291
+ 'property.path[1] ' ,
284
292
],
285
293
];
286
294
}
@@ -308,6 +316,90 @@ public function testArrayOfObjectsUnique()
308
316
$ this ->assertNoViolation ();
309
317
}
310
318
319
+ public function testErrorPath ()
320
+ {
321
+ $ array = [
322
+ new DummyClassOne (),
323
+ new DummyClassOne (),
324
+ new DummyClassOne (),
325
+ ];
326
+
327
+ $ array [0 ]->code = 'a1 ' ;
328
+ $ array [1 ]->code = 'a2 ' ;
329
+ $ array [2 ]->code = 'a1 ' ;
330
+
331
+ $ this ->validator ->validate (
332
+ $ array ,
333
+ new Unique (
334
+ normalizer: [self ::class, 'normalizeDummyClassOne ' ],
335
+ fields: 'code ' ,
336
+ errorPath: 'code ' ,
337
+ )
338
+ );
339
+
340
+ $ this ->buildViolation ('This collection should contain only unique elements. ' )
341
+ ->setParameter ('{{ value }} ' , 'array ' )
342
+ ->setCode (Unique::IS_NOT_UNIQUE )
343
+ ->atPath ('property.path[2].code ' )
344
+ ->assertRaised ();
345
+ }
346
+
347
+ public function testErrorPathWithIteratorAggregate ()
348
+ {
349
+ $ array = new \ArrayObject ([
350
+ new DummyClassOne (),
351
+ new DummyClassOne (),
352
+ new DummyClassOne (),
353
+ ]);
354
+
355
+ $ array [0 ]->code = 'a1 ' ;
356
+ $ array [1 ]->code = 'a2 ' ;
357
+ $ array [2 ]->code = 'a1 ' ;
358
+
359
+ $ this ->validator ->validate (
360
+ $ array ,
361
+ new Unique (
362
+ normalizer: [self ::class, 'normalizeDummyClassOne ' ],
363
+ fields: 'code ' ,
364
+ errorPath: 'code ' ,
365
+ )
366
+ );
367
+
368
+ $ this ->buildViolation ('This collection should contain only unique elements. ' )
369
+ ->setParameter ('{{ value }} ' , 'object ' )
370
+ ->setCode (Unique::IS_NOT_UNIQUE )
371
+ ->atPath ('property.path[2].code ' )
372
+ ->assertRaised ();
373
+ }
374
+
375
+ public function testErrorPathWithNonList ()
376
+ {
377
+ $ array = [
378
+ 'a ' => new DummyClassOne (),
379
+ 'b ' => new DummyClassOne (),
380
+ 'c ' => new DummyClassOne (),
381
+ ];
382
+
383
+ $ array ['a ' ]->code = 'a1 ' ;
384
+ $ array ['b ' ]->code = 'a2 ' ;
385
+ $ array ['c ' ]->code = 'a1 ' ;
386
+
387
+ $ this ->validator ->validate (
388
+ $ array ,
389
+ new Unique (
390
+ normalizer: [self ::class, 'normalizeDummyClassOne ' ],
391
+ fields: 'code ' ,
392
+ errorPath: 'code ' ,
393
+ )
394
+ );
395
+
396
+ $ this ->buildViolation ('This collection should contain only unique elements. ' )
397
+ ->setParameter ('{{ value }} ' , 'array ' )
398
+ ->setCode (Unique::IS_NOT_UNIQUE )
399
+ ->atPath ('property.path[c].code ' )
400
+ ->assertRaised ();
401
+ }
402
+
311
403
public static function normalizeDummyClassOne (DummyClassOne $ obj ): array
312
404
{
313
405
return [
0 commit comments