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 | namespace Fwk\Db\Registry; |
||
3 | |||
4 | use Fwk\Db\Accessor; |
||
5 | use Fwk\Db\Connection; |
||
6 | use Fwk\Db\Events\AbstractEntityEvent; |
||
7 | use Fwk\Db\Events\AfterSaveEvent; |
||
8 | use Fwk\Db\Events\FreshEvent; |
||
9 | use Fwk\Db\EventSubscriberInterface; |
||
10 | use Fwk\Db\Exception; |
||
11 | use Fwk\Db\Exceptions\UnregisteredEntityException; |
||
12 | use Fwk\Db\Table; |
||
13 | use Fwk\Db\Workers\DeleteEntityWorker; |
||
14 | use Fwk\Db\Workers\SaveEntityWorker; |
||
15 | use Fwk\Events\Dispatcher; |
||
16 | use Fwk\Events\Event; |
||
17 | use \SplObjectStorage; |
||
18 | |||
19 | class Registry implements \Countable, \IteratorAggregate |
||
20 | { |
||
21 | const ACTION_SAVE = 'save'; |
||
22 | const ACTION_DELETE = 'delete'; |
||
23 | |||
24 | /** |
||
25 | * Storage handler |
||
26 | * |
||
27 | * @var SplObjectStorage |
||
28 | */ |
||
29 | protected $store; |
||
30 | |||
31 | /** |
||
32 | * Table name |
||
33 | * |
||
34 | * @var string |
||
35 | */ |
||
36 | protected $tableName; |
||
37 | |||
38 | /** |
||
39 | * @var integer |
||
40 | */ |
||
41 | protected $_priority = \PHP_INT_MAX; |
||
0 ignored issues
–
show
|
|||
42 | |||
43 | /** |
||
44 | * Constructor |
||
45 | * |
||
46 | * @param string $tableName |
||
47 | * |
||
48 | * @return void |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
Adding a
@return annotation to constructors is generally not recommended as a constructor does not have a meaningful return value.
Adding a Please refer to the PHP core documentation on constructors. ![]() |
|||
49 | */ |
||
50 | public function __construct($tableName) |
||
51 | { |
||
52 | $this->tableName = $tableName; |
||
53 | $this->store = new SplObjectStorage(); |
||
54 | } |
||
55 | |||
56 | /** |
||
57 | * Stores an object into registry |
||
58 | * |
||
59 | * @param mixed $object |
||
60 | * |
||
61 | * @return Entry |
||
62 | */ |
||
63 | public function store($object, array $identifiers = array(), $state = RegistryState::UNKNOWN, array $data = array()) |
||
64 | { |
||
65 | if ($this->contains($object)) { |
||
66 | return $this; |
||
0 ignored issues
–
show
The return type of
return $this; (Fwk\Db\Registry\Registry ) is incompatible with the return type documented by Fwk\Db\Registry\Registry::store of type Fwk\Db\Registry\Entry .
If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design. Let’s take a look at an example: class Author {
private $name;
public function __construct($name) {
$this->name = $name;
}
public function getName() {
return $this->name;
}
}
abstract class Post {
public function getAuthor() {
return 'Johannes';
}
}
class BlogPost extends Post {
public function getAuthor() {
return new Author('Johannes');
}
}
class ForumPost extends Post { /* ... */ }
function my_function(Post $post) {
echo strtoupper($post->getAuthor());
}
Our function ![]() |
|||
67 | } |
||
68 | |||
69 | $entry = Entry::factory($object, $identifiers, $state, $data); |
||
70 | |||
71 | $dispatcher = $entry->data('dispatcher', new Dispatcher()); |
||
72 | $listeners = $entry->data('listeners', array()); |
||
73 | |||
74 | /** |
||
75 | * @todo Put this one elsewhere |
||
76 | */ |
||
77 | $dispatcher->on(AfterSaveEvent::EVENT_NAME, array($this, 'getLastInsertId')); |
||
78 | |||
79 | $dispatcher->addListener($object); |
||
80 | if ($object instanceof EventSubscriberInterface) { |
||
81 | foreach ($object->getListeners() as $key => $listener) { |
||
82 | if (is_object($listener) && !is_callable($listener)) { |
||
83 | $dispatcher->addListener($listener); |
||
84 | } elseif (is_callable($listener)) { |
||
85 | $dispatcher->on($key, $listener); |
||
86 | } |
||
87 | } |
||
88 | } |
||
89 | |||
90 | foreach ($listeners as $key => $listener) { |
||
91 | if (is_object($listener) && !is_callable($listener)) { |
||
92 | $dispatcher->addListener($listener); |
||
93 | } elseif (is_callable($listener)) { |
||
94 | $dispatcher->on($key, $listener); |
||
95 | } |
||
96 | } |
||
97 | |||
98 | $this->store->attach($entry); |
||
99 | |||
100 | return $entry; |
||
101 | } |
||
102 | |||
103 | /** |
||
104 | * Fetches an object |
||
105 | * |
||
106 | * @param array $identifiers |
||
107 | * |
||
108 | * @return object|null |
||
109 | */ |
||
110 | public function get(array $identifiers, $entityClass = null) |
||
111 | { |
||
112 | foreach ($this->store as $entry) { |
||
113 | if ($entry->match($identifiers, $entityClass)) { |
||
114 | return $entry->getObject(); |
||
115 | } |
||
116 | } |
||
117 | |||
118 | return null; |
||
119 | } |
||
120 | |||
121 | /** |
||
122 | * Returns the table name |
||
123 | * |
||
124 | * @return string |
||
125 | */ |
||
126 | public function getTableName() |
||
127 | { |
||
128 | return $this->tableName; |
||
129 | } |
||
130 | |||
131 | |||
132 | /** |
||
133 | * |
||
134 | * @param mixed $object |
||
135 | * |
||
136 | * @return Entry |
||
137 | */ |
||
138 | public function getEntry($object) |
||
139 | { |
||
140 | foreach ($this->store as $entry) { |
||
141 | if ($entry->matchObject($object)) { |
||
142 | return $entry; |
||
143 | } |
||
144 | } |
||
145 | |||
146 | return false; |
||
0 ignored issues
–
show
The return type of
return false; (false ) is incompatible with the return type documented by Fwk\Db\Registry\Registry::getEntry of type Fwk\Db\Registry\Entry .
If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design. Let’s take a look at an example: class Author {
private $name;
public function __construct($name) {
$this->name = $name;
}
public function getName() {
return $this->name;
}
}
abstract class Post {
public function getAuthor() {
return 'Johannes';
}
}
class BlogPost extends Post {
public function getAuthor() {
return new Author('Johannes');
}
}
class ForumPost extends Post { /* ... */ }
function my_function(Post $post) {
echo strtoupper($post->getAuthor());
}
Our function ![]() |
|||
147 | } |
||
148 | |||
149 | /** |
||
150 | * |
||
151 | * @return Entry |
||
152 | */ |
||
153 | protected function getEntryByIdentifiers(array $identifiers, $className = null) |
||
154 | { |
||
155 | foreach ($this->store as $entry) { |
||
156 | if ($entry->match($identifiers, $className)) { |
||
157 | return $entry; |
||
158 | } |
||
159 | } |
||
160 | |||
161 | return false; |
||
0 ignored issues
–
show
The return type of
return false; (false ) is incompatible with the return type documented by Fwk\Db\Registry\Registry::getEntryByIdentifiers of type Fwk\Db\Registry\Entry .
If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design. Let’s take a look at an example: class Author {
private $name;
public function __construct($name) {
$this->name = $name;
}
public function getName() {
return $this->name;
}
}
abstract class Post {
public function getAuthor() {
return 'Johannes';
}
}
class BlogPost extends Post {
public function getAuthor() {
return new Author('Johannes');
}
}
class ForumPost extends Post { /* ... */ }
function my_function(Post $post) {
echo strtoupper($post->getAuthor());
}
Our function ![]() |
|||
162 | } |
||
163 | |||
164 | /** |
||
165 | * Returns an Event Dispatcher attached to a stored object |
||
166 | * |
||
167 | * @return Dispatcher |
||
168 | * @throws UnregisteredEntityException if the $object is not registered |
||
169 | */ |
||
170 | public function getEventDispatcher($object) |
||
171 | { |
||
172 | $entry = $this->getEntry($object); |
||
173 | if ($entry === false) { |
||
174 | throw new UnregisteredEntityException(sprintf('Unregistered entity (%s)', get_class($object))); |
||
175 | } |
||
176 | |||
177 | return $entry->data('dispatcher', new Dispatcher()); |
||
178 | } |
||
179 | |||
180 | /** |
||
181 | * |
||
182 | * @param mixed $object |
||
183 | * @param \Fwk\Events\Event $event |
||
184 | * |
||
185 | * @return void |
||
186 | */ |
||
187 | public function fireEvent($object, Event $event) |
||
188 | { |
||
189 | $this->getEventDispatcher($object)->notify($event); |
||
190 | } |
||
191 | |||
192 | /** |
||
193 | * Listener to fetch last insert ID on auto-increment columns |
||
194 | * |
||
195 | * @param AbstractEntityEvent $event |
||
196 | * |
||
197 | * @return void |
||
198 | */ |
||
199 | public function getLastInsertId(AbstractEntityEvent $event) |
||
200 | { |
||
201 | $connx = $event->getConnection(); |
||
202 | $table = $connx->table($this->getTableName()); |
||
203 | $obj = $event->getEntity(); |
||
204 | $entry = $this->getEntry($obj); |
||
205 | |||
206 | if (false === $entry) { |
||
207 | return; |
||
208 | } |
||
209 | |||
210 | foreach ($table->getColumns() as $column) { |
||
211 | if (!$column->getAutoincrement()) { |
||
212 | continue; |
||
213 | } |
||
214 | |||
215 | $columnName = $column->getName(); |
||
216 | $access = Accessor::factory($obj); |
||
217 | $test = $access->get($columnName); |
||
218 | |||
219 | if (!empty($test)) { |
||
220 | continue; |
||
221 | } |
||
222 | |||
223 | $lastInsertId = $connx->lastInsertId(); |
||
224 | $access->set($columnName, $lastInsertId); |
||
225 | $ids = $entry->getIdentifiers(); |
||
226 | $ids[$columnName] = $lastInsertId; |
||
227 | $entry->setIdentifiers($ids)->fresh(); |
||
228 | } |
||
229 | } |
||
230 | |||
231 | /** |
||
232 | * Removes an object from the registry |
||
233 | * |
||
234 | * @param mixed $object |
||
235 | * |
||
236 | * @return Registry |
||
237 | * @throws UnregisteredEntityException if the $object is not registered |
||
238 | */ |
||
239 | public function remove($object) |
||
240 | { |
||
241 | $entry = $this->getEntry($object); |
||
242 | if ($entry === false) { |
||
243 | throw new UnregisteredEntityException(sprintf('Unregistered entity (%s)', get_class($object))); |
||
244 | } |
||
245 | |||
246 | $this->store->detach($entry); |
||
247 | unset($entry); |
||
248 | |||
249 | return $this; |
||
250 | } |
||
251 | |||
252 | /** |
||
253 | * Removes an object from its identifiers |
||
254 | * |
||
255 | * @param array $identifiers |
||
256 | * @param string $className |
||
0 ignored issues
–
show
Should the type for parameter
$className not be string|null ?
This check looks for It makes a suggestion as to what type it considers more descriptive. Most often this is a case of a parameter that can be null in addition to its declared types. ![]() |
|||
257 | * |
||
258 | * @return Registry |
||
259 | */ |
||
260 | public function removeByIdentifiers(array $identifiers, $className = null) |
||
261 | { |
||
262 | $entry = $this->getEntryByIdentifiers($identifiers, $className); |
||
263 | if (false !== $entry) { |
||
264 | $this->store->detach($entry); |
||
265 | unset($entry); |
||
266 | } |
||
267 | |||
268 | return $this; |
||
269 | } |
||
270 | |||
271 | /** |
||
272 | * Tells if the registry contains an instance of the object |
||
273 | * |
||
274 | * @param mixed $object |
||
275 | * |
||
276 | * @return boolean |
||
277 | */ |
||
278 | public function contains($object) |
||
0 ignored issues
–
show
function contains() does not seem to conform to the naming convention (^(?:is|has|should|may|su...ster|unregister|exists) ).
This check examines a number of code elements and verifies that they conform to the given naming conventions. You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods. ![]() |
|||
279 | { |
||
280 | return false !== $this->getEntry($object); |
||
281 | } |
||
282 | |||
283 | /** |
||
284 | * |
||
285 | * @param object $object |
||
286 | * |
||
287 | * @return integer |
||
288 | * @throws UnregisteredEntityException |
||
289 | */ |
||
290 | public function getState($object) |
||
291 | { |
||
292 | $entry = $this->getEntry($object); |
||
293 | if ($entry === false) { |
||
294 | return RegistryState::UNREGISTERED; |
||
295 | } |
||
296 | |||
297 | return $entry->getState(); |
||
298 | } |
||
299 | |||
300 | /** |
||
301 | * |
||
302 | * @return array |
||
303 | */ |
||
304 | public function toArray() |
||
305 | { |
||
306 | $arr = array(); |
||
307 | foreach ($this->store as $entry) { |
||
308 | $arr[] = $entry->getObject(); |
||
309 | } |
||
310 | |||
311 | return $arr; |
||
312 | } |
||
313 | |||
314 | /** |
||
315 | * |
||
316 | * @return integer |
||
317 | */ |
||
318 | public function count() |
||
319 | { |
||
320 | return count($this->store); |
||
321 | } |
||
322 | |||
323 | /** |
||
324 | * |
||
325 | * @return \ArrayIterator |
||
326 | */ |
||
327 | public function getIterator() |
||
328 | { |
||
329 | return new \ArrayIterator($this->toArray()); |
||
330 | } |
||
331 | |||
332 | |||
333 | public function markForAction($object, $action, array $listeners = array()) |
||
334 | { |
||
335 | $entry = $this->getEntry($object); |
||
336 | if (false === $entry) { |
||
337 | $entry = $this->store($object, array(), RegistryState::REGISTERED, array('listeners' => $listeners)); |
||
338 | } |
||
339 | |||
340 | $entry->setAction($action, $this->_priority); |
||
341 | $this->_priority--; |
||
342 | } |
||
343 | |||
344 | /** |
||
345 | * |
||
346 | * @return \SplPriorityQueue |
||
347 | */ |
||
348 | public function getWorkersQueue() |
||
349 | { |
||
350 | $queue = new \SplPriorityQueue(); |
||
351 | |||
352 | foreach ($this->store as $entry) { |
||
353 | if (!$entry->hasAction()) { |
||
354 | continue; |
||
355 | } |
||
356 | |||
357 | $action = $entry->getAction(); |
||
358 | $object = $entry->getObject(); |
||
359 | |||
360 | $access = new Accessor($object); |
||
361 | $relations = $access->getRelations(); |
||
362 | foreach ($relations as $key => $relation) { |
||
363 | $relation->setParent($object, $this->getEventDispatcher($object)); |
||
364 | } |
||
365 | |||
366 | switch ($action) { |
||
367 | case self::ACTION_DELETE: |
||
368 | $worker = new DeleteEntityWorker($object); |
||
369 | break; |
||
370 | |||
371 | case self::ACTION_SAVE: |
||
372 | $worker = new SaveEntityWorker($object); |
||
373 | break; |
||
374 | |||
375 | default: |
||
376 | throw new Exception(sprintf("Unknown registry action '%s'", $action)); |
||
377 | } |
||
378 | |||
379 | $worker->setRegistry($this); |
||
380 | $queue->insert($worker, $entry->getActionPriority()); |
||
381 | } |
||
382 | |||
383 | return $queue; |
||
384 | } |
||
385 | |||
386 | /** |
||
387 | * Mark current object values (Accessor) as initial values |
||
388 | * |
||
389 | * @param mixed $object |
||
390 | * |
||
391 | * @return void |
||
392 | */ |
||
393 | public function defineInitialValues($object, Connection $connection = null, Table $table = null) |
||
394 | { |
||
395 | $entry = $this->getEntry($object); |
||
396 | if (false === $entry) { |
||
397 | throw new UnregisteredEntityException(sprintf('Unregistered entity (%s)', get_class($object))); |
||
398 | } |
||
399 | |||
400 | $entry->fresh(); |
||
401 | |||
402 | if ($connection !== null && $table !== null) { |
||
403 | $entry->data('dispatcher')->notify(new FreshEvent($connection, $table, $object)); |
||
404 | } |
||
405 | } |
||
406 | |||
407 | /** |
||
408 | * |
||
409 | * @param mixed $object |
||
410 | * |
||
411 | * @return array |
||
412 | */ |
||
413 | public function getChangedValues($object) |
||
414 | { |
||
415 | $entry = $this->getEntry($object); |
||
416 | if (false === $entry) { |
||
417 | throw new UnregisteredEntityException(sprintf('Unregistered entity (%s)', get_class($object))); |
||
418 | } |
||
419 | |||
420 | return $entry->getChangedValues(); |
||
421 | } |
||
422 | |||
423 | /** |
||
424 | * |
||
425 | */ |
||
426 | public function clear() |
||
427 | { |
||
428 | unset($this->store); |
||
429 | $this->store = new SplObjectStorage(); |
||
430 | $this->_priority = \PHP_INT_MAX; |
||
431 | |||
432 | return $this; |
||
433 | } |
||
434 | |||
435 | /** |
||
436 | * @return SplObjectStorage |
||
437 | */ |
||
438 | public function getStore() |
||
439 | { |
||
440 | return $this->store; |
||
441 | } |
||
442 | } |
This check examines a number of code elements and verifies that they conform to the given naming conventions.
You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.