77use TypeLang \Mapper \Runtime \Context \LocalContext ;
88use TypeLang \Mapper \Runtime \Path \PathInterface ;
99use TypeLang \Parser \Node \Stmt \TypeStatement ;
10+ use TypeLang \Parser \Traverser ;
11+ use TypeLang \Parser \Traverser \TypeMapVisitor ;
1012
1113class InvalidFieldTypeValueException extends RuntimeException implements
1214 FieldExceptionInterface,
@@ -15,7 +17,9 @@ class InvalidFieldTypeValueException extends RuntimeException implements
1517{
1618 use FieldProvider;
1719 use ValueProvider;
18- use TypeProvider;
20+ use TypeProvider {
21+ TypeProvider::explain as private explainExpectedType;
22+ }
1923
2024 /**
2125 * @var int
@@ -34,6 +38,7 @@ public function __construct(
3438 protected readonly string $ field ,
3539 protected readonly mixed $ value ,
3640 protected readonly TypeStatement $ expected ,
41+ protected readonly TypeStatement $ object ,
3742 PathInterface $ path ,
3843 string $ template ,
3944 int $ code = 0 ,
@@ -54,28 +59,17 @@ public static function createFromPath(
5459 string $ field ,
5560 mixed $ value ,
5661 TypeStatement $ expected ,
62+ TypeStatement $ object ,
5763 PathInterface $ path ,
5864 ?\Throwable $ previous = null
5965 ): self {
60- $ template = 'Passed value of field {{field}} must be of type {{expected}}, but {{value}} given ' ;
61-
62- if ($ previous instanceof FieldExceptionInterface) {
63- $ field = $ previous ->getField ();
64- $ path = $ previous ->getPath ();
65-
66- if ($ previous instanceof ValueExceptionInterface) {
67- $ value = $ previous ->getValue ();
68- }
69-
70- if ($ previous instanceof MappingExceptionInterface) {
71- $ expected = $ previous ->getExpectedType ();
72- }
73- }
66+ $ template = 'Passed value in {{field}} of {{object}} must be of type {{expected}}, but {{value}} given ' ;
7467
7568 return new self (
7669 field: $ field ,
7770 value: $ value ,
7871 expected: $ expected ,
72+ object: $ object ,
7973 path: $ path ,
8074 template: $ template ,
8175 code: self ::CODE_ERROR_INVALID_VALUE ,
@@ -90,15 +84,29 @@ public static function createFromContext(
9084 string $ field ,
9185 mixed $ value ,
9286 TypeStatement $ expected ,
87+ TypeStatement $ object ,
9388 LocalContext $ context ,
9489 ?\Throwable $ previous = null ,
9590 ): self {
9691 return self ::createFromPath (
9792 field: $ field ,
9893 value: $ value ,
9994 expected: $ expected ,
95+ object: $ object ,
10096 path: clone $ context ->getPath (),
10197 previous: $ previous ,
10298 );
10399 }
100+
101+ public function explain (callable $ transform ): self
102+ {
103+ $ this ->explainExpectedType ($ transform );
104+
105+ Traverser::through (
106+ visitor: new TypeMapVisitor ($ transform (...)),
107+ nodes: [$ this ->object ],
108+ );
109+
110+ return $ this ;
111+ }
104112}
0 commit comments