| 1 |  |  | <?php | 
            
                                                                                                            
                            
            
                                    
            
            
                | 2 |  |  | declare(strict_types = 1); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 3 |  |  | /** | 
            
                                                                                                            
                            
            
                                    
            
            
                | 4 |  |  |  * /src/Rest/RepositoryHelper.php | 
            
                                                                                                            
                            
            
                                    
            
            
                | 5 |  |  |  * | 
            
                                                                                                            
                            
            
                                    
            
            
                | 6 |  |  |  * @author TLe, Tarmo Leppänen <[email protected]> | 
            
                                                                                                            
                            
            
                                    
            
            
                | 7 |  |  |  */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 8 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 9 |  |  | namespace App\Rest; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 10 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 11 |  |  | use Closure; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 12 |  |  | use Doctrine\ORM\Query\Expr\Composite; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 13 |  |  | use Doctrine\ORM\Query\Expr\Literal; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 14 |  |  | use Doctrine\ORM\QueryBuilder; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 15 |  |  | use InvalidArgumentException; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 16 |  |  | use Ramsey\Uuid\Exception\InvalidUuidStringException; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 17 |  |  | use stdClass; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 18 |  |  | use function array_combine; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 19 |  |  | use function array_key_exists; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 20 |  |  | use function array_map; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 21 |  |  | use function array_walk; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 22 |  |  | use function call_user_func_array; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 23 |  |  | use function count; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 24 |  |  | use function is_array; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 25 |  |  | use function is_numeric; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 26 |  |  | use function str_contains; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 27 |  |  | use function strcmp; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 28 |  |  | use function strtolower; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 29 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 30 |  |  | /** | 
            
                                                                                                            
                            
            
                                    
            
            
                | 31 |  |  |  * Class RepositoryHelper | 
            
                                                                                                            
                            
            
                                    
            
            
                | 32 |  |  |  * | 
            
                                                                                                            
                            
            
                                    
            
            
                | 33 |  |  |  * @package App\Rest | 
            
                                                                                                            
                            
            
                                    
            
            
                | 34 |  |  |  * @author TLe, Tarmo Leppänen <[email protected]> | 
            
                                                                                                            
                            
            
                                    
            
            
                | 35 |  |  |  */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 36 |  |  | class RepositoryHelper | 
            
                                                                                                            
                            
            
                                    
            
            
                | 37 |  |  | { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 38 |  |  |     /** | 
            
                                                                                                            
                            
            
                                    
            
            
                | 39 |  |  |      * Parameter count in current query, this is used to track parameters which | 
            
                                                                                                            
                            
            
                                    
            
            
                | 40 |  |  |      * are bind to current query. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 41 |  |  |      */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 42 |  |  |     public static int $parameterCount = 0; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 43 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 44 |  |  |     /** | 
            
                                                                                                            
                            
            
                                    
            
            
                | 45 |  |  |      * Method to reset current parameter count value | 
            
                                                                                                            
                            
            
                                    
            
            
                | 46 |  |  |      */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 47 | 56 |  |     public static function resetParameterCount(): void | 
            
                                                                                                            
                            
            
                                    
            
            
                | 48 |  |  |     { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 49 | 56 |  |         self::$parameterCount = 0; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 50 | 56 |  |     } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 51 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 52 |  |  |     /** | 
            
                                                                                                            
                            
            
                                    
            
            
                | 53 |  |  |      * Process given criteria which is given by ?where parameter. This is given | 
            
                                                                                                            
                            
            
                                    
            
            
                | 54 |  |  |      * as JSON string, which is converted to assoc array for this process. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 55 |  |  |      * | 
            
                                                                                                            
                            
            
                                    
            
            
                | 56 |  |  |      * Note that this supports by default (without any extra work) just 'eq' | 
            
                                                                                                            
                            
            
                                    
            
            
                | 57 |  |  |      * and 'in' expressions. See example array below: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 58 |  |  |      * | 
            
                                                                                                            
                            
            
                                    
            
            
                | 59 |  |  |      *  [ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 60 |  |  |      *      'u.id' => 3, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 61 |  |  |      *      'u.uid' => 'uid', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 62 |  |  |      *      'u.foo' => [1, 2, 3], | 
            
                                                                                                            
                            
            
                                    
            
            
                | 63 |  |  |      *      'u.bar' => ['foo', 'bar'], | 
            
                                                                                                            
                            
            
                                    
            
            
                | 64 |  |  |      *  ] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 65 |  |  |      * | 
            
                                                                                                            
                            
            
                                    
            
            
                | 66 |  |  |      * And these you can make easily happen within REST controller and simple | 
            
                                                                                                            
                            
            
                                    
            
            
                | 67 |  |  |      * 'where' parameter. See example below: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 68 |  |  |      * | 
            
                                                                                                            
                            
            
                                    
            
            
                | 69 |  |  |      *  ?where={"u.id":3,"u.uid":"uid","u.foo":[1,2,3],"u.bar":["foo","bar"]} | 
            
                                                                                                            
                            
            
                                    
            
            
                | 70 |  |  |      * | 
            
                                                                                                            
                            
            
                                    
            
            
                | 71 |  |  |      * Also note that you can make more complex use case fairly easy, just | 
            
                                                                                                            
                            
            
                                    
            
            
                | 72 |  |  |      * follow instructions below. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 73 |  |  |      * | 
            
                                                                                                            
                            
            
                                    
            
            
                | 74 |  |  |      * If you're trying to make controller specified special criteria with | 
            
                                                                                                            
                            
            
                                    
            
            
                | 75 |  |  |      * projects generic Rest controller, just add 'processCriteria(array &$criteria)' | 
            
                                                                                                            
                            
            
                                    
            
            
                | 76 |  |  |      * method to your own controller and pre-process that criteria in there | 
            
                                                                                                            
                            
            
                                    
            
            
                | 77 |  |  |      * the way you want it to be handled. In other words just modify that basic | 
            
                                                                                                            
                            
            
                                    
            
            
                | 78 |  |  |      * key-value array just as you like it, main goal is to create array that | 
            
                                                                                                            
                            
            
                                    
            
            
                | 79 |  |  |      * is compatible with 'getExpression' method in this class. For greater | 
            
                                                                                                            
                            
            
                                    
            
            
                | 80 |  |  |      * detail just see that method comments. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 81 |  |  |      * | 
            
                                                                                                            
                            
            
                                    
            
            
                | 82 |  |  |      * tl;dr Modify your $criteria parameter in your controller with | 
            
                                                                                                            
                            
            
                                    
            
            
                | 83 |  |  |      * 'processCriteria(array &$criteria)' method. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 84 |  |  |      * | 
            
                                                                                                            
                            
            
                                    
            
            
                | 85 |  |  |      * @see \App\Repository\Traits\RepositoryMethodsTrait::getQueryBuilder() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 86 |  |  |      * | 
            
                                                                                                            
                            
            
                                    
            
            
                | 87 |  |  |      * @param array<int|string, string|array>|null $criteria | 
            
                                                                                                            
                            
            
                                    
            
            
                | 88 |  |  |      * | 
            
                                                                                                            
                            
            
                                    
            
            
                | 89 |  |  |      * @throws InvalidArgumentException | 
            
                                                                                                            
                            
            
                                    
            
            
                | 90 |  |  |      */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 91 |  |  |     public static function processCriteria(QueryBuilder $queryBuilder, ?array $criteria = null): void | 
            
                                                                                                            
                            
            
                                    
            
            
                | 92 | 121 |  |     { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 93 |  |  |         $criteria ??= []; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 94 | 121 |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 95 |  |  |         if (count($criteria) === 0) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 96 | 121 |  |             return; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 97 | 113 |  |         } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 98 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 99 |  |  |         // Initialize condition array | 
            
                                                                                                            
                            
            
                                    
            
            
                | 100 |  |  |         $condition = []; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 101 | 8 |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 102 |  |  |         // Create used condition array | 
            
                                                                                                            
                            
            
                                    
            
            
                | 103 |  |  |         array_walk($criteria, self::getIterator($condition)); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 104 | 8 |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 105 |  |  |         // And attach search term condition to main query | 
            
                                                                                                            
                            
            
                                    
            
            
                | 106 |  |  |         $queryBuilder->andWhere(self::getExpression($queryBuilder, $queryBuilder->expr()->andX(), $condition)); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 107 | 8 |  |     } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 108 | 8 |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 109 |  |  |     /** | 
            
                                                                                                            
                            
            
                                    
            
            
                | 110 |  |  |      * Helper method to process given search terms and create criteria about | 
            
                                                                                                            
                            
            
                                    
            
            
                | 111 |  |  |      * those. Note that each repository has 'searchColumns' property which | 
            
                                                                                                            
                            
            
                                    
            
            
                | 112 |  |  |      * contains the fields where search term will be affected. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 113 |  |  |      * | 
            
                                                                                                            
                            
            
                                    
            
            
                | 114 |  |  |      * @see \App\Repository\Traits\RepositoryMethodsTrait::getQueryBuilder() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 115 |  |  |      * | 
            
                                                                                                            
                            
            
                                    
            
            
                | 116 |  |  |      * @param array<int, string> $columns | 
            
                                                                                                            
                            
            
                                    
            
            
                | 117 |  |  |      * @param array<string, string>|null $terms | 
            
                                                                                                            
                            
            
                                    
            
            
                | 118 |  |  |      * | 
            
                                                                                                            
                            
            
                                    
            
            
                | 119 |  |  |      * @throws InvalidArgumentException | 
            
                                                                                                            
                            
            
                                    
            
            
                | 120 |  |  |      */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 121 |  |  |     public static function processSearchTerms(QueryBuilder $queryBuilder, array $columns, ?array $terms = null): void | 
            
                                                                                                            
                            
            
                                    
            
            
                | 122 | 119 |  |     { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 123 |  |  |         $terms ??= []; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 124 | 119 |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 125 |  |  |         if (count($columns) === 0) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 126 | 119 |  |             return; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 127 | 24 |  |         } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 128 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 129 |  |  |         // Iterate search term sets | 
            
                                                                                                            
                            
            
                                    
            
            
                | 130 |  |  |         foreach ($terms as $operand => $search) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 131 | 95 |  |             $criteria = SearchTerm::getCriteria($columns, $search, $operand); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 132 | 6 |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 133 |  |  |             if ($criteria !== null) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 134 | 6 |  |                 $queryBuilder->andWhere(self::getExpression($queryBuilder, $queryBuilder->expr()->andX(), $criteria)); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 135 | 6 |  |             } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 136 |  |  |         } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 137 |  |  |     } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 138 | 95 |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 139 |  |  |     /** | 
            
                                                                                                            
                            
            
                                    
            
            
                | 140 |  |  |      * Simple process method for order by part of for current query builder. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 141 |  |  |      * | 
            
                                                                                                            
                            
            
                                    
            
            
                | 142 |  |  |      * @param array<string, string>|null $orderBy | 
            
                                                                                                            
                            
            
                                    
            
            
                | 143 |  |  |      */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 144 |  |  |     public static function processOrderBy(QueryBuilder $queryBuilder, ?array $orderBy = null): void | 
            
                                                                                                            
                            
            
                                    
            
            
                | 145 | 119 |  |     { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 146 |  |  |         $orderBy ??= []; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 147 | 119 |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 148 |  |  |         foreach ($orderBy as $column => $order) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 149 | 119 |  |             if (!str_contains($column, '.')) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 150 | 6 |  |                 $column = 'entity.' . $column; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 151 | 3 |  |             } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 152 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 153 |  |  |             $queryBuilder->addOrderBy($column, $order); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 154 | 6 |  |         } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 155 |  |  |     } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 156 | 119 |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 157 |  |  |     /** | 
            
                                                                                                            
                            
            
                                    
            
            
                | 158 |  |  |      * Recursively takes the specified criteria and adds too the expression. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 159 |  |  |      * | 
            
                                                                                                            
                            
            
                                    
            
            
                | 160 |  |  |      * The criteria is defined in an array notation where each item in the list | 
            
                                                                                                            
                            
            
                                    
            
            
                | 161 |  |  |      * represents a comparison <fieldName, operator, value>. The operator maps | 
            
                                                                                                            
                            
            
                                    
            
            
                | 162 |  |  |      * to comparison methods located in ExpressionBuilder. The key in the array | 
            
                                                                                                            
                            
            
                                    
            
            
                | 163 |  |  |      * can be used to identify grouping of comparisons. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 164 |  |  |      * | 
            
                                                                                                            
                            
            
                                    
            
            
                | 165 |  |  |      * Currently supported Doctrine\ORM\Query\Expr methods: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 166 |  |  |      * | 
            
                                                                                                            
                            
            
                                    
            
            
                | 167 |  |  |      * OPERATOR EXAMPLE INPUT ARRAY GENERATED QUERY RESULT NOTES | 
            
                                                                                                            
                            
            
                                    
            
            
                | 168 |  |  |      *  eq ['u.id', 'eq', 123] u.id = ?1 - | 
            
                                                                                                            
                            
            
                                    
            
            
                | 169 |  |  |      *  neq ['u.id', 'neq', 123] u.id <> ?1 - | 
            
                                                                                                            
                            
            
                                    
            
            
                | 170 |  |  |      *  lt ['u.id', 'lt', 123] u.id < ?1 - | 
            
                                                                                                            
                            
            
                                    
            
            
                | 171 |  |  |      *  lte ['u.id', 'lte', 123] u.id <= ?1 - | 
            
                                                                                                            
                            
            
                                    
            
            
                | 172 |  |  |      *  gt ['u.id', 'gt', 123] u.id > ?1 - | 
            
                                                                                                            
                            
            
                                    
            
            
                | 173 |  |  |      *  gte ['u.id', 'gte', 123] u.id >= ?1 - | 
            
                                                                                                            
                            
            
                                    
            
            
                | 174 |  |  |      *  in ['u.id', 'in', [1,2]] u.id IN (1,2) third value may contain n values | 
            
                                                                                                            
                            
            
                                    
            
            
                | 175 |  |  |      *  notIn ['u.id', 'notIn', [1,2]] u.id NOT IN (1,2) third value may contain n values | 
            
                                                                                                            
                            
            
                                    
            
            
                | 176 |  |  |      *  isNull ['u.id', 'isNull', null] u.id IS NULL third value must be set, but not used | 
            
                                                                                                            
                            
            
                                    
            
            
                | 177 |  |  |      *  isNotNull ['u.id', 'isNotNull', null] u.id IS NOT NULL third value must be set, but not used | 
            
                                                                                                            
                            
            
                                    
            
            
                | 178 |  |  |      *  like ['u.id', 'like', 'abc'] u.id LIKE ?1 - | 
            
                                                                                                            
                            
            
                                    
            
            
                | 179 |  |  |      *  notLike ['u.id', 'notLike', 'abc'] u.id NOT LIKE ?1 - | 
            
                                                                                                            
                            
            
                                    
            
            
                | 180 |  |  |      *  between ['u.id', 'between', [1,6]] u.id BETWEEN ?1 AND ?2 third value must contain two values | 
            
                                                                                                            
                            
            
                                    
            
            
                | 181 |  |  |      * | 
            
                                                                                                            
                            
            
                                    
            
            
                | 182 |  |  |      * Also note that you can easily combine 'and' and 'or' queries like | 
            
                                                                                                            
                            
            
                                    
            
            
                | 183 |  |  |      * following examples: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 184 |  |  |      * | 
            
                                                                                                            
                            
            
                                    
            
            
                | 185 |  |  |      * EXAMPLE INPUT ARRAY GENERATED QUERY RESULT | 
            
                                                                                                            
                            
            
                                    
            
            
                | 186 |  |  |      *  [ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 187 |  |  |      *      'and' => [ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 188 |  |  |      *          ['u.firstName', 'eq', 'foo bar'] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 189 |  |  |      *          ['u.lastName', 'neq', 'not this one'] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 190 |  |  |      *      ] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 191 |  |  |      *  ] (u.firstName = ?1 AND u.lastName <> ?2) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 192 |  |  |      *  [ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 193 |  |  |      *      'or' => [ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 194 |  |  |      *          ['u.firstName', 'eq', 'foo bar'] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 195 |  |  |      *          ['u.lastName', 'neq', 'not this one'] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 196 |  |  |      *      ] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 197 |  |  |      *  ] (u.firstName = ?1 OR u.lastName <> ?2) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 198 |  |  |      * | 
            
                                                                                                            
                            
            
                                    
            
            
                | 199 |  |  |      * Also note that you can nest these criteria arrays as many levels as you | 
            
                                                                                                            
                            
            
                                    
            
            
                | 200 |  |  |      * need - only the sky is the limit... | 
            
                                                                                                            
                            
            
                                    
            
            
                | 201 |  |  |      * | 
            
                                                                                                            
                            
            
                                    
            
            
                | 202 |  |  |      * @example | 
            
                                                                                                            
                            
            
                                    
            
            
                | 203 |  |  |      *  $criteria = [ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 204 |  |  |      *      'or' => [ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 205 |  |  |      *          ['entity.field1', 'like', '%field1Value%'], | 
            
                                                                                                            
                            
            
                                    
            
            
                | 206 |  |  |      *          ['entity.field2', 'like', '%field2Value%'], | 
            
                                                                                                            
                            
            
                                    
            
            
                | 207 |  |  |      *      ], | 
            
                                                                                                            
                            
            
                                    
            
            
                | 208 |  |  |      *      'and' => [ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 209 |  |  |      *          ['entity.field3', 'eq', 3], | 
            
                                                                                                            
                            
            
                                    
            
            
                | 210 |  |  |      *          ['entity.field4', 'eq', 'four'], | 
            
                                                                                                            
                            
            
                                    
            
            
                | 211 |  |  |      *      ], | 
            
                                                                                                            
                            
            
                                    
            
            
                | 212 |  |  |      *      ['entity.field5', 'neq', 5], | 
            
                                                                                                            
                            
            
                                    
            
            
                | 213 |  |  |      *  ]; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 214 |  |  |      * | 
            
                                                                                                            
                            
            
                                    
            
            
                | 215 |  |  |      * $qb = $this->createQueryBuilder('entity'); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 216 |  |  |      * $qb->where($this->getExpression($qb, $qb->expr()->andX(), $criteria)); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 217 |  |  |      * $query = $qb->getQuery(); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 218 |  |  |      * echo $query->getSQL(); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 219 |  |  |      * | 
            
                                                                                                            
                            
            
                                    
            
            
                | 220 |  |  |      * // Result: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 221 |  |  |      * // SELECT * | 
            
                                                                                                            
                            
            
                                    
            
            
                | 222 |  |  |      * // FROM tableName | 
            
                                                                                                            
                            
            
                                    
            
            
                | 223 |  |  |      * // WHERE ((field1 LIKE '%field1Value%') OR (field2 LIKE '%field2Value%')) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 224 |  |  |      * // AND ((field3 = '3') AND (field4 = 'four')) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 225 |  |  |      * // AND (field5 <> '5') | 
            
                                                                                                            
                            
            
                                    
            
            
                | 226 |  |  |      * | 
            
                                                                                                            
                            
            
                                    
            
            
                | 227 |  |  |      * Also note that you can nest these queries as many times as you wish... | 
            
                                                                                                            
                            
            
                                    
            
            
                | 228 |  |  |      * | 
            
                                                                                                            
                            
            
                                    
            
            
                | 229 |  |  |      * @see https://gist.github.com/jgornick/8671644 | 
            
                                                                                                            
                            
            
                                    
            
            
                | 230 |  |  |      * | 
            
                                                                                                            
                            
            
                                    
            
            
                | 231 |  |  |      * @param array<int|string, string|array> $criteria | 
            
                                                                                                            
                            
            
                                    
            
            
                | 232 |  |  |      * | 
            
                                                                                                            
                            
            
                                    
            
            
                | 233 |  |  |      * @throws InvalidArgumentException | 
            
                                                                                                            
                            
            
                                    
            
            
                | 234 |  |  |      */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 235 |  |  |     public static function getExpression( | 
            
                                                                                                            
                            
            
                                    
            
            
                | 236 | 30 |  |         QueryBuilder $queryBuilder, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 237 |  |  |         Composite $expression, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 238 |  |  |         array $criteria, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 239 |  |  |     ): Composite { | 
                            
                    |  |  |  | 
                                                                                        
                                                                                     | 
            
                                                                                                            
                            
            
                                    
            
            
                | 240 |  |  |         self::processExpression($queryBuilder, $expression, $criteria); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 241 | 30 |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 242 |  |  |         return $expression; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 243 | 30 |  |     } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 244 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 245 |  |  |     /** | 
            
                                                                                                            
                            
            
                                    
            
            
                | 246 |  |  |      * @param array<int|string, string|array> $criteria | 
            
                                                                                                            
                            
            
                                    
            
            
                | 247 |  |  |      * | 
            
                                                                                                            
                            
            
                                    
            
            
                | 248 |  |  |      * @throws InvalidArgumentException | 
            
                                                                                                            
                            
            
                                    
            
            
                | 249 |  |  |      */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 250 |  |  |     private static function processExpression(QueryBuilder $queryBuilder, Composite $expression, array $criteria): void | 
            
                                                                                                            
                            
            
                                    
            
            
                | 251 | 30 |  |     { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 252 |  |  |         $iterator = static function (array $comparison, string $key) use ($queryBuilder, $expression): void { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 253 | 30 |  |             $expressionAnd = ($key === 'and' || array_key_exists('and', $comparison)); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 254 | 29 |  |             $expressionOr = ($key === 'or' || array_key_exists('or', $comparison)); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 255 | 29 |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 256 |  |  |             self::buildExpression($queryBuilder, $expression, $expressionAnd, $expressionOr, $comparison); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 257 | 29 |  |         }; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 258 | 30 |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 259 |  |  |         array_walk($criteria, $iterator); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 260 | 30 |  |     } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 261 | 30 |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 262 |  |  |     /** | 
            
                                                                                                            
                            
            
                                    
            
            
                | 263 |  |  |      * @param array<int|string, string|array> $comparison | 
            
                                                                                                            
                            
            
                                    
            
            
                | 264 |  |  |      * | 
            
                                                                                                            
                            
            
                                    
            
            
                | 265 |  |  |      * @throws InvalidArgumentException | 
            
                                                                                                            
                            
            
                                    
            
            
                | 266 |  |  |      */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 267 |  |  |     private static function buildExpression( | 
            
                                                                                                            
                            
            
                                    
            
            
                | 268 | 29 |  |         QueryBuilder $queryBuilder, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 269 |  |  |         Composite $expression, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 270 |  |  |         bool $expressionAnd, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 271 |  |  |         bool $expressionOr, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 272 |  |  |         array $comparison | 
            
                                                                                                            
                            
            
                                    
            
            
                | 273 |  |  |     ): void { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 274 |  |  |         if ($expressionAnd) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 275 | 29 |  |             $expression->add(self::getExpression($queryBuilder, $queryBuilder->expr()->andX(), $comparison)); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 276 | 10 |  |         } elseif ($expressionOr) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 277 | 29 |  |             $expression->add(self::getExpression($queryBuilder, $queryBuilder->expr()->orX(), $comparison)); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 278 | 8 |  |         } else { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 279 |  |  |             [$comparison, $parameters] = self::determineComparisonAndParameters($queryBuilder, $comparison); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 280 | 29 |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 281 |  |  |             /** @var callable $callable */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 282 |  |  |             $callable = [$queryBuilder->expr(), $comparison->operator]; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 283 | 29 |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 284 |  |  |             // And finally add new expression to main one with specified parameters | 
            
                                                                                                            
                            
            
                                    
            
            
                | 285 |  |  |             $expression->add(call_user_func_array($callable, $parameters)); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 286 | 29 |  |         } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 287 |  |  |     } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 288 | 29 |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 289 |  |  |     /** | 
            
                                                                                                            
                            
            
                                    
            
            
                | 290 |  |  |      * Lambda function to create condition array for 'getExpression' method. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 291 |  |  |      * | 
            
                                                                                                            
                            
            
                                    
            
            
                | 292 |  |  |      * @param string|array<int, string> $value | 
            
                                                                                                            
                            
            
                                    
            
            
                | 293 |  |  |      * | 
            
                                                                                                            
                            
            
                                    
            
            
                | 294 |  |  |      * @return array{0: string, 1: string, 2: string|array} | 
            
                                                                                                            
                            
            
                                    
            
            
                | 295 |  |  |      */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 296 |  |  |     private static function createCriteria(string $column, string | array $value): array | 
            
                                                                                                            
                            
            
                                    
            
            
                | 297 | 4 |  |     { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 298 |  |  |         if (!str_contains($column, '.')) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 299 | 4 |  |             $column = 'entity.' . $column; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 300 | 3 |  |         } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 301 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 302 |  |  |         $operator = is_array($value) ? 'in' : 'eq'; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 303 | 4 |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 304 |  |  |         return [$column, $operator, $value]; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 305 | 4 |  |     } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 306 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 307 |  |  |     /** | 
            
                                                                                                            
                            
            
                                    
            
            
                | 308 |  |  |      * @param array<int|string, string|array> $comparison | 
            
                                                                                                            
                            
            
                                    
            
            
                | 309 |  |  |      * | 
            
                                                                                                            
                            
            
                                    
            
            
                | 310 |  |  |      * @return array<int, mixed> | 
            
                                                                                                            
                            
            
                                    
            
            
                | 311 |  |  |      */ | 
            
                                                                                                            
                                                                
            
                                    
            
            
                | 312 |  |  |     private static function determineComparisonAndParameters(QueryBuilder $queryBuilder, array $comparison): array | 
            
                                                                        
                            
            
                                    
            
            
                | 313 | 29 |  |     { | 
            
                                                                        
                            
            
                                    
            
            
                | 314 |  |  |         $comparisonObject = (object)array_combine(['field', 'operator', 'value'], $comparison); | 
            
                                                                        
                            
            
                                    
            
            
                | 315 | 29 |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 316 |  |  |         // Increase parameter count | 
            
                                                                        
                            
            
                                    
            
            
                | 317 |  |  |         self::$parameterCount++; | 
            
                                                                        
                            
            
                                    
            
            
                | 318 | 29 |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 319 |  |  |         // Initialize used callback parameters | 
            
                                                                        
                            
            
                                    
            
            
                | 320 |  |  |         $parameters = [$comparisonObject->field]; | 
            
                                                                        
                            
            
                                    
            
            
                | 321 | 29 |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 322 |  |  |         $lowercaseOperator = strtolower($comparisonObject->operator); | 
            
                                                                        
                            
            
                                    
            
            
                | 323 | 29 |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 324 |  |  |         if (!($lowercaseOperator === 'isnull' || $lowercaseOperator === 'isnotnull')) { | 
            
                                                                        
                            
            
                                    
            
            
                | 325 | 29 |  |             $parameters = self::getComparisonParameters( | 
            
                                                                        
                            
            
                                    
            
            
                | 326 | 27 |  |                 $queryBuilder, | 
            
                                                                        
                            
            
                                    
            
            
                | 327 | 27 |  |                 $comparisonObject, | 
            
                                                                        
                            
            
                                    
            
            
                | 328 |  |  |                 $lowercaseOperator, | 
            
                                                                        
                            
            
                                    
            
            
                | 329 |  |  |                 $parameters | 
            
                                                                        
                            
            
                                    
            
            
                | 330 |  |  |             ); | 
            
                                                                        
                            
            
                                    
            
            
                | 331 |  |  |         } | 
            
                                                                        
                            
            
                                    
            
            
                | 332 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 333 |  |  |         return [$comparisonObject, $parameters]; | 
            
                                                                        
                            
            
                                    
            
            
                | 334 | 29 |  |     } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 335 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 336 |  |  |     /** | 
            
                                                                                                            
                            
            
                                    
            
            
                | 337 |  |  |      * @param array<int, string> $parameters | 
            
                                                                                                            
                            
            
                                    
            
            
                | 338 |  |  |      * @param array<int, mixed> $value | 
            
                                                                                                            
                            
            
                                    
            
            
                | 339 |  |  |      * | 
            
                                                                                                            
                            
            
                                    
            
            
                | 340 |  |  |      * @return array<int, array<int, Literal>|string> | 
            
                                                                                                            
                            
            
                                    
            
            
                | 341 |  |  |      */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 342 |  |  |     private static function getParameters( | 
            
                                                                                                            
                            
            
                                    
            
            
                | 343 | 3 |  |         QueryBuilder $queryBuilder, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 344 |  |  |         string $lowercaseOperator, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 345 |  |  |         array $parameters, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 346 |  |  |         array $value | 
            
                                                                                                            
                            
            
                                    
            
            
                | 347 |  |  |     ): array { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 348 |  |  |         // Operator is between, so we need to add third parameter for Expr method | 
            
                                                                                                            
                            
            
                                    
            
            
                | 349 |  |  |         if ($lowercaseOperator === 'between') { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 350 | 3 |  |             $parameters[] = '?' . self::$parameterCount; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 351 | 1 |  |             $queryBuilder->setParameter(self::$parameterCount, $value[0], UuidHelper::getType((string)$value[0])); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 352 | 1 |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 353 |  |  |             self::$parameterCount++; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 354 | 1 |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 355 |  |  |             $parameters[] = '?' . self::$parameterCount; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 356 | 1 |  |             $queryBuilder->setParameter(self::$parameterCount, $value[1], UuidHelper::getType((string)$value[1])); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 357 | 1 |  |         } else { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 358 |  |  |             // Otherwise this must be IN or NOT IN expression | 
            
                                                                                                            
                            
            
                                    
            
            
                | 359 |  |  |             try { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 360 |  |  |                 $value = array_map([UuidHelper::class, 'getBytes'], $value); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 361 | 2 |  |             } catch (InvalidUuidStringException $error) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 362 | 2 |  |                 (static fn (InvalidUuidStringException $error): InvalidUuidStringException => $error)($error); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 363 | 2 |  |             } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 364 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 365 |  |  |             $parameters[] = array_map( | 
            
                                                                                                            
                            
            
                                    
            
            
                | 366 | 2 |  |                 static fn (string $value): Literal => $queryBuilder->expr()->literal( | 
            
                                                                                                            
                            
            
                                    
            
            
                | 367 | 2 |  |                     is_numeric($value) ? (int)$value : $value | 
            
                                                                                                            
                            
            
                                    
            
            
                | 368 | 2 |  |                 ), | 
            
                                                                                                            
                            
            
                                    
            
            
                | 369 | 2 |  |                 $value | 
            
                                                                                                            
                            
            
                                    
            
            
                | 370 | 2 |  |             ); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 371 |  |  |         } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 372 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 373 |  |  |         return $parameters; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 374 | 3 |  |     } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 375 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 376 |  |  |     /** | 
            
                                                                                                            
                            
            
                                    
            
            
                | 377 |  |  |      * @param array<int|string, string|array> $condition | 
            
                                                                                                            
                            
            
                                    
            
            
                | 378 |  |  |      */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 379 |  |  |     private static function getIterator(array &$condition): Closure | 
            
                                                                                                            
                            
            
                                    
            
            
                | 380 |  |  |     { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 381 |  |  |         return static function (string | array $value, string $column) use (&$condition): void { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 382 | 8 |  |             // If criteria contains 'and' OR 'or' key(s) assume that array in only in the right format | 
            
                                                                                                            
                            
            
                                    
            
            
                | 383 |  |  |             if (strcmp($column, 'and') === 0 || strcmp($column, 'or') === 0) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 384 | 8 |  |                 $condition[$column] = $value; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 385 |  |  |             } else { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 386 | 8 |  |                 // Add condition | 
            
                                                                                                            
                            
            
                                    
            
            
                | 387 | 4 |  |                 $condition[] = self::createCriteria($column, $value); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 388 |  |  |             } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 389 |  |  |         }; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 390 | 4 |  |     } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 391 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 392 | 8 |  |     /** | 
            
                                                                                                            
                            
            
                                    
            
            
                | 393 |  |  |      * @param array<int, string> $parameters | 
            
                                                                                                            
                            
            
                                    
            
            
                | 394 |  |  |      * | 
            
                                                                                                            
                            
            
                                    
            
            
                | 395 |  |  |      * @return array<int, array<int, Literal>|string> | 
            
                                                                                                            
                            
            
                                    
            
            
                | 396 |  |  |      */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 397 |  |  |     private static function getComparisonParameters( | 
            
                                                                                                            
                            
            
                                    
            
            
                | 398 |  |  |         QueryBuilder $queryBuilder, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 399 |  |  |         stdClass $comparison, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 400 | 27 |  |         string $lowercaseOperator, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 401 |  |  |         array $parameters | 
            
                                                                                                            
                            
            
                                    
            
            
                | 402 |  |  |     ): array { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 403 |  |  |         if (is_array($comparison->value)) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 404 |  |  |             $value = $comparison->value; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 405 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 406 | 27 |  |             $parameters = self::getParameters($queryBuilder, $lowercaseOperator, $parameters, $value); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 407 | 3 |  |         } else { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 408 |  |  |             $parameters[] = '?' . self::$parameterCount; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 409 | 3 |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 410 |  |  |             $queryBuilder->setParameter( | 
            
                                                                                                            
                            
            
                                    
            
            
                | 411 | 24 |  |                 self::$parameterCount, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 412 |  |  |                 $comparison->value, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 413 | 24 |  |                 UuidHelper::getType((string)$comparison->value) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 414 | 24 |  |             ); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 415 | 24 |  |         } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 416 | 24 |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 417 |  |  |         return $parameters; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 418 |  |  |     } | 
            
                                                                                                            
                                                                
            
                                    
            
            
                | 419 |  |  | } | 
            
                                                        
            
                                    
            
            
                | 420 |  |  |  |