This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
possible assignment of non-compatible types.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | declare(strict_types=1); |
||
4 | |||
5 | namespace Rinvex\Repository\Traits; |
||
6 | |||
7 | use Closure; |
||
8 | use Illuminate\Support\Arr; |
||
9 | use Rinvex\Repository\Contracts\CriterionContract; |
||
10 | use Rinvex\Repository\Contracts\RepositoryContract; |
||
11 | use Rinvex\Repository\Exceptions\CriterionException; |
||
12 | use Rinvex\Repository\Exceptions\RepositoryException; |
||
13 | |||
14 | trait Criteriable |
||
15 | { |
||
16 | /** |
||
17 | * List of repository criteria. |
||
18 | * |
||
19 | * @var array |
||
20 | */ |
||
21 | protected $criteria = []; |
||
22 | |||
23 | /** |
||
24 | * List of default repository criteria. |
||
25 | * |
||
26 | * @var array |
||
27 | */ |
||
28 | protected $defaultCriteria = []; |
||
29 | |||
30 | /** |
||
31 | * Skip criteria flag. |
||
32 | * If setted to true criteria will not be apply to the query. |
||
33 | * |
||
34 | * @var bool |
||
35 | */ |
||
36 | protected $skipCriteria = false; |
||
37 | |||
38 | /** |
||
39 | * Skip default criteria flag. |
||
40 | * If setted to true default criteria will not be added to the criteria list. |
||
41 | * |
||
42 | * @var bool |
||
43 | */ |
||
44 | protected $skipDefaultCriteria = false; |
||
45 | |||
46 | /** |
||
47 | * Return name for the criterion. |
||
48 | * If as criterion in parameter passed string we assume that is criterion class name. |
||
49 | * |
||
50 | * @param CriterionContract|Closure|string $criteria |
||
51 | * |
||
52 | * @return string |
||
53 | */ |
||
54 | public function getCriterionName($criteria): string |
||
55 | { |
||
56 | if ($criteria instanceof Closure) { |
||
57 | return spl_object_hash($criteria); |
||
58 | } |
||
59 | |||
60 | return is_object($criteria) ? get_class($criteria) : $criteria; |
||
61 | } |
||
62 | |||
63 | /** |
||
64 | * Try to instantiate given criterion class name with this arguments. |
||
65 | * |
||
66 | * @param $class |
||
67 | * @param $arguments |
||
68 | * |
||
69 | * @throws CriterionException |
||
70 | * |
||
71 | * @return mixed |
||
72 | */ |
||
73 | protected function instantiateCriterion($class, $arguments) |
||
74 | { |
||
75 | $reflection = new \ReflectionClass($class); |
||
76 | |||
77 | if (! $reflection->implementsInterface(CriterionContract::class)) { |
||
78 | throw CriterionException::classNotImplementContract($class); |
||
79 | } |
||
80 | |||
81 | // If arguments is an associative array we can assume their order and parameter existence |
||
82 | if (Arr::isAssoc($arguments)) { |
||
83 | $parameters = array_column($reflection->getConstructor()->getParameters(), 'name'); |
||
84 | |||
85 | $arguments = array_filter(array_map(function ($parameter) use ($arguments) { |
||
86 | return $arguments[$parameter] ?? null; |
||
87 | }, $parameters)); |
||
88 | } |
||
89 | |||
90 | return $reflection->newInstanceArgs($arguments); |
||
91 | } |
||
92 | |||
93 | /** |
||
94 | * Return class and arguments from passed array criterion. |
||
95 | * Extracting class and arguments from array. |
||
96 | * |
||
97 | * @param array $criterion |
||
98 | * |
||
99 | * @throws CriterionException |
||
100 | * |
||
101 | * @return array |
||
102 | */ |
||
103 | protected function extractCriterionClassAndArgs(array $criterion): array |
||
104 | { |
||
105 | if (count($criterion) > 2 || empty($criterion)) { |
||
106 | throw CriterionException::wrongArraySignature($criterion); |
||
107 | } |
||
108 | |||
109 | // If an array is assoc we assume that the key is a class and value is an arguments |
||
110 | if (Arr::isAssoc($criterion)) { |
||
111 | $criterion = [array_keys($criterion)[0], array_values($criterion)[0]]; |
||
112 | } elseif (count($criterion) === 1) { |
||
113 | // If an array is not assoc but count is one, we can assume there is a class without arguments. |
||
114 | // Like when a string passed as criterion |
||
115 | array_push($criterion, []); |
||
116 | } |
||
117 | |||
118 | return $criterion; |
||
119 | } |
||
120 | |||
121 | /** |
||
122 | * Add criterion to the specific list. |
||
123 | * low-level implementation of adding criterion to the list. |
||
124 | * |
||
125 | * @param Closure|CriterionContract|array|string $criterion |
||
126 | * @param string $list |
||
127 | * |
||
128 | * @throws CriterionException |
||
129 | * @throws RepositoryException |
||
130 | * |
||
131 | * @return $this |
||
132 | */ |
||
133 | protected function addCriterion($criterion, $list) |
||
134 | { |
||
135 | if (! property_exists($this, $list)) { |
||
136 | throw RepositoryException::listNotFound($list, $this); |
||
137 | } |
||
138 | |||
139 | if (! $criterion instanceof Closure && |
||
140 | ! $criterion instanceof CriterionContract && |
||
141 | ! is_string($criterion) && |
||
142 | ! is_array($criterion) |
||
143 | ) { |
||
144 | throw CriterionException::wrongCriterionType($criterion); |
||
145 | } |
||
146 | |||
147 | //If criterion is a string we will assume it is a class name without arguments |
||
148 | //and we need to normalize signature for instantiation try |
||
149 | if (is_string($criterion)) { |
||
150 | $criterion = [$criterion, []]; |
||
151 | } |
||
152 | |||
153 | //If the criterion is an array we will assume it is an array of class name with arguments |
||
154 | //and try to instantiate this |
||
155 | if (is_array($criterion)) { |
||
156 | $criterion = call_user_func_array([$this, 'instantiateCriterion'], $this->extractCriterionClassAndArgs($criterion)); |
||
157 | } |
||
158 | |||
159 | $this->{$list}[$this->getCriterionName($criterion)] = $criterion; |
||
160 | |||
161 | return $this; |
||
162 | } |
||
163 | |||
164 | /** |
||
165 | * Add criteria to the specific list |
||
166 | * low-level implementation of adding criteria to the list. |
||
167 | * |
||
168 | * @param array $criteria |
||
169 | * @param $list |
||
170 | */ |
||
171 | protected function addCriteria(array $criteria, $list) |
||
172 | { |
||
173 | array_walk($criteria, function ($value, $key) use ($list) { |
||
174 | $criterion = is_string($key) ? [$key, $value] : $value; |
||
175 | $this->addCriterion($criterion, $list); |
||
176 | }); |
||
177 | } |
||
178 | |||
179 | /** |
||
180 | * Push criterion to the criteria list. |
||
181 | * |
||
182 | * @param CriterionContract|Closure|array|string $criterion |
||
183 | * |
||
184 | * @return $this |
||
185 | */ |
||
186 | public function pushCriterion($criterion) |
||
187 | { |
||
188 | $this->addCriterion($criterion, 'criteria'); |
||
189 | |||
190 | return $this; |
||
191 | } |
||
192 | |||
193 | /** |
||
194 | * Remove provided criterion from criteria list. |
||
195 | * |
||
196 | * @param CriterionContract|Closure|string $criterion |
||
197 | * |
||
198 | * @return $this |
||
199 | */ |
||
200 | public function removeCriterion($criterion) |
||
201 | { |
||
202 | unset($this->criteria[$this->getCriterionName($criterion)]); |
||
203 | |||
204 | return $this; |
||
205 | } |
||
206 | |||
207 | /** |
||
208 | * Remove provided criteria from criteria list. |
||
209 | * |
||
210 | * @param array $criteria |
||
211 | * |
||
212 | * @return RepositoryContract |
||
213 | */ |
||
214 | public function removeCriteria(array $criteria) |
||
215 | { |
||
216 | array_walk($criteria, function ($criterion) { |
||
217 | $this->removeCriterion($criterion); |
||
218 | }); |
||
219 | |||
220 | return $this; |
||
221 | } |
||
222 | |||
223 | /** |
||
224 | * Push array of criteria to the criteria list. |
||
225 | * |
||
226 | * @param array $criteria |
||
227 | * |
||
228 | * @return $this |
||
229 | */ |
||
230 | public function pushCriteria(array $criteria) |
||
231 | { |
||
232 | $this->addCriteria($criteria, 'criteria'); |
||
233 | |||
234 | return $this; |
||
235 | } |
||
236 | |||
237 | /** |
||
238 | * Flush criteria list. |
||
239 | * We can flush criteria only when they is not skipped. |
||
240 | * |
||
241 | * @return $this |
||
242 | */ |
||
243 | public function flushCriteria() |
||
244 | { |
||
245 | if (! $this->skipCriteria) { |
||
246 | $this->criteria = []; |
||
247 | } |
||
248 | |||
249 | return $this; |
||
250 | } |
||
251 | |||
252 | /** |
||
253 | * Set default criteria list. |
||
254 | * |
||
255 | * @param array $criteria |
||
256 | * |
||
257 | * @return $this |
||
258 | */ |
||
259 | public function setDefaultCriteria(array $criteria) |
||
260 | { |
||
261 | $this->addCriteria($criteria, 'defaultCriteria'); |
||
262 | |||
263 | return $this; |
||
264 | } |
||
265 | |||
266 | /** |
||
267 | * Return default criteria list. |
||
268 | * |
||
269 | * @return array |
||
270 | */ |
||
271 | public function getDefaultCriteria(): array |
||
272 | { |
||
273 | return $this->defaultCriteria; |
||
274 | } |
||
275 | |||
276 | /** |
||
277 | * Return current list of criteria. |
||
278 | * |
||
279 | * @return array |
||
280 | */ |
||
281 | public function getCriteria(): array |
||
282 | { |
||
283 | if ($this->skipCriteria) { |
||
284 | return []; |
||
285 | } |
||
286 | |||
287 | return $this->skipDefaultCriteria ? $this->criteria : array_merge($this->getDefaultCriteria(), $this->criteria); |
||
288 | } |
||
289 | |||
290 | /** |
||
291 | * Set skipCriteria flag. |
||
292 | * |
||
293 | * @param bool|true $flag |
||
294 | * |
||
295 | * @return $this |
||
296 | */ |
||
297 | public function skipCriteria($flag = true) |
||
298 | { |
||
299 | $this->skipCriteria = $flag; |
||
0 ignored issues
–
show
|
|||
300 | |||
301 | return $this; |
||
302 | } |
||
303 | |||
304 | /** |
||
305 | * Set skipDefaultCriteria flag. |
||
306 | * |
||
307 | * @param bool|true $flag |
||
308 | * |
||
309 | * @return $this |
||
310 | */ |
||
311 | public function skipDefaultCriteria($flag = true) |
||
312 | { |
||
313 | $this->skipDefaultCriteria = $flag; |
||
0 ignored issues
–
show
It seems like
$flag can also be of type object<Rinvex\Repository\Traits\true> . However, the property $skipDefaultCriteria is declared as type boolean . Maybe add an additional type check?
Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly. For example, imagine you have a variable Either this assignment is in error or a type check should be added for that assignment. class Id
{
public $id;
public function __construct($id)
{
$this->id = $id;
}
}
class Account
{
/** @var Id $id */
public $id;
}
$account_id = false;
if (starsAreRight()) {
$account_id = new Id(42);
}
$account = new Account();
if ($account instanceof Id)
{
$account->id = $account_id;
}
Loading history...
|
|||
314 | |||
315 | return $this; |
||
316 | } |
||
317 | |||
318 | /** |
||
319 | * Check if a given criterion name now in the criteria list. |
||
320 | * |
||
321 | * @param CriterionContract|Closure|string $criterion |
||
322 | * |
||
323 | * @return bool |
||
324 | */ |
||
325 | public function hasCriterion($criterion): bool |
||
326 | { |
||
327 | return isset($this->getCriteria()[$this->getCriterionName($criterion)]); |
||
328 | } |
||
329 | |||
330 | /** |
||
331 | * Return criterion object or closure from criteria list by name. |
||
332 | * |
||
333 | * @param $criterion |
||
334 | * |
||
335 | * @return CriterionContract|Closure|null |
||
336 | */ |
||
337 | public function getCriterion($criterion) |
||
338 | { |
||
339 | if ($this->hasCriterion($criterion)) { |
||
340 | return $this->getCriteria()[$this->getCriterionName($criterion)]; |
||
341 | } |
||
342 | } |
||
343 | |||
344 | /** |
||
345 | * Apply criteria list to the given query. |
||
346 | * |
||
347 | * @param $query |
||
348 | * @param $repository |
||
349 | * |
||
350 | * @return mixed |
||
351 | */ |
||
352 | public function applyCriteria($query, $repository) |
||
353 | { |
||
354 | foreach ($this->getCriteria() as $criterion) { |
||
355 | if ($criterion instanceof CriterionContract) { |
||
356 | $query = $criterion->apply($query, $repository); |
||
357 | } elseif ($criterion instanceof Closure) { |
||
358 | $query = $criterion($query, $repository); |
||
359 | } |
||
360 | } |
||
361 | |||
362 | return $query; |
||
363 | } |
||
364 | } |
||
365 |
Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.
For example, imagine you have a variable
$accountId
that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to theid
property of an instance of theAccount
class. This class holds a proper account, so the id value must no longer be false.Either this assignment is in error or a type check should be added for that assignment.