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.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | namespace Analogue\ORM\Relationships; |
||
4 | |||
5 | use Closure; |
||
6 | use Carbon\Carbon; |
||
7 | use Analogue\ORM\Mappable; |
||
8 | use Analogue\ORM\System\Query; |
||
9 | use Analogue\ORM\System\Mapper; |
||
10 | use Analogue\ORM\EntityCollection; |
||
11 | use Analogue\ORM\System\InternallyMappable; |
||
12 | use Analogue\ORM\System\Wrappers\Factory; |
||
13 | use Illuminate\Database\Query\Expression; |
||
14 | |||
15 | /** |
||
16 | * Class Relationship |
||
17 | * |
||
18 | * @mixin Query |
||
19 | */ |
||
20 | abstract class Relationship |
||
21 | { |
||
22 | /** |
||
23 | * The mapper instance for the related entity |
||
24 | * |
||
25 | * @var Mapper |
||
26 | */ |
||
27 | protected $relatedMapper; |
||
28 | |||
29 | /** |
||
30 | * The Analogue Query Builder instance. |
||
31 | * |
||
32 | * @var Query |
||
33 | */ |
||
34 | protected $query; |
||
35 | |||
36 | /** |
||
37 | * The parent entity proxy instance. |
||
38 | * |
||
39 | * @var InternallyMappable |
||
40 | */ |
||
41 | protected $parent; |
||
42 | |||
43 | /** |
||
44 | * The parent entity map |
||
45 | * @var \Analogue\ORM\EntityMap |
||
46 | */ |
||
47 | protected $parentMap; |
||
48 | |||
49 | /** |
||
50 | * The Parent Mapper instance |
||
51 | * |
||
52 | * @var Mapper |
||
53 | */ |
||
54 | protected $parentMapper; |
||
55 | |||
56 | /** |
||
57 | * The related entity instance. |
||
58 | * |
||
59 | * @var object |
||
60 | */ |
||
61 | protected $related; |
||
62 | |||
63 | /** |
||
64 | * The related entity Map |
||
65 | * @var \Analogue\ORM\EntityMap |
||
66 | */ |
||
67 | protected $relatedMap; |
||
68 | |||
69 | /** |
||
70 | * Indicate if the parent entity hold the key for the relation. |
||
71 | * |
||
72 | * @var boolean |
||
73 | */ |
||
74 | protected static $ownForeignKey = false; |
||
75 | |||
76 | /** |
||
77 | * Indicate if the relationships use a pivot table.* |
||
78 | * |
||
79 | * @var boolean |
||
80 | */ |
||
81 | protected static $hasPivot = false; |
||
82 | |||
83 | /** |
||
84 | * Indicates if the relation is adding constraints. |
||
85 | * |
||
86 | * @var bool |
||
87 | */ |
||
88 | protected static $constraints = true; |
||
89 | |||
90 | /** |
||
91 | * Wrapper factory |
||
92 | * |
||
93 | * @var \Analogue\ORM\System\Wrappers\Factory |
||
94 | */ |
||
95 | protected $factory; |
||
96 | |||
97 | /** |
||
98 | * Create a new relation instance. |
||
99 | * |
||
100 | * @param Mapper $mapper |
||
101 | * @param Mappable $parent |
||
102 | * @throws \Analogue\ORM\Exceptions\MappingException |
||
103 | */ |
||
104 | public function __construct(Mapper $mapper, $parent) |
||
105 | { |
||
106 | $this->relatedMapper = $mapper; |
||
107 | |||
108 | $this->query = $mapper->getQuery(); |
||
109 | |||
110 | $this->factory = new Factory; |
||
111 | |||
112 | $this->parent = $this->factory->make($parent); |
||
113 | |||
114 | $this->parentMapper = $mapper->getManager()->getMapper($parent); |
||
115 | |||
116 | $this->parentMap = $this->parentMapper->getEntityMap(); |
||
117 | |||
118 | $this->related = $this->query->getEntityInstance(); |
||
119 | |||
120 | $this->relatedMap = $mapper->getEntityMap(); |
||
121 | |||
122 | $this->addConstraints(); |
||
123 | } |
||
124 | |||
125 | /** |
||
126 | * @param $related |
||
127 | * @return mixed |
||
128 | */ |
||
129 | abstract public function attachTo($related); |
||
130 | |||
131 | /** |
||
132 | * @param $related |
||
133 | * @return mixed |
||
134 | */ |
||
135 | abstract public function detachFrom($related); |
||
136 | |||
137 | /** |
||
138 | * Indicate if the parent entity hold the foreign key for relation. |
||
139 | * |
||
140 | * @return boolean |
||
141 | */ |
||
142 | public function ownForeignKey() |
||
143 | { |
||
144 | return static::$ownForeignKey; |
||
145 | } |
||
146 | |||
147 | /** |
||
148 | * Indicate if the relationship uses a pivot table |
||
149 | * |
||
150 | * @return boolean |
||
151 | */ |
||
152 | public function hasPivot() |
||
153 | { |
||
154 | return static::$hasPivot; |
||
155 | } |
||
156 | |||
157 | /** |
||
158 | * Set the base constraints on the relation query. |
||
159 | * |
||
160 | * @return void |
||
161 | */ |
||
162 | abstract public function addConstraints(); |
||
163 | |||
164 | /** |
||
165 | * Set the constraints for an eager load of the relation. |
||
166 | * |
||
167 | * @param array $models |
||
168 | * @return void |
||
169 | */ |
||
170 | abstract public function addEagerConstraints(array $models); |
||
171 | |||
172 | /** |
||
173 | * Initialize the relation on a set of models. |
||
174 | * |
||
175 | * @param array $models |
||
176 | * @param string $relation |
||
177 | * @return array |
||
178 | */ |
||
179 | abstract public function initRelation(array $models, $relation); |
||
180 | |||
181 | /** |
||
182 | * Match the eagerly loaded results to their parents. |
||
183 | * |
||
184 | * @param array $entities |
||
185 | * @param EntityCollection $results |
||
186 | * @param string $relation |
||
187 | * @return array |
||
188 | */ |
||
189 | abstract public function match(array $entities, EntityCollection $results, $relation); |
||
190 | |||
191 | /** |
||
192 | * Get the results of the relationship. |
||
193 | * |
||
194 | * @param string $relation relation name in parent's entity map |
||
195 | * @return mixed |
||
196 | */ |
||
197 | abstract public function getResults($relation); |
||
198 | |||
199 | /** |
||
200 | * Get the relationship for eager loading. |
||
201 | * |
||
202 | * @return EntityCollection |
||
203 | */ |
||
204 | public function getEager() |
||
205 | { |
||
206 | return $this->get(); |
||
0 ignored issues
–
show
|
|||
207 | } |
||
208 | |||
209 | /** |
||
210 | * Add the constraints for a relationship count query. |
||
211 | * |
||
212 | * @param Query $query |
||
213 | * @param Query $parent |
||
214 | * @return Query |
||
215 | */ |
||
216 | public function getRelationCountQuery(Query $query, Query $parent) |
||
217 | { |
||
218 | $query->select(new Expression('count(*)')); |
||
0 ignored issues
–
show
The method
select does not exist on object<Analogue\ORM\System\Query> ? Since you implemented __call , maybe consider adding a @method annotation.
If you implement This is often the case, when class ParentClass {
private $data = array();
public function __call($method, array $args) {
if (0 === strpos($method, 'get')) {
return $this->data[strtolower(substr($method, 3))];
}
throw new \LogicException(sprintf('Unsupported method: %s', $method));
}
}
/**
* If this class knows which fields exist, you can specify the methods here:
*
* @method string getName()
*/
class SomeClass extends ParentClass { }
![]() |
|||
219 | |||
220 | $key = $this->wrap($this->getQualifiedParentKeyName()); |
||
221 | |||
222 | return $query->where($this->getHasCompareKey(), '=', new Expression($key)); |
||
0 ignored issues
–
show
The method
getHasCompareKey does not exist on object<Analogue\ORM\Relationships\Relationship> ? Since you implemented __call , maybe consider adding a @method annotation.
If you implement This is often the case, when class ParentClass {
private $data = array();
public function __call($method, array $args) {
if (0 === strpos($method, 'get')) {
return $this->data[strtolower(substr($method, 3))];
}
throw new \LogicException(sprintf('Unsupported method: %s', $method));
}
}
/**
* If this class knows which fields exist, you can specify the methods here:
*
* @method string getName()
*/
class SomeClass extends ParentClass { }
![]() |
|||
223 | } |
||
224 | |||
225 | /** |
||
226 | * Run a callback with constraints disabled on the relation. |
||
227 | * |
||
228 | * @param Closure $callback |
||
229 | * @return mixed |
||
230 | */ |
||
231 | public static function noConstraints(Closure $callback) |
||
232 | { |
||
233 | static::$constraints = false; |
||
234 | |||
235 | // When resetting the relation where clause, we want to shift the first element |
||
236 | // off of the bindings, leaving only the constraints that the developers put |
||
237 | // as "extra" on the relationships, and not original relation constraints. |
||
238 | $results = call_user_func($callback); |
||
239 | |||
240 | static::$constraints = true; |
||
241 | |||
242 | return $results; |
||
243 | } |
||
244 | |||
245 | /** |
||
246 | * Get all of the primary keys for an array of entities. |
||
247 | * |
||
248 | * @param array $entities |
||
249 | * @param string $key |
||
250 | * @return array |
||
251 | */ |
||
252 | protected function getKeys(array $entities, $key = null) |
||
253 | { |
||
254 | if (is_null($key)) { |
||
255 | $key = $this->relatedMap->getKeyName(); |
||
256 | } |
||
257 | |||
258 | $host = $this; |
||
259 | |||
260 | return array_unique(array_values(array_map(function ($value) use ($key, $host) { |
||
261 | if (!$value instanceof InternallyMappable) { |
||
262 | $value = $host->factory->make($value); |
||
263 | } |
||
264 | |||
265 | return $value->getEntityAttribute($key); |
||
266 | |||
267 | }, $entities))); |
||
268 | } |
||
269 | |||
270 | /** |
||
271 | * Get the underlying query for the relation. |
||
272 | * |
||
273 | * @return Query |
||
274 | */ |
||
275 | public function getQuery() |
||
276 | { |
||
277 | return $this->query; |
||
278 | } |
||
279 | |||
280 | /** |
||
281 | * Get the base query builder |
||
282 | * |
||
283 | * @return \Analogue\ORM\Drivers\QueryAdapter |
||
284 | */ |
||
285 | public function getBaseQuery() |
||
286 | { |
||
287 | return $this->query->getQuery(); |
||
0 ignored issues
–
show
The expression
$this->query->getQuery(); of type Analogue\ORM\Drivers\Que...\IlluminateQueryAdapter adds the type Analogue\ORM\Drivers\IlluminateQueryAdapter to the return on line 287 which is incompatible with the return type documented by Analogue\ORM\Relationshi...ationship::getBaseQuery of type Analogue\ORM\Drivers\QueryAdapter .
![]() |
|||
288 | } |
||
289 | |||
290 | /** |
||
291 | * Get the parent model of the relation. |
||
292 | * |
||
293 | * @return InternallyMappable |
||
294 | */ |
||
295 | public function getParent() |
||
296 | { |
||
297 | return $this->parent; |
||
298 | } |
||
299 | |||
300 | /** |
||
301 | * Get the fully qualified parent key name. |
||
302 | * |
||
303 | * @return string |
||
304 | */ |
||
305 | protected function getQualifiedParentKeyName() |
||
306 | { |
||
307 | return $this->parent->getQualifiedKeyName(); |
||
0 ignored issues
–
show
The method
getQualifiedKeyName() does not seem to exist on object<Analogue\ORM\System\InternallyMappable> .
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces. This is most likely a typographical error or the method has been renamed. ![]() |
|||
308 | } |
||
309 | |||
310 | /** |
||
311 | * Get the related entity of the relation. |
||
312 | * |
||
313 | * @return \Analogue\ORM\Entity |
||
314 | */ |
||
315 | public function getRelated() |
||
316 | { |
||
317 | return $this->related; |
||
318 | } |
||
319 | |||
320 | /** |
||
321 | * Get the related mapper for the relation |
||
322 | * |
||
323 | * @return Mapper |
||
324 | */ |
||
325 | public function getRelatedMapper() |
||
326 | { |
||
327 | return $this->relatedMapper; |
||
328 | } |
||
329 | |||
330 | |||
331 | /** |
||
332 | * Get the name of the "created at" column. |
||
333 | * |
||
334 | * @return string |
||
335 | */ |
||
336 | public function createdAt() |
||
337 | { |
||
338 | return $this->parentMap->getCreatedAtColumn(); |
||
339 | } |
||
340 | |||
341 | /** |
||
342 | * Get the name of the "updated at" column. |
||
343 | * |
||
344 | * @return string |
||
345 | */ |
||
346 | public function updatedAt() |
||
347 | { |
||
348 | return $this->parentMap->getUpdatedAtColumn(); |
||
349 | } |
||
350 | |||
351 | /** |
||
352 | * Get the name of the related model's "updated at" column. |
||
353 | * |
||
354 | * @return string |
||
355 | */ |
||
356 | public function relatedUpdatedAt() |
||
357 | { |
||
358 | return $this->related->getUpdatedAtColumn(); |
||
359 | } |
||
360 | |||
361 | /** |
||
362 | * Wrap the given value with the parent query's grammar. |
||
363 | * |
||
364 | * @param string $value |
||
365 | * @return string |
||
366 | */ |
||
367 | public function wrap($value) |
||
368 | { |
||
369 | return $this->parentMapper->getQuery()->getQuery()->getGrammar()->wrap($value); |
||
370 | } |
||
371 | |||
372 | /** |
||
373 | * Get a fresh timestamp |
||
374 | * |
||
375 | * @return Carbon |
||
376 | */ |
||
377 | protected function freshTimestamp() |
||
378 | { |
||
379 | return new Carbon; |
||
380 | } |
||
381 | |||
382 | /** |
||
383 | * Cache the link between parent and related |
||
384 | * into the mapper's Entity Cache. |
||
385 | * |
||
386 | * @param EntityCollection|Mappable $results result of the relation query |
||
387 | * @param string $relation name of the relation method on the parent entity |
||
388 | * @return void |
||
389 | */ |
||
390 | protected function cacheRelation($results, $relation) |
||
391 | { |
||
392 | $cache = $this->parentMapper->getEntityCache(); |
||
393 | |||
394 | $cache->cacheLoadedRelationResult($this->parent, $relation, $results, $this); |
||
395 | } |
||
396 | |||
397 | /** |
||
398 | * Return Pivot attributes when available on a relationship |
||
399 | * |
||
400 | * @return array |
||
401 | */ |
||
402 | public function getPivotAttributes() |
||
403 | { |
||
404 | return []; |
||
405 | } |
||
406 | |||
407 | /** |
||
408 | * Get a combo type.primaryKey |
||
409 | * |
||
410 | * @param Mappable $entity |
||
411 | * @return string |
||
412 | */ |
||
413 | View Code Duplication | protected function getEntityHash(Mappable $entity) |
|
0 ignored issues
–
show
This method seems to be duplicated in your project.
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. ![]() |
|||
414 | { |
||
415 | $class = get_class($entity); |
||
416 | |||
417 | $keyName = Mapper::getMapper($class)->getEntityMap()->getKeyName(); |
||
0 ignored issues
–
show
The method
getMapper() does not seem to exist on object<Analogue\ORM\System\Mapper> .
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces. This is most likely a typographical error or the method has been renamed. ![]() |
|||
418 | |||
419 | return $class . '.' . $entity->getEntityAttribute($keyName); |
||
0 ignored issues
–
show
The method
getEntityAttribute() does not exist on Analogue\ORM\Mappable . Did you maybe mean getEntityAttributes() ?
This check marks calls to methods that do not seem to exist on an object. This is most likely the result of a method being renamed without all references to it being renamed likewise. ![]() |
|||
420 | } |
||
421 | |||
422 | /** |
||
423 | * Run synchronization content if needed by the |
||
424 | * relation type. |
||
425 | * |
||
426 | * @param array $actualContent |
||
427 | * @return void |
||
428 | */ |
||
429 | abstract public function sync(array $actualContent); |
||
430 | |||
431 | /** |
||
432 | * Handle dynamic method calls to the relationship. |
||
433 | * |
||
434 | * @param string $method |
||
435 | * @param array $parameters |
||
436 | * @return mixed |
||
437 | */ |
||
438 | public function __call($method, $parameters) |
||
439 | { |
||
440 | $result = call_user_func_array([$this->query, $method], $parameters); |
||
441 | |||
442 | if ($result === $this->query) { |
||
443 | return $this; |
||
444 | } |
||
445 | |||
446 | return $result; |
||
447 | } |
||
448 | } |
||
449 |
If you implement
__call
and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.This is often the case, when
__call
is implemented by a parent class and only the child class knows which methods exist: