DoctrineSubscriber   A
last analyzed

Complexity

Total Complexity 31

Size/Duplication

Total Lines 223
Duplicated Lines 0 %

Importance

Changes 7
Bugs 0 Features 0
Metric Value
wmc 31
eloc 55
c 7
b 0
f 0
dl 0
loc 223
rs 9.92

19 Methods

Rating   Name   Duplication   Size   Complexity  
A preRemove() 0 13 3
A postPersist() 0 3 1
A postUpdate() 0 3 1
A getSubscribedEvents() 0 7 1
A __construct() 0 3 1
A postRemove() 0 6 2
A shouldTrackEventType() 0 3 2
A handleEvent() 0 5 2
A isConfiguredToTrack() 0 18 4
A hasAnnotation() 0 7 1
A getToBeDeletedId() 0 7 2
A isScheduledForDelete() 0 5 2
A isAnnotatedEvent() 0 9 3
A getIdentity() 0 3 1
A setDispatcher() 0 3 1
A setAnnotationReader() 0 3 1
A getAnnotationReader() 0 3 1
A getReflectionClassFromObject() 0 5 1
A shouldTrackAllEventType() 0 3 1
1
<?php
2
3
/*
4
 * This file is part of the XiideaEasyAuditBundle package.
5
 *
6
 * (c) Xiidea <http://www.xiidea.net>
7
 *
8
 * This source file is subject to the MIT license that is bundled
9
 * with this source code in the file LICENSE.
10
 */
