@@ -44,16 +44,24 @@ public function check(&$value = null, $schema = null, JsonPointer $path = null,
4444    {
4545        $ typeisset ($ schematype ) ? $ schematype  : null ;
4646        $ isValidfalse ;
47+         $ coerce$ this factory ->getConfig (self ::CHECK_MODE_COERCE_TYPES );
48+         $ earlyCoerce$ this factory ->getConfig (self ::CHECK_MODE_EARLY_COERCE );
4749        $ wordingarray ();
4850
4951        if  (is_array ($ type
50-             $ this validateTypesArray ($ value$ type$ wording$ isValid$ path
52+             $ this validateTypesArray ($ value$ type$ wording$ isValid$ path$ coerce$ earlyCoerce
53+             if  (!$ isValid$ coerce$ earlyCoerce
54+                 $ this validateTypesArray ($ value$ type$ wording$ isValid$ pathtrue );
55+             }
5156        } elseif  (is_object ($ type
5257            $ this checkUndefined ($ value$ type$ path
5358
5459            return ;
5560        } else  {
56-             $ isValid$ this validateType ($ value$ type
61+             $ isValid$ this validateType ($ value$ type$ coerce$ earlyCoerce
62+             if  (!$ isValid$ coerce$ earlyCoerce
63+                 $ isValid$ this validateType ($ value$ typetrue );
64+             }
5765        }
5866
5967        if  ($ isValidfalse ) {
@@ -62,8 +70,8 @@ public function check(&$value = null, $schema = null, JsonPointer $path = null,
6270                $ wordingself ::$ wording$ type
6371            }
6472            $ this addError (ConstraintError::TYPE (), $ patharray (
65-                     'expected '  => gettype ($ value
66-                     'found '  => $ this implodeWith ($ wording',  ' , 'or ' )
73+                     'found '  => gettype ($ value
74+                     'expected '  => $ this implodeWith ($ wording',  ' , 'or ' )
6775            ));
6876        }
6977    }
@@ -79,9 +87,14 @@ public function check(&$value = null, $schema = null, JsonPointer $path = null,
7987     * @param bool  $isValid           The current validation value 
8088     * @param $path 
8189     */ 
82-     protected  function  validateTypesArray (&$ valuearray  $ type$ validTypesWording$ isValid$ path
90+     protected  function  validateTypesArray (&$ valuearray  $ type$ validTypesWording$ isValid$ path,  $ coerce  =  false )
8391    {
8492        foreach  ($ typeas  $ tp
93+             // already valid, so no need to waste cycles looping over everything 
94+             if  ($ isValid
95+                 return ;
96+             }
97+ 
8598            // $tp can be an object, if it's a schema instead of a simple type, validate it 
8699            // with a new type constraint 
87100            if  (is_object ($ tp
@@ -98,7 +111,7 @@ protected function validateTypesArray(&$value, array $type, &$validTypesWording,
98111                $ this validateTypeNameWording ($ tp
99112                $ validTypesWordingself ::$ wording$ tp
100113                if  (!$ isValid
101-                     $ isValid$ this validateType ($ value$ tp
114+                     $ isValid$ this validateType ($ value$ tp,  $ coerce 
102115                }
103116            }
104117        }
@@ -157,7 +170,7 @@ protected function validateTypeNameWording($type)
157170     * 
158171     * @return bool 
159172     */ 
160-     protected  function  validateType (&$ value$ type
173+     protected  function  validateType (&$ value$ type,  $ coerce  =  false )
161174    {
162175        //mostly the case for inline schema 
163176        if  (!$ type
@@ -173,11 +186,13 @@ protected function validateType(&$value, $type)
173186        }
174187
175188        if  ('array '  === $ type
189+             if  ($ coerce
190+                 $ value$ this toArray ($ value
191+             }
192+ 
176193            return  $ this getTypeCheck ()->isArray ($ value
177194        }
178195
179-         $ coerce$ this factory ->getConfig (Constraint::CHECK_MODE_COERCE_TYPES );
180- 
181196        if  ('integer '  === $ type
182197            if  ($ coerce
183198                $ value$ this toInteger ($ value
@@ -203,10 +218,18 @@ protected function validateType(&$value, $type)
203218        }
204219
205220        if  ('string '  === $ type
221+             if  ($ coerce
222+                 $ value$ this toString ($ value
223+             }
224+ 
206225            return  is_string ($ value
207226        }
208227
209228        if  ('null '  === $ type
229+             if  ($ coerce
230+                 $ value$ this toNull ($ value
231+             }
232+ 
210233            return  is_null ($ value
211234        }
212235
@@ -222,19 +245,21 @@ protected function validateType(&$value, $type)
222245     */ 
223246    protected  function  toBoolean ($ value
224247    {
225-         if  ($ value'true ' ) {
248+         if  ($ value1  ||  $ value  ===  'true ' ) {
226249            return  true ;
227250        }
228- 
229-         if  ($ value'false ' ) {
251+         if  (is_null ($ value$ value0  || $ value'false ' ) {
230252            return  false ;
231253        }
254+         if  ($ this getTypeCheck ()->isArray ($ valuecount ($ value1 ) {
255+             return  $ this toBoolean (reset ($ value
256+         }
232257
233258        return  $ value
234259    }
235260
236261    /** 
237-      * Converts a numeric string  to a number. For example, "4" becomes 4. 
262+      * Converts a value  to a number. For example, "4.5 " becomes 4.5 . 
238263     * 
239264     * @param mixed $value the value to convert to a number 
240265     * 
@@ -245,14 +270,89 @@ protected function toNumber($value)
245270        if  (is_numeric ($ value
246271            return  $ value0 ; // cast to number 
247272        }
273+         if  (is_bool ($ valueis_null ($ value
274+             return  (int ) $ value
275+         }
276+         if  ($ this getTypeCheck ()->isArray ($ valuecount ($ value1 ) {
277+             return  $ this toNumber (reset ($ value
278+         }
248279
249280        return  $ value
250281    }
251282
283+     /** 
284+      * Converts a value to an integer. For example, "4" becomes 4. 
285+      * 
286+      * @param mixed $value 
287+      * 
288+      * @return int|mixed 
289+      */ 
252290    protected  function  toInteger ($ value
253291    {
254-         if  (is_numeric ($ valueint ) $ value$ value
255-             return  (int ) $ value// cast to number 
292+         $ numberValue$ this toNumber ($ value
293+         if  (is_numeric ($ numberValueint ) $ numberValue$ numberValue
294+             return  (int ) $ numberValue// cast to number 
295+         }
296+ 
297+         return  $ value
298+     }
299+ 
300+     /** 
301+      * Converts a value to an array containing that value. For example, [4] becomes 4. 
302+      * 
303+      * @param mixed $value 
304+      * 
305+      * @return array|mixed 
306+      */ 
307+     protected  function  toArray ($ value
308+     {
309+         if  (is_scalar ($ valueis_null ($ value
310+             return  array ($ value
311+         }
312+ 
313+         return  $ value
314+     }
315+ 
316+     /** 
317+      * Convert a value to a string representation of that value. For example, null becomes "". 
318+      * 
319+      * @param mixed $value 
320+      * 
321+      * @return string|mixed 
322+      */ 
323+     protected  function  toString ($ value
324+     {
325+         if  (is_numeric ($ value
326+             return  "$ value ;
327+         }
328+         if  ($ valuetrue ) {
329+             return  'true ' ;
330+         }
331+         if  ($ valuefalse ) {
332+             return  'false ' ;
333+         }
334+         if  (is_null ($ value
335+             return  '' ;
336+         }
337+         if  ($ this getTypeCheck ()->isArray ($ valuecount ($ value1 ) {
338+             return  $ this toString (reset ($ value
339+         }
340+     }
341+ 
342+     /** 
343+      * Convert a value to a null. For example, 0 becomes null. 
344+      * 
345+      * @param mixed $value 
346+      * 
347+      * @return null|mixed 
348+      */ 
349+     protected  function  toNull ($ value
350+     {
351+         if  ($ value0  || $ valuefalse  || $ value'' ) {
352+             return  null ;
353+         }
354+         if  ($ this getTypeCheck ()->isArray ($ valuecount ($ value1 ) {
355+             return  $ this toNull (reset ($ value
256356        }
257357
258358        return  $ value
0 commit comments