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\System; |
||
4 | |||
5 | use Analogue\ORM\Mappable; |
||
6 | use Analogue\ORM\EntityMap; |
||
7 | use Analogue\ORM\EntityCollection; |
||
8 | use Analogue\ORM\System\Wrappers\Factory; |
||
9 | use Analogue\ORM\Relationships\Relationship; |
||
10 | use Analogue\ORM\Exceptions\MappingException; |
||
11 | |||
12 | /** |
||
13 | * The EntityCache class is responsible for tracking entity's attribute states |
||
14 | * between request. |
||
15 | */ |
||
16 | class EntityCache |
||
17 | { |
||
18 | /** |
||
19 | * Entity's raw attributes/relationships |
||
20 | * |
||
21 | * @var array |
||
22 | */ |
||
23 | protected $cache = []; |
||
24 | |||
25 | /** |
||
26 | * Entity Map for the current Entity Type |
||
27 | * @var \Analogue\ORM\EntityMap |
||
28 | */ |
||
29 | protected $entityMap; |
||
30 | |||
31 | /** |
||
32 | * Wrapper factory |
||
33 | * |
||
34 | * @var \Analogue\ORM\System\Wrappers\Factory |
||
35 | */ |
||
36 | protected $factory; |
||
37 | |||
38 | /** |
||
39 | * Associative array containing list of pivot attributes per relationship |
||
40 | * so we don't have to call relationship method on refresh. |
||
41 | * |
||
42 | * @var array |
||
43 | */ |
||
44 | protected $pivotAttributes = []; |
||
45 | |||
46 | /** |
||
47 | * EntityCache constructor. |
||
48 | * @param EntityMap $entityMap |
||
49 | */ |
||
50 | public function __construct(EntityMap $entityMap) |
||
51 | { |
||
52 | $this->entityMap = $entityMap; |
||
53 | |||
54 | $this->factory = new Factory; |
||
55 | } |
||
56 | |||
57 | /** |
||
58 | * Add an array of key=>attributes representing |
||
59 | * the initial state of loaded entities. |
||
60 | * |
||
61 | * @param array $entities |
||
62 | */ |
||
63 | public function add(array $entities) |
||
64 | { |
||
65 | if (count($this->cache) == 0) { |
||
66 | $this->cache = $entities; |
||
67 | } else { |
||
68 | $this->mergeCacheResults($entities); |
||
69 | } |
||
70 | } |
||
71 | |||
72 | /** |
||
73 | * Retrieve initial attributes for a single entity |
||
74 | * |
||
75 | * @param string $id |
||
76 | * @return array |
||
77 | */ |
||
78 | public function get($id) |
||
79 | { |
||
80 | if ($this->has($id)) { |
||
81 | return $this->cache[$id]; |
||
82 | } else { |
||
83 | return []; |
||
84 | } |
||
85 | } |
||
86 | |||
87 | /** |
||
88 | * Check if a record for this id exists. |
||
89 | * |
||
90 | * @param string $id |
||
91 | * @return boolean |
||
92 | */ |
||
93 | public function has($id) |
||
94 | { |
||
95 | return array_key_exists($id, $this->cache); |
||
96 | } |
||
97 | |||
98 | /** |
||
99 | * Combine new result set with existing attributes in |
||
100 | * cache. |
||
101 | * |
||
102 | * @param array $entities |
||
103 | * @return void |
||
104 | */ |
||
105 | protected function mergeCacheResults($entities) |
||
106 | { |
||
107 | foreach ($entities as $key => $entity) { |
||
108 | $this->cache[$key] = $entity; |
||
109 | } |
||
110 | } |
||
111 | |||
112 | /** |
||
113 | * Cache Relation's query result for an entity |
||
114 | * |
||
115 | * @param mixed $parent |
||
116 | * @param string $relation name of the relation |
||
117 | * @param mixed $results results of the relationship's query |
||
118 | * @param Relationship $relationship |
||
119 | * @throws MappingException |
||
120 | * @return void |
||
121 | */ |
||
122 | public function cacheLoadedRelationResult($parent, $relation, $results, Relationship $relationship) |
||
123 | { |
||
124 | $keyName = $this->entityMap->getKeyName(); |
||
125 | |||
126 | if (!$parent instanceof InternallyMappable) { |
||
127 | $parent = $this->factory->make($parent); |
||
128 | } |
||
129 | |||
130 | $key = $parent->getEntityAttribute($keyName); |
||
131 | |||
132 | if ($results instanceof EntityCollection) { |
||
133 | $this->cacheManyRelationResults($key, $relation, $results, $relationship); |
||
134 | } |
||
135 | |||
136 | // POPO : Maybe this check isn't needed, or we have to check for stdClass |
||
137 | // instead |
||
138 | if ($results instanceof Mappable) { |
||
139 | $this->cacheSingleRelationResult($key, $relation, $results, $relationship); |
||
140 | } |
||
141 | } |
||
142 | |||
143 | /** |
||
144 | * Create a cachedRelationship instance which will hold related entity's hash and pivot attributes, if any. |
||
145 | * |
||
146 | * @param string $parentKey |
||
147 | * @param string $relation |
||
148 | * @param array $result |
||
149 | * @param Relationship $relationship |
||
150 | * @throws MappingException |
||
151 | * @return CachedRelationship |
||
152 | */ |
||
153 | protected function getCachedRelationship($parentKey, $relation, $result, Relationship $relationship) |
||
0 ignored issues
–
show
|
|||
154 | { |
||
155 | $pivotColumns = $relationship->getPivotAttributes(); |
||
156 | |||
157 | if (!array_key_exists($relation, $this->pivotAttributes)) { |
||
158 | $this->pivotAttributes[$relation] = $pivotColumns; |
||
159 | } |
||
160 | |||
161 | $wrapper = $this->factory->make($result); |
||
162 | |||
163 | $hash = $this->getEntityHash($wrapper); |
||
164 | |||
165 | if (count($pivotColumns) > 0) { |
||
166 | $pivotAttributes = []; |
||
167 | foreach ($pivotColumns as $column) { |
||
168 | $pivot = $wrapper->getEntityAttribute('pivot'); |
||
169 | |||
170 | $pivotWrapper = $this->factory->make($pivot); |
||
171 | |||
172 | $pivotAttributes[$column] = $pivotWrapper->getEntityAttribute($column); |
||
173 | } |
||
174 | |||
175 | $cachedRelationship = new CachedRelationship($hash, $pivotAttributes); |
||
176 | } else { |
||
177 | $cachedRelationship = new CachedRelationship($hash); |
||
178 | } |
||
179 | |||
180 | return $cachedRelationship; |
||
181 | } |
||
182 | |||
183 | /** |
||
184 | * Cache a many relationship |
||
185 | * |
||
186 | * @param $parentKey |
||
187 | * @param string $relation |
||
188 | * @param EntityCollection $results |
||
189 | * @param Relationship $relationship |
||
190 | * @throws MappingException |
||
191 | */ |
||
192 | protected function cacheManyRelationResults($parentKey, $relation, $results, Relationship $relationship) |
||
193 | { |
||
194 | $this->cache[$parentKey][$relation] = []; |
||
195 | |||
196 | foreach ($results as $result) { |
||
197 | $cachedRelationship = $this->getCachedRelationship($parentKey, $relation, $result, $relationship); |
||
198 | |||
199 | $relatedHash = $cachedRelationship->getHash(); |
||
200 | |||
201 | $this->cache[$parentKey][$relation][$relatedHash] = $cachedRelationship; |
||
202 | } |
||
203 | } |
||
204 | |||
205 | /** |
||
206 | * Cache a single relationship |
||
207 | * |
||
208 | * @param $parentKey |
||
209 | * @param string $relation |
||
210 | * @param Mappable $result |
||
211 | * @param Relationship $relationship |
||
212 | * @throws MappingException |
||
213 | */ |
||
214 | protected function cacheSingleRelationResult($parentKey, $relation, $result, Relationship $relationship) |
||
215 | { |
||
216 | $this->cache[$parentKey][$relation] = $this->getCachedRelationship($parentKey, $relation, $result, $relationship); |
||
0 ignored issues
–
show
$result is of type object<Analogue\ORM\Mappable> , but the function expects a array .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
![]() |
|||
217 | } |
||
218 | |||
219 | /** |
||
220 | * Get Entity's Hash |
||
221 | * |
||
222 | * @param $entity |
||
223 | * @throws MappingException |
||
224 | * @return string |
||
225 | */ |
||
226 | View Code Duplication | protected function getEntityHash(InternallyMappable $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. ![]() |
|||
227 | { |
||
228 | $class = get_class($entity->getObject()); |
||
0 ignored issues
–
show
It seems like you code against a concrete implementation and not the interface
Analogue\ORM\System\InternallyMappable as the method getObject() does only exist in the following implementations of said interface: Analogue\ORM\System\Wrappers\EntityWrapper , Analogue\ORM\System\Wrappers\PlainObjectWrapper , Analogue\ORM\System\Wrappers\Wrapper .
Let’s take a look at an example: interface User
{
/** @return string */
public function getPassword();
}
class MyUser implements User
{
public function getPassword()
{
// return something
}
public function getDisplayName()
{
// return some name.
}
}
class AuthSystem
{
public function authenticate(User $user)
{
$this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
// do something.
}
}
In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break. Available Fixes
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types
inside the if block in such a case.
![]() |
|||
229 | |||
230 | $mapper = Manager::getMapper($class); |
||
231 | |||
232 | $keyName = $mapper->getEntityMap()->getKeyName(); |
||
233 | |||
234 | return $class . '.' . $entity->getEntityAttribute($keyName); |
||
235 | } |
||
236 | |||
237 | /** |
||
238 | * Refresh the cache record for an aggregated entity after a write operation |
||
239 | * @param Aggregate $entity |
||
240 | */ |
||
241 | public function refresh(Aggregate $entity) |
||
242 | { |
||
243 | $this->cache[$entity->getEntityId()] = $this->transform($entity); |
||
244 | } |
||
245 | |||
246 | /** |
||
247 | * Transform an Aggregated Entity into a cache record |
||
248 | * |
||
249 | * @param Aggregate $aggregatedEntity |
||
250 | * @throws MappingException |
||
251 | * @return array |
||
252 | */ |
||
253 | protected function transform(Aggregate $aggregatedEntity) |
||
254 | { |
||
255 | $baseAttributes = $aggregatedEntity->getRawAttributes(); |
||
256 | |||
257 | $relationAttributes = []; |
||
258 | |||
259 | // First we'll handle each relationships that are a one to one |
||
260 | // relation, and which will be saved as a CachedRelationship |
||
261 | // object inside the cache. |
||
262 | |||
263 | // NOTE : storing localRelationships maybe useless has we store |
||
264 | // the foreign key in the attributes already. |
||
265 | |||
266 | foreach ($this->entityMap->getSingleRelationships() as $relation) { |
||
267 | $aggregates = $aggregatedEntity->getRelationship($relation); |
||
268 | |||
269 | if (count($aggregates) == 1) { |
||
270 | $related = $aggregates[0]; |
||
271 | $relationAttributes[$relation] = new CachedRelationship($related->getEntityHash()); |
||
272 | } |
||
273 | if (count($aggregates) > 1) { |
||
274 | throw new MappingException("Single Relationship '$relation' contains several related entities"); |
||
275 | } |
||
276 | } |
||
277 | |||
278 | // Then we'll handle the 'many' relationships and store them as |
||
279 | // an array of CachedRelationship objects. |
||
280 | |||
281 | foreach ($this->entityMap->getManyRelationships() as $relation) { |
||
282 | $aggregates = $aggregatedEntity->getRelationship($relation); |
||
283 | |||
284 | $relationAttributes[$relation] = []; |
||
285 | |||
286 | foreach ($aggregates as $aggregate) { |
||
287 | $relationAttributes[$relation][] = new CachedRelationship( |
||
288 | $aggregate->getEntityHash(), |
||
289 | $aggregate->getPivotAttributes() |
||
290 | ); |
||
291 | } |
||
292 | } |
||
293 | |||
294 | return $baseAttributes + $relationAttributes; |
||
295 | } |
||
296 | |||
297 | /** |
||
298 | * Get pivot attributes for a relation |
||
299 | * |
||
300 | * @param string $relation |
||
301 | * @param InternallyMappable $entity |
||
302 | * @return array |
||
303 | */ |
||
304 | protected function getPivotValues($relation, InternallyMappable $entity) |
||
305 | { |
||
306 | $values = []; |
||
307 | |||
308 | $entityAttributes = $entity->getEntityAttributes(); |
||
309 | |||
310 | if (array_key_exists($relation, $this->pivotAttributes)) { |
||
311 | foreach ($this->pivotAttributes[$relation] as $attribute) { |
||
312 | if (array_key_exists($attribute, $entityAttributes)) { |
||
313 | $values[$attribute] = $entity->getEntityAttribute('pivot')->$attribute; |
||
314 | } |
||
315 | } |
||
316 | } |
||
317 | |||
318 | return $values; |
||
319 | } |
||
320 | |||
321 | /** |
||
322 | * Clear the entity Cache. Use with caution as it could result |
||
323 | * in impredictable behaviour if the cached entities are stored |
||
324 | * after the cache clear operation. |
||
325 | * |
||
326 | * @return void |
||
327 | */ |
||
328 | public function clear() |
||
329 | { |
||
330 | $this->cache = []; |
||
331 | $this->pivotAttributes = []; |
||
332 | } |
||
333 | } |
||
334 |
This check looks from parameters that have been defined for a function or method, but which are not used in the method body.