11
12
namespace Xiidea\EasyAuditBundle\Subscriber;
13
14
use Doctrine\Common\EventSubscriber;
15
use Doctrine\Common\Util\ClassUtils;
16
use Doctrine\Persistence\Event\LifecycleEventArgs;
17
use Symfony\Component\EventDispatcher\EventDispatcher;
18
use Xiidea\EasyAuditBundle\Annotation\SubscribeDoctrineEvents;
19
use Xiidea\EasyAuditBundle\Events\DoctrineObjectEvent;
20
use Xiidea\EasyAuditBundle\Events\DoctrineEvents;
21
22
class DoctrineSubscriber implements EventSubscriber
23
{
24
    /** @var \Doctrine\Common\Annotations\Reader */
25
    private $annotationReader;
26
27
    private $toBeDeleted = [];
28
29
    /**
30
     * @var EventDispatcher
31
     */
32
    private $dispatcher;
33
34
    /**
35
     * @var array
36
     */
37
    private $entities;
38
39
    public function __construct($entities = array())
40
    {
41
        $this->entities = $entities;
42
    }
43
44
    public function getSubscribedEvents()
45
    {
46
        return array(
47
            'postPersist',
48
            'postUpdate',
49
            'preRemove',
50
            'postRemove',
51
        );
52
    }
53
54
    public function postPersist(LifecycleEventArgs $args)
55
    {
56
        $this->handleEvent(DoctrineEvents::ENTITY_CREATED, $args);
57
    }
58
59
    public function postUpdate(LifecycleEventArgs $args)
60
    {
61
        $this->handleEvent(DoctrineEvents::ENTITY_UPDATED, $args);
62
    }
63
64
    public function preRemove(LifecycleEventArgs $args)
65
    {
66
        if (false === $this->isConfiguredToTrack($args->getObject(), DoctrineEvents::ENTITY_DELETED)) {
67
            return;
68
        }
69
70
        $className = ClassUtils::getClass($args->getObject());
71
72
        if (!isset($this->toBeDeleted[$className])) {
73
            $this->toBeDeleted[$className] = [];
74
        }
75
76
        $this->toBeDeleted[$className][spl_object_hash($args->getObject())] = $this->getIdentity($args, $className);
77
    }
78
79
    public function postRemove(LifecycleEventArgs $args)
80
    {
81
        $identity = $this->getToBeDeletedId($args->getObject());
82
83
        if (null !== $identity) {
84
            $this->dispatcher->dispatch(new DoctrineObjectEvent($args, $identity), DoctrineEvents::ENTITY_DELETED);
85
        }
86
    }
87
88
    private function getToBeDeletedId($entity)
89
    {
90
        if ($this->isScheduledForDelete($entity)) {
91
            return $this->toBeDeleted[ClassUtils::getClass($entity)][spl_object_hash($entity)];
92
        }
93
94
        return null;
95
    }
96
97
    /**
98
     * @param string             $eventName
99
     * @param LifecycleEventArgs $args
100
     */
101
    private function handleEvent($eventName, LifecycleEventArgs $args)
102
    {
103
        if (true === $this->isConfiguredToTrack($args->getObject(), $eventName)) {
104
            $this->dispatcher->dispatch(new DoctrineObjectEvent($args, $this->getIdentity($args, ClassUtils::getClass($args->getObject()))),
105
                $eventName
106
            );
107
        }
108
    }
109
110
    /**
111
     * @param $entity
112
     * @param string $eventName
113
     *
114
     * @return bool
115
     */
116
    private function isConfiguredToTrack($entity, $eventName = '')
117
    {
118
        $class = ClassUtils::getClass($entity);
119
        $eventType = DoctrineEvents::getShortEventType($eventName);
120
121
        if (null !== $track = $this->isAnnotatedEvent($entity, $eventType)) {
122
            return $track;
123
        }
124
125
        if (!isset($this->entities[$class])) {
126
            return false;
127
        }
128
129
        if ($this->shouldTrackAllEventType($class)) {
130
            return true;
131
        }
132
133
        return $this->shouldTrackEventType($eventType, $class);
134
    }
135
136
    /**
137
     * @param $entity
138
     * @param string $eventType
139
     *
140
     * @return bool|null
141
     */
142
    protected function isAnnotatedEvent($entity, $eventType)
143
    {
144
        $metaData = $this->hasAnnotation($entity);
145
146
        if (!$metaData) {
147
            return null;
148
        }
149
150
        return empty($metaData->events) || in_array($eventType, $metaData->events);
151
    }
152
153
    /**
154
     * @param $entity
155
     *
156
     * @return null|object
157
     */
158
    protected function hasAnnotation($entity)
159
    {
160
        $reflection = $this->getReflectionClassFromObject($entity);
161
162
        return $this
163
            ->getAnnotationReader()
164
            ->getClassAnnotation($reflection, SubscribeDoctrineEvents::class);
165
    }
166
167
    /**
168
     * @return \Doctrine\Common\Annotations\Reader
169
     */
170
    protected function getAnnotationReader()
171
    {
172
        return $this->annotationReader;
173
    }
174
175
    /**
176
     * @param $object
177
     *
178
     * @return \ReflectionClass
179
     */
180
    protected function getReflectionClassFromObject($object)
181
    {
182
        $class = ClassUtils::getClass($object);
183
184
        return new \ReflectionClass($class);
185
    }
186
187
    /**
188
     * @param string $eventType
189
     * @param string $class
190
     *
191
     * @return bool
192
     */
193
    private function shouldTrackEventType($eventType, $class)
194
    {
195
        return is_array($this->entities[$class]) && in_array($eventType, $this->entities[$class]);
196
    }
197
198
    /**
199
     * @param string $class
200
     *
201
     * @return bool
202
     */
203
    private function shouldTrackAllEventType($class)
204
    {
205
        return empty($this->entities[$class]);
206
    }
207
208
    /**
209
     * @param \Doctrine\Common\Annotations\Reader $annotationReader
210
     */
211
    public function setAnnotationReader($annotationReader = null)
212
    {
213
        $this->annotationReader = $annotationReader;
214
    }
215
216
    /**
217
     * @param LifecycleEventArgs $args
218
     * @param $className
219
     *
220
     * @return array
221
     */
222
    protected function getIdentity(LifecycleEventArgs $args, $className)
223
    {
224
        return $args->getObjectManager()->getClassMetadata($className)->getIdentifierValues($args->getObject());
225
    }
226
227
    /**
228
     * @param $entity
229
     *
230
     * @return bool
231
     */
232
    private function isScheduledForDelete($entity)
233
    {
234
        $originalClassName = ClassUtils::getClass($entity);
235
236
        return isset($this->toBeDeleted[$originalClassName]) && isset($this->toBeDeleted[$originalClassName][spl_object_hash($entity)]);
237
    }
238
239
    /**
240
     * @param EventDispatcher $dispatcher
241
     */
242
    public function setDispatcher($dispatcher)
243
    {
244
        $this->dispatcher = $dispatcher;
245
    }
246
}
247