33namespace TraderInteractive ;
44
55use Exception ;
6+ use InvalidArgumentException ;
67use Throwable ;
78use TraderInteractive \Exceptions \FilterException ;
89
@@ -40,6 +41,16 @@ final class Filterer
4041 'url ' => '\\TraderInteractive \\Filter \\Url::filter ' ,
4142 ];
4243
44+ /**
45+ * @var string
46+ */
47+ const RESPONSE_TYPE_ARRAY = 'array ' ;
48+
49+ /**
50+ * @var string
51+ */
52+ const RESPONSE_TYPE_FILTER = FilterResponse::class;
53+
4354 /**
4455 * @var array
4556 */
@@ -105,23 +116,29 @@ final class Filterer
105116 * @param array $options 'allowUnknowns' (default false) true to allow unknowns or false to treat as error,
106117 * 'defaultRequired' (default false) true to make fields required by default and treat as
107118 * error on absence and false to allow their absence by default
119+ * 'responseType' (default RESPONSE_TYPE_ARRAY) Determines the return type, as described
120+ * in the return section.
108121 *
109- * @return array on success [true, $input filtered, null, array of unknown fields]
110- * on error [false, null, 'error message', array of unknown fields]
122+ * @return array|FilterResponse If 'responseType' option is RESPONSE_TYPE_ARRAY:
123+ * on success [true, $input filtered, null, array of unknown fields]
124+ * on error [false, null, 'error message', array of unknown fields]
125+ * If 'responseType' option is RESPONSE_TYPE_FILTER: a FilterResponse instance.
111126 *
112127 * @throws Exception
113- * @throws \InvalidArgumentException if 'allowUnknowns' option was not a bool
114- * @throws \InvalidArgumentException if 'defaultRequired' option was not a bool
115- * @throws \InvalidArgumentException if filters for a field was not a array
116- * @throws \InvalidArgumentException if a filter for a field was not a array
117- * @throws \InvalidArgumentException if 'required' for a field was not a bool
128+ * @throws InvalidArgumentException if 'allowUnknowns' option was not a bool
129+ * @throws InvalidArgumentException if 'defaultRequired' option was not a bool
130+ * @throws InvalidArgumentException if 'responseType' option was not a recognized type
131+ * @throws InvalidArgumentException if filters for a field was not an array
132+ * @throws InvalidArgumentException if a filter for a field was not an array
133+ * @throws InvalidArgumentException if 'required' for a field was not a bool
118134 */
119- public static function filter (array $ spec , array $ input , array $ options = []) : array
135+ public static function filter (array $ spec , array $ input , array $ options = [])
120136 {
121- $ options += ['allowUnknowns ' => false , 'defaultRequired ' => false ];
137+ $ options += ['allowUnknowns ' => false , 'defaultRequired ' => false , ' responseType ' => self :: RESPONSE_TYPE_ARRAY ];
122138
123139 $ allowUnknowns = self ::getAllowUnknowns ($ options );
124140 $ defaultRequired = self ::getDefaultRequired ($ options );
141+ $ responseType = $ options ['responseType ' ];
125142
126143 $ inputToFilter = array_intersect_key ($ input , $ spec );
127144 $ leftOverSpec = array_diff_key ($ spec , $ input );
@@ -171,11 +188,7 @@ public static function filter(array $spec, array $input, array $options = []) :
171188
172189 $ errors = self ::handleAllowUnknowns ($ allowUnknowns , $ leftOverInput , $ errors );
173190
174- if (empty ($ errors )) {
175- return [true , $ inputToFilter , null , $ leftOverInput ];
176- }
177-
178- return [false , null , implode ("\n" , $ errors ), $ leftOverInput ];
191+ return self ::generateFilterResponse ($ responseType , $ inputToFilter , $ errors , $ leftOverInput );
179192 }
180193
181194 /**
@@ -319,7 +332,7 @@ public static function ofArray(array $value, array $spec) : array
319332 private static function assertIfStringOrInt ($ alias )
320333 {
321334 if (!is_string ($ alias ) && !is_int ($ alias )) {
322- throw new \ InvalidArgumentException ('$alias was not a string or int ' );
335+ throw new InvalidArgumentException ('$alias was not a string or int ' );
323336 }
324337 }
325338
@@ -333,7 +346,7 @@ private static function assertIfAliasExists($alias, bool $overwrite)
333346 private static function checkForUnknowns (array $ leftOverInput , array $ errors ) : array
334347 {
335348 foreach ($ leftOverInput as $ field => $ value ) {
336- $ errors [] = "Field ' {$ field }' with value ' " . trim (var_export ($ value , true ), "' " ) . "' is unknown " ;
349+ $ errors [$ field ] = "Field ' {$ field }' with value ' " . trim (var_export ($ value , true ), "' " ) . "' is unknown " ;
337350 }
338351
339352 return $ errors ;
@@ -351,7 +364,7 @@ private static function handleAllowUnknowns(bool $allowUnknowns, array $leftOver
351364 private static function handleRequiredFields (bool $ required , string $ field , array $ errors ) : array
352365 {
353366 if ($ required ) {
354- $ errors [] = "Field ' {$ field }' was required and not present " ;
367+ $ errors [$ field ] = "Field ' {$ field }' was required and not present " ;
355368 }
356369 return $ errors ;
357370 }
@@ -360,7 +373,7 @@ private static function getRequired($filters, $defaultRequired, $field) : bool
360373 {
361374 $ required = isset ($ filters ['required ' ]) ? $ filters ['required ' ] : $ defaultRequired ;
362375 if ($ required !== false && $ required !== true ) {
363- throw new \ InvalidArgumentException ("'required' for field ' {$ field }' was not a bool " );
376+ throw new InvalidArgumentException ("'required' for field ' {$ field }' was not a bool " );
364377 }
365378
366379 return $ required ;
@@ -369,7 +382,7 @@ private static function getRequired($filters, $defaultRequired, $field) : bool
369382 private static function assertFiltersIsAnArray ($ filters , string $ field )
370383 {
371384 if (!is_array ($ filters )) {
372- throw new \ InvalidArgumentException ("filters for field ' {$ field }' was not a array " );
385+ throw new InvalidArgumentException ("filters for field ' {$ field }' was not a array " );
373386 }
374387 }
375388
@@ -389,7 +402,7 @@ private static function handleCustomError(
389402 );
390403 }
391404
392- $ errors [] = str_replace ('{value} ' , trim (var_export ($ value , true ), "' " ), $ error );
405+ $ errors [$ field ] = str_replace ('{value} ' , trim (var_export ($ value , true ), "' " ), $ error );
393406 return $ errors ;
394407 }
395408
@@ -414,7 +427,7 @@ private static function handleFilterAliases($function)
414427 private static function assertFilterIsNotArray ($ filter , string $ field )
415428 {
416429 if (!is_array ($ filter )) {
417- throw new \ InvalidArgumentException ("filter for field ' {$ field }' was not a array " );
430+ throw new InvalidArgumentException ("filter for field ' {$ field }' was not a array " );
418431 }
419432 }
420433
@@ -424,7 +437,7 @@ private static function validateCustomError(array &$filters, string $field)
424437 if (array_key_exists ('error ' , $ filters )) {
425438 $ customError = $ filters ['error ' ];
426439 if (!is_string ($ customError ) || trim ($ customError ) === '' ) {
427- throw new \ InvalidArgumentException ("error for field ' {$ field }' was not a non-empty string " );
440+ throw new InvalidArgumentException ("error for field ' {$ field }' was not a non-empty string " );
428441 }
429442
430443 unset($ filters ['error ' ]);//unset so its not used as a filter
@@ -437,7 +450,7 @@ private static function getAllowUnknowns(array $options) : bool
437450 {
438451 $ allowUnknowns = $ options ['allowUnknowns ' ];
439452 if ($ allowUnknowns !== false && $ allowUnknowns !== true ) {
440- throw new \ InvalidArgumentException ("'allowUnknowns' option was not a bool " );
453+ throw new InvalidArgumentException ("'allowUnknowns' option was not a bool " );
441454 }
442455
443456 return $ allowUnknowns ;
@@ -447,9 +460,43 @@ private static function getDefaultRequired(array $options) : bool
447460 {
448461 $ defaultRequired = $ options ['defaultRequired ' ];
449462 if ($ defaultRequired !== false && $ defaultRequired !== true ) {
450- throw new \ InvalidArgumentException ("'defaultRequired' option was not a bool " );
463+ throw new InvalidArgumentException ("'defaultRequired' option was not a bool " );
451464 }
452465
453466 return $ defaultRequired ;
454467 }
468+
469+ /**
470+ * @param string $responseType The type of object that should be returned.
471+ * @param array $filteredValue The filtered input to return.
472+ * @param array $errors The errors to return.
473+ * @param array $unknowns The unknowns to return.
474+ *
475+ * @return array|FilterResponse
476+ *
477+ * @see filter For more information on how responseType is handled and returns are structured.
478+ */
479+ private static function generateFilterResponse (
480+ string $ responseType ,
481+ array $ filteredValue ,
482+ array $ errors ,
483+ array $ unknowns
484+ ) {
485+ $ filterResponse = new FilterResponse ($ filteredValue , $ errors , $ unknowns );
486+
487+ if ($ responseType === self ::RESPONSE_TYPE_FILTER ) {
488+ return $ filterResponse ;
489+ }
490+
491+ if ($ responseType === self ::RESPONSE_TYPE_ARRAY ) {
492+ return [
493+ $ filterResponse ->success ,
494+ $ filterResponse ->success ? $ filterResponse ->filteredValue : null ,
495+ $ filterResponse ->errorMessage ,
496+ $ filterResponse ->unknowns
497+ ];
498+ }
499+
500+ throw new InvalidArgumentException ("'responseType' was not a recognized value " );
501+ }
455502}
0 commit comments