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 Analogue\ORM\System\Mapper; |
||
6 | use Analogue\ORM\EntityCollection; |
||
7 | |||
8 | abstract class HasOneOrMany extends Relationship |
||
9 | { |
||
10 | /** |
||
11 | * The foreign key of the parent model. |
||
12 | * |
||
13 | * @var string |
||
14 | */ |
||
15 | protected $foreignKey; |
||
16 | |||
17 | /** |
||
18 | * The local key of the parent model. |
||
19 | * |
||
20 | * @var string |
||
21 | */ |
||
22 | protected $localKey; |
||
23 | |||
24 | /** |
||
25 | * Create a new has many relationship instance. |
||
26 | * |
||
27 | * @param Mapper $mapper |
||
28 | * @param \Analogue\ORM\Mappable $parentEntity |
||
29 | * @param string $foreignKey |
||
30 | * @param string $localKey |
||
31 | */ |
||
32 | public function __construct(Mapper $mapper, $parentEntity, $foreignKey, $localKey) |
||
33 | { |
||
34 | $this->localKey = $localKey; |
||
35 | $this->foreignKey = $foreignKey; |
||
36 | |||
37 | parent::__construct($mapper, $parentEntity); |
||
38 | } |
||
39 | |||
40 | /** |
||
41 | * @param \Analogue\ORM\Entity|EntityCollection $entity |
||
42 | * @return void |
||
43 | */ |
||
44 | public function attachTo($entity) |
||
45 | { |
||
46 | if ($entity instanceof EntityCollection) { |
||
47 | $this->attachMany($entity); |
||
48 | } |
||
49 | $this->attachOne($entity); |
||
0 ignored issues
–
show
|
|||
50 | } |
||
51 | |||
52 | /** |
||
53 | * @param $entityHash |
||
54 | * @return void |
||
55 | */ |
||
56 | public function detachFrom($entityHash) |
||
57 | { |
||
58 | if (is_array($entityHash)) { |
||
59 | $this->detachMany($entityHash); |
||
60 | return; |
||
61 | } |
||
62 | $this->detachMany([$entityHash]); |
||
63 | } |
||
64 | |||
65 | /** |
||
66 | * @param \Analogue\ORM\Entity $entity |
||
67 | */ |
||
68 | public function attachOne($entity) |
||
69 | { |
||
70 | $wrapper = $this->factory->make($entity); |
||
71 | |||
72 | // Ok, we need to guess the inverse of the relation from there. |
||
73 | // Let's assume the inverse of the relation method is the name of |
||
74 | // the entity. |
||
75 | |||
76 | $wrapper->setEntityAttribute($this->getPlainForeignKey(), $this->getParentKey()); |
||
77 | } |
||
78 | |||
79 | /** |
||
80 | * @param EntityCollection $entities |
||
81 | */ |
||
82 | public function attachMany(EntityCollection $entities) |
||
83 | { |
||
84 | foreach ($entities as $entity) { |
||
85 | $this->attachOne($entity); |
||
86 | } |
||
87 | } |
||
88 | |||
89 | /** |
||
90 | * @param $entityHash |
||
91 | */ |
||
92 | protected function detachOne($entityHash) |
||
93 | { |
||
94 | $this->detachMany([$entityHash]); |
||
95 | } |
||
96 | |||
97 | /** |
||
98 | * Attach ids that are passed as arguments, and detach any other |
||
99 | * @param mixed $entities |
||
100 | * @throws \InvalidArgumentException |
||
101 | * @return void |
||
102 | */ |
||
103 | public function sync(array $entities) |
||
104 | { |
||
105 | $this->detachExcept($entities); |
||
106 | } |
||
107 | |||
108 | /** |
||
109 | * @param $entities |
||
110 | * @throws \InvalidArgumentException |
||
111 | */ |
||
112 | protected function detachExcept($entities) |
||
113 | { |
||
114 | $query = $this->query->getQuery()->from($this->relatedMap->getTable()); |
||
115 | |||
116 | if (count($entities) > 0) { |
||
117 | $keys = $this->getKeys($entities); |
||
118 | $query->whereNotIn($this->relatedMap->getKeyName(), $keys); |
||
119 | } |
||
120 | |||
121 | $parentKey = $this->parentMap->getKeyName(); |
||
122 | |||
123 | $query->where($this->getPlainForeignKey(), '=', $this->parent->getEntityAttribute($parentKey)) |
||
124 | ->update([$this->getPlainForeignKey() => null]); |
||
125 | } |
||
126 | |||
127 | /** |
||
128 | * @param array $entityHashes |
||
129 | */ |
||
130 | public function detachMany(array $entityHashes) |
||
131 | { |
||
132 | $keys = []; |
||
133 | |||
134 | foreach ($entityHashes as $hash) { |
||
135 | $split = explode('.', $hash); |
||
136 | $keys[] = $split[1]; |
||
137 | } |
||
138 | |||
139 | $query = $this->query->getQuery()->from($this->relatedMap->getTable()); |
||
140 | |||
141 | $query->whereIn($this->relatedMap->getKeyName(), $keys) |
||
142 | ->update([$this->getPlainForeignKey() => null]); |
||
143 | } |
||
144 | |||
145 | /** |
||
146 | * Set the base constraints on the relation query. |
||
147 | * |
||
148 | * @return void |
||
149 | */ |
||
150 | public function addConstraints() |
||
151 | { |
||
152 | if (static::$constraints) { |
||
153 | $this->query->where($this->foreignKey, '=', $this->getParentKey()); |
||
154 | } |
||
155 | } |
||
156 | |||
157 | /** |
||
158 | * Set the constraints for an eager load of the relation. |
||
159 | * |
||
160 | * @param array $entities |
||
161 | * @return void |
||
162 | */ |
||
163 | public function addEagerConstraints(array $entities) |
||
164 | { |
||
165 | $this->query->whereIn($this->foreignKey, $this->getKeys($entities, $this->localKey)); |
||
0 ignored issues
–
show
The method
whereIn 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 { }
![]() |
|||
166 | } |
||
167 | |||
168 | /** |
||
169 | * Match the eagerly loaded results to their single parents. |
||
170 | * |
||
171 | * @param array $entities |
||
172 | * @param EntityCollection $results |
||
173 | * @param string $relation |
||
174 | * @return array |
||
175 | */ |
||
176 | public function matchOne(array $entities, EntityCollection $results, $relation) |
||
177 | { |
||
178 | return $this->matchOneOrMany($entities, $results, $relation, 'one'); |
||
179 | } |
||
180 | |||
181 | /** |
||
182 | * Match the eagerly loaded results to their many parents. |
||
183 | * |
||
184 | * @param array $entities |
||
185 | * @param EntityCollection $results |
||
186 | * @param string $relation |
||
187 | * @return array |
||
188 | */ |
||
189 | public function matchMany(array $entities, EntityCollection $results, $relation) |
||
190 | { |
||
191 | return $this->matchOneOrMany($entities, $results, $relation, 'many'); |
||
192 | } |
||
193 | |||
194 | /** |
||
195 | * Match the eagerly loaded results to their many parents. |
||
196 | * |
||
197 | * @param array $entities |
||
198 | * @param EntityCollection $results |
||
199 | * @param string $relation |
||
200 | * @param string $type |
||
201 | * @return array |
||
202 | */ |
||
203 | View Code Duplication | protected function matchOneOrMany(array $entities, EntityCollection $results, $relation, $type) |
|
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. ![]() |
|||
204 | { |
||
205 | $dictionary = $this->buildDictionary($results); |
||
206 | |||
207 | $cache = $this->parentMapper->getEntityCache(); |
||
208 | |||
209 | // Once we have the dictionary we can simply spin through the parent models to |
||
210 | // link them up with their children using the keyed dictionary to make the |
||
211 | // matching very convenient and easy work. Then we'll just return them. |
||
212 | foreach ($entities as $entity) { |
||
213 | $entity = $this->factory->make($entity); |
||
214 | |||
215 | $key = $entity->getEntityAttribute($this->localKey); |
||
216 | |||
217 | if (isset($dictionary[$key])) { |
||
218 | $value = $this->getRelationValue($dictionary, $key, $type); |
||
219 | |||
220 | $entity->setEntityAttribute($relation, $value); |
||
221 | |||
222 | $cache->cacheLoadedRelationResult($entity, $relation, $value, $this); |
||
223 | } |
||
224 | } |
||
225 | |||
226 | return $entities; |
||
227 | } |
||
228 | |||
229 | /** |
||
230 | * Get the value of a relationship by one or many type. |
||
231 | * |
||
232 | * @param array $dictionary |
||
233 | * @param string $key |
||
234 | * @param string $type |
||
235 | * @return mixed |
||
236 | */ |
||
237 | protected function getRelationValue(array $dictionary, $key, $type) |
||
238 | { |
||
239 | $value = $dictionary[$key]; |
||
240 | |||
241 | return $type == 'one' ? reset($value) : $this->relatedMap->newCollection($value); |
||
242 | } |
||
243 | |||
244 | /** |
||
245 | * Build model dictionary keyed by the relation's foreign key. |
||
246 | * |
||
247 | * @param EntityCollection $results |
||
248 | * @return array |
||
249 | */ |
||
250 | View Code Duplication | protected function buildDictionary(EntityCollection $results) |
|
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. ![]() |
|||
251 | { |
||
252 | $dictionary = []; |
||
253 | |||
254 | $foreign = $this->getPlainForeignKey(); |
||
255 | |||
256 | // First we will create a dictionary of models keyed by the foreign key of the |
||
257 | // relationship as this will allow us to quickly access all of the related |
||
258 | // models without having to do nested looping which will be quite slow. |
||
259 | foreach ($results as $result) { |
||
260 | $dictionary[$result->{$foreign}][] = $result; |
||
261 | } |
||
262 | |||
263 | return $dictionary; |
||
264 | } |
||
265 | |||
266 | /** |
||
267 | * Get the key for comparing against the parent key in "has" query. |
||
268 | * |
||
269 | * @return string |
||
270 | */ |
||
271 | public function getHasCompareKey() |
||
272 | { |
||
273 | return $this->getForeignKey(); |
||
274 | } |
||
275 | |||
276 | /** |
||
277 | * Get the foreign key for the relationship. |
||
278 | * |
||
279 | * @return string |
||
280 | */ |
||
281 | public function getForeignKey() |
||
282 | { |
||
283 | return $this->foreignKey; |
||
284 | } |
||
285 | |||
286 | /** |
||
287 | * Get the plain foreign key. |
||
288 | * |
||
289 | * @return string |
||
290 | */ |
||
291 | public function getPlainForeignKey() |
||
292 | { |
||
293 | $segments = explode('.', $this->getForeignKey()); |
||
294 | |||
295 | return $segments[count($segments) - 1]; |
||
296 | } |
||
297 | |||
298 | /** |
||
299 | * Get the key value of the parent's local key. |
||
300 | * |
||
301 | * @return mixed |
||
302 | */ |
||
303 | public function getParentKey() |
||
304 | { |
||
305 | return $this->parent->getEntityAttribute($this->localKey); |
||
306 | } |
||
307 | |||
308 | /** |
||
309 | * Get the fully qualified parent key name. |
||
310 | * |
||
311 | * @return string |
||
312 | */ |
||
313 | public function getQualifiedParentKeyName() |
||
314 | { |
||
315 | return $this->parentMap->getTable() . '.' . $this->localKey; |
||
316 | } |
||
317 | |||
318 | /** |
||
319 | * Get the foreign key as value pair for this relation |
||
320 | * |
||
321 | * @return array |
||
322 | */ |
||
323 | public function getForeignKeyValuePair() |
||
324 | { |
||
325 | return [$this->getPlainForeignKey() => $this->getParentKey()]; |
||
326 | } |
||
327 | } |
||
328 |
This check looks at variables that have been passed in as parameters and are passed out again to other methods.
If the outgoing method call has stricter type requirements than the method itself, an issue is raised.
An additional type check may prevent trouble.