Issues (33)

Security Analysis    no request data  

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

src/InMemoryRepository.php (6 issues)

Upgrade to new PHP Analysis Engine

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 T4webInfrastructure;
4
5
use ArrayObject;
6
use Zend\EventManager\EventManagerInterface;
7
use Zend\EventManager\Event;
8
use T4webDomainInterface\Infrastructure\CriteriaInterface;
9
use T4webDomainInterface\Infrastructure\RepositoryInterface;
10
use T4webDomainInterface\EntityInterface;
11
use T4webDomainInterface\EntityFactoryInterface;
12
use T4webInfrastructure\Event\EntityChangedEvent;
13
14
class InMemoryRepository implements RepositoryInterface
15
{
16
    /**
17
     * @var string
18
     */
19
    protected $entityName;
20
21
    /**
22
     * @var string
23
     */
24
    protected $collectionClass;
25
26
    /**
27
     * @var CriteriaFactory
28
     */
29
    protected $criteriaFactory;
30
31
    /**
32
     * @var EntityFactoryInterface
33
     */
34
    protected $entityFactory;
35
36
    /**
37
     * @var ArrayObject
38
     */
39
    protected $identityMap;
40
41
    /**
42
     * @var ArrayObject
43
     */
44
    protected $identityMapOriginal;
45
46
    /**
47
     * @var EventManagerInterface
48
     */
49
    protected $eventManager;
50
51
    /**
52
     * @var EntityChangedEvent
53
     */
54
    protected $event;
55
56
    protected $primaryKey = 1;
57
58
    /**
59
     * @param string $entityName
60
     * @param string $collectionClass
61
     * @param CriteriaFactory $criteriaFactory
62
     * @param EntityFactoryInterface $entityFactory
63
     * @param EventManagerInterface $eventManager
64
     */
65
    public function __construct(
66
        $entityName,
67
        $collectionClass,
68
        CriteriaFactory $criteriaFactory,
69
        EntityFactoryInterface $entityFactory,
70
        EventManagerInterface $eventManager
71
    ) {
72
        $this->entityName = $entityName;
73
        $this->collectionClass = $collectionClass;
74
        $this->criteriaFactory = $criteriaFactory;
75
        $this->entityFactory = $entityFactory;
76
        $this->identityMap = new ArrayObject();
77
        $this->identityMapOriginal = new ArrayObject();
78
        $this->eventManager = $eventManager;
79
    }
80
81
    /**
82
     * @param EntityInterface $entity
83
     * @return EntityInterface|int|null
84
     */
85
    public function add(EntityInterface $entity)
86
    {
87
        $id = $entity->getId();
88
89
        if ($this->identityMap->offsetExists((int)$id)) {
90
            $e = $this->getEvent();
91
            $originalEntity = $this->identityMapOriginal->offsetGet($entity->getId());
92
            $e->setOriginalEntity($originalEntity);
93
            $e->setChangedEntity($entity);
94
95
            $this->triggerPreChanges($e);
96
97
            $this->toIdentityMap($entity);
98
99
            $this->triggerChanges($e);
100
            $this->triggerAttributesChange($e);
101
102
            return 1;
103
        } else {
104
            if (empty($id)) {
105
                $id = $this->primaryKey++;
106
                $entity->populate(compact('id'));
107
            }
108
109
            $this->toIdentityMap($entity);
110
111
            $this->triggerCreate($entity);
112
        }
113
114
        return $entity;
115
    }
116
117
    /**
118
     * @param EntityInterface $entity
119
     * @return int|null
120
     */
121
    public function remove(EntityInterface $entity)
122
    {
123
        $id = $entity->getId();
124
125
        if ($this->identityMap->offsetExists((int)$id)) {
126
            $this->identityMap->offsetUnset($id);
127
            $result = 1;
128
        } else {
129
            $result = 0;
130
        }
131
132
        $this->triggerDelete($entity);
133
134
        return $result;
135
    }
136
137
    /**
138
     * @param CriteriaInterface|array $criteria
139
     * @return EntityInterface|null
140
     */
141
    public function find($criteria)
142
    {
143
        if (is_array($criteria)) {
144
            $criteria = $this->createCriteria($criteria);
145
        }
146
147
        $callbacks = $criteria->getQuery();
148
149
        $result = null;
150
        /** @var EntityInterface $entity */
151 View Code Duplication
        foreach ($this->identityMap as $entity) {
0 ignored issues
show
This code seems to be duplicated across 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.

Loading history...
152
153
            $data = $entity->extract();
154
            $isSatisfied = true;
155
156
            foreach ($callbacks as $callback) {
157
                if (!$callback($data)) {
158
                    $isSatisfied = false;
159
                    break 1;
160
                }
161
            }
162
163
            if ($isSatisfied) {
164
                $result = $entity;
165
                break;
166
            }
167
        }
168
169
        if (is_null($result)) {
170
            return;
171
        }
172
173
        $entity = $result;
174
175
        $this->toIdentityMap($entity);
176
177
        return $entity;
178
    }
179
180
    /**
181
     * @param mixed $id
182
     * @return EntityInterface|null
183
     */
184
    public function findById($id)
185
    {
186
        $criteria = $this->createCriteria();
187
        $criteria->equalTo('id', $id);
188
189
        return $this->find($criteria);
190
    }
191
192
    /**
193
     * @param CriteriaInterface|array $criteria
194
     * @return EntityInterface[]
195
     */
196
    public function findMany($criteria)
197
    {
198
        if (is_array($criteria)) {
199
            $criteria = $this->createCriteria($criteria);
200
        }
201
202
        $callbacks = $criteria->getQuery();
203
204
        $entities = new $this->collectionClass;
205
206
        /** @var EntityInterface $entity */
207 View Code Duplication
        foreach ($this->identityMap as $entity) {
0 ignored issues
show
This code seems to be duplicated across 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.

Loading history...
208
209
            $data = $entity->extract();
210
            $isSatisfied = true;
211
212
            foreach ($callbacks as $callback) {
213
                if (!$callback($data)) {
214
                    $isSatisfied = false;
215
                    break 1;
216
                }
217
            }
218
219
            if ($isSatisfied) {
220
                $entities->offsetSet($entity->getId(), $entity);
221
            }
222
        }
223
224
        foreach ($entities as $entity) {
225
            $this->toIdentityMap($entity);
226
        }
227
228
        return $entities;
229
    }
230
231
    /**
232
     * @param CriteriaInterface|array $criteria
233
     * @return int
234
     */
235
    public function count($criteria)
236
    {
237
        if (is_array($criteria)) {
238
            $criteria = $this->createCriteria($criteria);
239
        }
240
241
        /** @var ArrayObject $entities */
242
        $entities = $this->findMany($criteria);
243
244
        return $entities->count();
245
    }
246
247
    /**
248
     * @param array $filter
249
     * @return CriteriaInterface
250
     */
251
    public function createCriteria(array $filter = [])
252
    {
253
        return $this->criteriaFactory->buildInMemory($this->entityName, $filter);
254
    }
255
256
    /**
257
     * @param EntityInterface $entity
258
     */
259
    protected function toIdentityMap(EntityInterface $entity)
260
    {
261
        $this->identityMap->offsetSet($entity->getId(), $entity);
262
        $this->identityMapOriginal->offsetSet($entity->getId(), clone $entity);
263
    }
264
265
    /**
266
     * @param EntityInterface $changedEntity
267
     * @return bool
268
     */
269
    protected function isEntityChanged(EntityInterface $changedEntity)
270
    {
271
        $originalEntity = $this->identityMapOriginal->offsetGet($changedEntity->getId());
272
        return $changedEntity != $originalEntity;
273
    }
274
275
    /**
276
     * @return EntityChangedEvent
277
     */
278 View Code Duplication
    protected function getEvent()
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.

Loading history...
279
    {
280
        if (null === $this->event) {
281
            $this->event = new EntityChangedEvent();
282
            $this->event->setTarget($this);
283
        }
284
285
        return $this->event;
286
    }
287
288
    /**
289
     * @param EntityInterface $createdEntity
290
     */
291 View Code Duplication
    protected function triggerCreate(EntityInterface &$createdEntity)
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.

Loading history...
292
    {
293
        $this->eventManager->addIdentifiers([get_class($createdEntity)]);
294
295
        $event = new Event(
296
            sprintf('entity:%s:created', get_class($createdEntity)),
297
            $this,
298
            ['entity' => $createdEntity]
299
        );
300
        $this->eventManager->triggerEvent($event);
301
302
        if ($event->getParam('entity') && $event->getParam('entity') instanceof EntityInterface) {
303
            $createdEntity = $event->getParam('entity');
304
        }
305
    }
306
307
    /**
308
     * @param EntityInterface $deletedEntity
309
     */
310 View Code Duplication
    protected function triggerDelete(EntityInterface $deletedEntity)
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.

Loading history...
311
    {
312
        $this->eventManager->addIdentifiers([get_class($deletedEntity)]);
313
314
        $event = new Event(
315
            sprintf('entity:%s:deleted', get_class($deletedEntity)),
316
            $this,
317
            ['entity' => $deletedEntity]
318
        );
319
        $this->eventManager->triggerEvent($event);
320
    }
321
322
    /**
323
     * @param EntityChangedEvent $e
324
     */
325
    protected function triggerChanges(EntityChangedEvent $e)
326
    {
327
        $changedEntity = $e->getChangedEntity();
328
        $e->setName($this->getEntityChangeEventName($changedEntity));
329
        $this->eventManager->triggerEvent($e);
330
    }
331
332
    /**
333
     * @param EntityChangedEvent $e
334
     */
335
    protected function triggerPreChanges(EntityChangedEvent $e)
336
    {
337
        $changedEntity = $e->getChangedEntity();
338
        $e->setName($this->getEntityChangeEventName($changedEntity).':pre');
339
        $this->eventManager->triggerEvent($e);
340
    }
341
342
    /**
343
     * @param EntityChangedEvent $e
344
     */
345 View Code Duplication
    protected function triggerAttributesChange(EntityChangedEvent $e)
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.

Loading history...
346
    {
347
        $changedEntity = $e->getChangedEntity();
348
349
        $originalAttrs = $e->getOriginalEntity()->extract();
350
        $changedAttrs = $changedEntity->extract();
351
352
        foreach (array_keys(array_diff_assoc($originalAttrs, $changedAttrs)) as $attribute) {
353
            $e->setName($this->getAttributeChangeEventName($changedEntity, $attribute));
354
            $this->eventManager->triggerEvent($e);
355
        }
356
    }
357
358
    /**
359
     * @param EntityInterface $changedEntity
360
     * @return string
361
     */
362
    protected function getEntityChangeEventName(EntityInterface $changedEntity)
363
    {
364
        return sprintf('entity:%s:changed', get_class($changedEntity));
365
    }
366
367
    /**
368
     * @param EntityInterface $changedEntity
369
     * @param $attributeName
370
     * @return string
371
     */
372
    protected function getAttributeChangeEventName(EntityInterface $changedEntity, $attributeName)
373
    {
374
        return sprintf('attribute:%s:%s:changed', get_class($changedEntity), $attributeName);
375
    }
376
}
377