These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | /* |
||
4 | * This file is part of the API Platform project. |
||
5 | * |
||
6 | * (c) Kévin Dunglas <[email protected]> |
||
7 | * |
||
8 | * For the full copyright and license information, please view the LICENSE |
||
9 | * file that was distributed with this source code. |
||
10 | */ |
||
11 | |||
12 | declare(strict_types=1); |
||
13 | |||
14 | namespace ApiPlatform\Core\Bridge\Doctrine\Orm\Filter; |
||
15 | |||
16 | use ApiPlatform\Core\Bridge\Doctrine\Orm\Util\QueryNameGeneratorInterface; |
||
17 | use ApiPlatform\Core\Exception\InvalidArgumentException; |
||
18 | use Doctrine\ORM\QueryBuilder; |
||
19 | |||
20 | /** |
||
21 | * Filters the collection by range. |
||
22 | * |
||
23 | * @author Lee Siong Chan <[email protected]> |
||
24 | */ |
||
25 | class RangeFilter extends AbstractFilter |
||
26 | { |
||
27 | const PARAMETER_BETWEEN = 'between'; |
||
28 | const PARAMETER_GREATER_THAN = 'gt'; |
||
29 | const PARAMETER_GREATER_THAN_OR_EQUAL = 'gte'; |
||
30 | const PARAMETER_LESS_THAN = 'lt'; |
||
31 | const PARAMETER_LESS_THAN_OR_EQUAL = 'lte'; |
||
32 | |||
33 | /** |
||
34 | * {@inheritdoc} |
||
35 | */ |
||
36 | View Code Duplication | public function getDescription(string $resourceClass): array |
|
0 ignored issues
–
show
|
|||
37 | { |
||
38 | $description = []; |
||
39 | |||
40 | $properties = $this->properties; |
||
41 | if (null === $properties) { |
||
42 | $properties = array_fill_keys($this->getClassMetadata($resourceClass)->getFieldNames(), null); |
||
43 | } |
||
44 | |||
45 | foreach ($properties as $property => $unused) { |
||
46 | if (!$this->isPropertyMapped($property, $resourceClass)) { |
||
47 | continue; |
||
48 | } |
||
49 | |||
50 | $description += $this->getFilterDescription($property, self::PARAMETER_BETWEEN); |
||
51 | $description += $this->getFilterDescription($property, self::PARAMETER_GREATER_THAN); |
||
52 | $description += $this->getFilterDescription($property, self::PARAMETER_GREATER_THAN_OR_EQUAL); |
||
53 | $description += $this->getFilterDescription($property, self::PARAMETER_LESS_THAN); |
||
54 | $description += $this->getFilterDescription($property, self::PARAMETER_LESS_THAN_OR_EQUAL); |
||
55 | } |
||
56 | |||
57 | return $description; |
||
58 | } |
||
59 | |||
60 | /** |
||
61 | * {@inheritdoc} |
||
62 | */ |
||
63 | protected function filterProperty(string $property, $values, QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, string $operationName = null) |
||
64 | { |
||
65 | View Code Duplication | if ( |
|
66 | !is_array($values) || |
||
67 | !$this->isPropertyEnabled($property, $resourceClass) || |
||
68 | !$this->isPropertyMapped($property, $resourceClass) |
||
69 | ) { |
||
70 | return; |
||
71 | } |
||
72 | |||
73 | $alias = 'o'; |
||
74 | $field = $property; |
||
75 | |||
76 | View Code Duplication | if ($this->isPropertyNested($property, $resourceClass)) { |
|
77 | list($alias, $field) = $this->addJoinsForNestedProperty($property, $alias, $queryBuilder, $queryNameGenerator, $resourceClass); |
||
78 | } |
||
79 | |||
80 | foreach ($values as $operator => $value) { |
||
81 | $this->addWhere( |
||
82 | $queryBuilder, |
||
83 | $queryNameGenerator, |
||
84 | $alias, |
||
85 | $field, |
||
86 | $operator, |
||
87 | $value |
||
88 | ); |
||
89 | } |
||
90 | } |
||
91 | |||
92 | /** |
||
93 | * Adds the where clause according to the operator. |
||
94 | * |
||
95 | * @param QueryBuilder $queryBuilder |
||
96 | * @param QueryNameGeneratorInterface $queryNameGenerator |
||
97 | * @param string $alias |
||
98 | * @param string $field |
||
99 | * @param string $operator |
||
100 | * @param string $value |
||
101 | */ |
||
102 | protected function addWhere(QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, $alias, $field, $operator, $value) |
||
103 | { |
||
104 | $valueParameter = $queryNameGenerator->generateParameterName($field); |
||
105 | |||
106 | switch ($operator) { |
||
107 | case self::PARAMETER_BETWEEN: |
||
108 | $rangeValue = explode('..', $value); |
||
109 | |||
110 | if (2 !== count($rangeValue)) { |
||
111 | $this->logger->notice('Invalid filter ignored', [ |
||
112 | 'exception' => new InvalidArgumentException(sprintf('Invalid format for "[%s]", expected "<min>..<max>"', $operator)), |
||
113 | ]); |
||
114 | |||
115 | return; |
||
116 | } |
||
117 | |||
118 | if (!is_numeric($rangeValue[0]) || !is_numeric($rangeValue[1])) { |
||
119 | $this->logger->notice('Invalid filter ignored', [ |
||
120 | 'exception' => new InvalidArgumentException(sprintf('Invalid values for "[%s]" range, expected numbers', $operator)), |
||
121 | ]); |
||
122 | |||
123 | return; |
||
124 | } |
||
125 | |||
126 | $queryBuilder |
||
127 | ->andWhere(sprintf('%1$s.%2$s BETWEEN :%3$s_1 AND :%3$s_2', $alias, $field, $valueParameter)) |
||
128 | ->setParameter(sprintf('%s_1', $valueParameter), $rangeValue[0]) |
||
129 | ->setParameter(sprintf('%s_2', $valueParameter), $rangeValue[1]); |
||
130 | |||
131 | break; |
||
132 | View Code Duplication | case self::PARAMETER_GREATER_THAN: |
|
133 | if (!is_numeric($value)) { |
||
134 | $this->logger->notice('Invalid filter ignored', [ |
||
135 | 'exception' => new InvalidArgumentException(sprintf('Invalid value for "[%s]", expected number', $operator)), |
||
136 | ]); |
||
137 | |||
138 | return; |
||
139 | } |
||
140 | |||
141 | $queryBuilder |
||
142 | ->andWhere(sprintf('%s.%s > :%s', $alias, $field, $valueParameter)) |
||
143 | ->setParameter($valueParameter, $value); |
||
144 | |||
145 | break; |
||
146 | View Code Duplication | case self::PARAMETER_GREATER_THAN_OR_EQUAL: |
|
147 | if (!is_numeric($value)) { |
||
148 | $this->logger->notice('Invalid filter ignored', [ |
||
149 | 'exception' => new InvalidArgumentException(sprintf('Invalid value for "[%s]", expected number', $operator)), |
||
150 | ]); |
||
151 | |||
152 | return; |
||
153 | } |
||
154 | |||
155 | $queryBuilder |
||
156 | ->andWhere(sprintf('%s.%s >= :%s', $alias, $field, $valueParameter)) |
||
157 | ->setParameter($valueParameter, $value); |
||
158 | |||
159 | break; |
||
160 | View Code Duplication | case self::PARAMETER_LESS_THAN: |
|
161 | if (!is_numeric($value)) { |
||
162 | $this->logger->notice('Invalid filter ignored', [ |
||
163 | 'exception' => new InvalidArgumentException(sprintf('Invalid value for "[%s]", expected number', $operator)), |
||
164 | ]); |
||
165 | |||
166 | return; |
||
167 | } |
||
168 | |||
169 | $queryBuilder |
||
170 | ->andWhere(sprintf('%s.%s < :%s', $alias, $field, $valueParameter)) |
||
171 | ->setParameter($valueParameter, $value); |
||
172 | |||
173 | break; |
||
174 | View Code Duplication | case self::PARAMETER_LESS_THAN_OR_EQUAL: |
|
175 | if (!is_numeric($value)) { |
||
176 | $this->logger->notice('Invalid filter ignored', [ |
||
177 | 'exception' => new InvalidArgumentException(sprintf('Invalid value for "[%s]", expected number', $operator)), |
||
178 | ]); |
||
179 | |||
180 | return; |
||
181 | } |
||
182 | |||
183 | $queryBuilder |
||
184 | ->andWhere(sprintf('%s.%s <= :%s', $alias, $field, $valueParameter)) |
||
185 | ->setParameter($valueParameter, $value); |
||
186 | |||
187 | break; |
||
188 | } |
||
189 | } |
||
190 | |||
191 | /** |
||
192 | * Gets filter description. |
||
193 | * |
||
194 | * @param string $fieldName |
||
195 | * @param string $operator |
||
196 | * |
||
197 | * @return array |
||
198 | */ |
||
199 | protected function getFilterDescription(string $fieldName, string $operator): array |
||
200 | { |
||
201 | return [ |
||
202 | sprintf('%s[%s]', $fieldName, $operator) => [ |
||
203 | 'property' => $fieldName, |
||
204 | 'type' => 'string', |
||
205 | 'required' => false, |
||
206 | ], |
||
207 | ]; |
||
208 | } |
||
209 | } |
||
210 |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.