1010 *
1111 * This class is responsible for building complex database query specifications,
1212 * allowing for the combination of predicates using logical operators (AND, OR).
13- *
13+ *
1414 * @author Kamshory
1515 * @package MagicObject\Database
1616 * @link https://github.com/Planetbiru/MagicObject
@@ -47,7 +47,7 @@ class PicoSpecification // NOSONAR
4747 * @var string
4848 */
4949 private $ defaultLogic = self ::LOGIC_AND ;
50-
50+
5151 /**
5252 * Gets an instance of PicoSpecification.
5353 *
@@ -61,13 +61,13 @@ public static function getInstance()
6161 /**
6262 * Creates and returns an instance of the class with an optional PicoPredicate condition.
6363 *
64- * This static method creates a new instance of the class and, if the provided parameters
64+ * This static method creates a new instance of the class and, if the provided parameters
6565 * are set, adds a PicoPredicate condition using the given field and value.
6666 *
67- * @param string|null $field The name of the field to be used in the predicate.
67+ * @param string|null $field The name of the field to be used in the predicate.
6868 * If null, no predicate is added.
69- * @param mixed|null $value The value to compare against the field in the predicate.
70- *
69+ * @param mixed|null $value The value to compare against the field in the predicate.
70+ *
7171 * @return self A new instance of the class with the optionally added predicate.
7272 */
7373 public static function getInstanceOf ($ field = null , $ value = null )
@@ -289,7 +289,7 @@ public function isEmpty()
289289 {
290290 return empty ($ this ->specifications );
291291 }
292-
292+
293293 /**
294294 * Check if the given input is an array.
295295 *
@@ -309,6 +309,10 @@ public static function isArray($array)
309309 */
310310 public static function isValueEmpty ($ value )
311311 {
312+ if ($ value === false )
313+ {
314+ return false ;
315+ }
312316 return !isset ($ value ) || (is_string ($ value ) && empty (trim ($ value )));
313317 }
314318
@@ -373,15 +377,15 @@ private function getWhere($specifications)
373377 }
374378 return $ arr ;
375379 }
376-
380+
377381 /**
378382 * Retrieves the full column name, including any parent field.
379- *
383+ *
380384 * This method returns the column name formatted as "parentField.field" if the parent field is provided; otherwise, it returns just the field name.
381- *
385+ *
382386 * @param string $field The field name of the entity.
383387 * @param string|null $parentField The parent field name, if applicable.
384- *
388+ *
385389 * @return string The full column name, either just the field name or the parent field concatenated with the field.
386390 */
387391 private function getColumnName ($ field , $ parentField )
@@ -438,7 +442,7 @@ private function hasValue($specification)
438442 *
439443 * Supported dynamic method:
440444 *
441- * - `set<FieldName>(value)`:
445+ * - `set<FieldName>(value)`:
442446 * Sets a predicate for the specified field.
443447 * For example, calling `$obj->setAge(30)` would:
444448 * - Extract the field name `age` from the method name.
@@ -549,7 +553,7 @@ public static function fromUserInput($request, $map = null) // NOSONAR
549553 }
550554 return $ specification ;
551555 }
552-
556+
553557 /**
554558 * Validates whether a given filter value and filter object are usable.
555559 *
@@ -583,8 +587,8 @@ public static function toLowerCase($input)
583587 * Adjusts the filter value based on the filter's configuration.
584588 *
585589 * This method ensures that the input value aligns with the filter type.
586- * If the filter does not expect an array but the input is an array,
587- * the first value in the array is selected. If no adjustment is needed,
590+ * If the filter does not expect an array but the input is an array,
591+ * the first value in the array is selected. If no adjustment is needed,
588592 * the input value is returned as-is.
589593 *
590594 * @param mixed $filterValue The raw user input value.
@@ -596,9 +600,70 @@ private static function fixInput($filterValue, $filter)
596600 if (!$ filter ->isArray () && is_array ($ filterValue ) && !empty ($ filterValue )) {
597601 $ filterValue = array_values ($ filterValue )[0 ];
598602 }
603+ if ($ filter ->isArrayBoolean () && is_array ($ filterValue )) {
604+ foreach ($ filterValue as $ key => $ value )
605+ {
606+ // Parameter is array
607+ // Result is array
608+ $ filterValue [$ key ] = self ::fixInputArrayBoolean ($ value );
609+ }
610+ }
611+ else if ($ filter ->isBoolean ()) {
612+ // Parameter is boolean
613+ // Result is boolean
614+ $ filterValue = self ::fixInputBoolean ($ filterValue );
615+ }
616+
599617 return $ filterValue ;
600618 }
601619
620+ /**
621+ * Normalizes boolean values within an array.
622+ *
623+ * This method iterates through the array and converts each element
624+ * into a proper boolean value if possible. If the input is a string,
625+ * it is also normalized into a boolean.
626+ *
627+ * @param array|string $value The array or string containing raw boolean-like values.
628+ * @return array|bool The normalized array of booleans, or a single boolean if input was a string.
629+ */
630+ private static function fixInputArrayBoolean ($ value )
631+ {
632+ if (is_array ($ value )) {
633+ foreach ($ value as $ key => $ val )
634+ {
635+ $ value [$ key ] = self ::fixInputBoolean ($ val );
636+ }
637+ }
638+ else if (is_string ($ value )) {
639+ $ value = self ::fixInputBoolean ($ value );
640+ }
641+ return $ value ;
642+ }
643+
644+ /**
645+ * Converts a raw input into a boolean value.
646+ *
647+ * This method interprets common string representations of boolean values
648+ * such as "true", "false", "yes", "no", "1", and "0". If the input
649+ * matches one of these values, it is converted into a boolean.
650+ * Otherwise, the original value is returned unchanged.
651+ *
652+ * @param mixed $value The raw input value to be normalized.
653+ * @return bool|mixed A boolean value if conversion is possible, otherwise the original input.
654+ */
655+ private static function fixInputBoolean ($ value )
656+ {
657+ if (is_string ($ value )) {
658+ if (strtolower ($ value ) === "true " || strtolower ($ value ) === "yes " || strtolower ($ value ) === "1 " ){
659+ return true ;
660+ } else if (strtolower ($ value ) === "false " || strtolower ($ value ) === "no " || strtolower ($ value ) === "0 " ){
661+ return false ;
662+ }
663+ }
664+ return $ value ;
665+ }
666+
602667 /**
603668 * Creates a full text search specification based on keywords.
604669 *
@@ -710,7 +775,7 @@ public function setDefaultLogicOr()
710775 * Checks if a real join table is required based on the specifications.
711776 *
712777 * @return bool true if a join is required, false otherwise.
713- */
778+ */
714779 public function getRequireJoin ()
715780 {
716781 return $ this ->requireJoin ;
0 commit comments