@@ -41,48 +41,99 @@ class TypeConstraint extends Constraint
4141 public function check ($ value = null , $ schema = null , $ path = null , $ i = null )
4242 {
4343 $ type = isset ($ schema ->type ) ? $ schema ->type : null ;
44- $ isValid = true ;
44+ $ isValid = false ;
45+ $ wording = array ();
4546
4647 if (is_array ($ type )) {
47- // @TODO refactor
48- $ validatedOneType = false ;
49- $ errors = array ();
50- foreach ($ type as $ tp ) {
51- $ validator = new static ($ this ->checkMode );
52- $ subSchema = new \stdClass ();
53- $ subSchema ->type = $ tp ;
54- $ validator ->check ($ value , $ subSchema , $ path , null );
55- $ error = $ validator ->getErrors ();
56-
57- if (!count ($ error )) {
58- $ validatedOneType = true ;
59- break ;
60- }
61-
62- $ errors = $ error ;
63- }
64-
65- if (!$ validatedOneType ) {
66- $ this ->addErrors ($ errors );
67-
68- return ;
69- }
48+ $ this ->validateTypesArray ($ value , $ type , $ wording , $ isValid , $ path );
7049 } elseif (is_object ($ type )) {
7150 $ this ->checkUndefined ($ value , $ type , $ path );
51+ return ;
7252 } else {
7353 $ isValid = $ this ->validateType ($ value , $ type );
7454 }
7555
7656 if ($ isValid === false ) {
77- if (!isset (self ::$ wording [$ type ])) {
78- throw new StandardUnexpectedValueException (
79- sprintf (
80- "No wording for %s available, expected wordings are: [%s] " ,
81- var_export ($ type , true ),
82- implode (', ' , array_filter (self ::$ wording )))
83- );
57+ if (!is_array ($ type )) {
58+ $ this ->validateTypeNameWording ($ type );
59+ $ wording [] = self ::$ wording [$ type ];
60+ }
61+ $ this ->addError ($ path , ucwords (gettype ($ value )) . " value found, but " .
62+ $ this ->implodeWith ($ wording , ', ' , 'or ' ) . " is required " , 'type ' );
63+ }
64+ }
65+
66+ /**
67+ * Validates the given $value against the array of types in $type. Sets the value
68+ * of $isValid to true, if at least one $type mateches the type of $value or the value
69+ * passed as $isValid is already true.
70+ *
71+ * @param mixed $value Value to validate
72+ * @param array $type TypeConstraints to check agains
73+ * @param array $wording An array of wordings of the valid types of the array $type
74+ * @param boolean $isValid The current validation value
75+ */
76+ protected function validateTypesArray ($ value , array $ type , &$ validTypesWording , &$ isValid ,
77+ $ path ) {
78+ foreach ($ type as $ tp ) {
79+ // $tp can be an object, if it's a schema instead of a simple type, validate it
80+ // with a new type constraint
81+ if (is_object ($ tp )) {
82+ if (!$ isValid ) {
83+ $ validator = new static ($ this ->checkMode );
84+ $ subSchema = new \stdClass ();
85+ $ subSchema ->type = $ tp ;
86+ $ validator ->check ($ value , $ subSchema , $ path , null );
87+ $ error = $ validator ->getErrors ();
88+ $ isValid = !(bool )$ error ;
89+ $ validTypesWording [] = self ::$ wording ['object ' ];
90+ }
91+ } else {
92+ $ this ->validateTypeNameWording ( $ tp );
93+ $ validTypesWording [] = self ::$ wording [$ tp ];
94+ if (!$ isValid ) {
95+ $ isValid = $ this ->validateType ( $ value , $ tp );
96+ }
8497 }
85- $ this ->addError ($ path , ucwords (gettype ($ value )) . " value found, but " . self ::$ wording [$ type ] . " is required " , 'type ' );
98+ }
99+ }
100+
101+ /**
102+ * Implodes the given array like implode() with turned around parameters and with the
103+ * difference, that, if $listEnd isn't false, the last element delimiter is $listEnd instead of
104+ * $delimiter.
105+ *
106+ * @param array $elements The elements to implode
107+ * @param string $delimiter The delimiter to use
108+ * @param bool $listEnd The last delimiter to use (defaults to $delimiter)
109+ * @return string
110+ */
111+ protected function implodeWith (array $ elements , $ delimiter = ', ' , $ listEnd = false ) {
112+ if ($ listEnd === false || !isset ($ elements [1 ])) {
113+ return implode (', ' , $ elements );
114+ }
115+ $ lastElement = array_slice ($ elements , -1 );
116+ $ firsElements = join (', ' , array_slice ($ elements , 0 , -1 ));
117+ $ implodedElements = array_merge (array ($ firsElements ), $ lastElement );
118+ return join (" $ listEnd " , $ implodedElements );
119+ }
120+
121+ /**
122+ * Validates the given $type, if there's an associated self::$wording. If not, throws an
123+ * exception.
124+ *
125+ * @param string $type The type to validate
126+ *
127+ * @throws StandardUnexpectedValueException
128+ */
129+ protected function validateTypeNameWording ( $ type ) {
130+ if (!isset (self ::$ wording [$ type ])) {
131+ throw new StandardUnexpectedValueException (
132+ sprintf (
133+ "No wording for %s available, expected wordings are: [%s] " ,
134+ var_export ($ type , true ),
135+ implode (', ' , array_filter (self ::$ wording )))
136+ );
86137 }
87138 }
88139
@@ -126,7 +177,7 @@ protected function validateType($value, $type)
126177 if ('string ' === $ type ) {
127178 return is_string ($ value );
128179 }
129-
180+
130181 if ('email ' === $ type ) {
131182 return is_string ($ value );
132183 }
0 commit comments