Completed
Push — master ( 9d97a9...c11d2c )
by Roni
01:25
created

DoctrineSubscriber::isScheduledForDelete()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 6
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 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\ORM\Event\LifecycleEventArgs;
17
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
18
use Symfony\Component\DependencyInjection\ContainerAwareTrait;
19
use Xiidea\EasyAuditBundle\Events\DoctrineEntityEvent;
20
use Xiidea\EasyAuditBundle\Events\DoctrineEvents;
21
22
class DoctrineSubscriber implements ContainerAwareInterface, EventSubscriber
23
{
24
    use ContainerAwareTrait;
25
26
    /** @var \Doctrine\Common\Annotations\Reader */
27
    private $annotationReader;
28
29
    private $toBeDeleted = [];
30
31
    /**
32
     * @var array
33
     */
34
    private $entities;
35
36
    public function __construct($entities = array())
37
    {
38
        $this->entities = $entities;
39
    }
40
41
    public function getSubscribedEvents()
42
    {
43
        return array(
44
            'postPersist',
45
            'postUpdate',
46
            'preRemove',
47
            'postRemove'
48
        );
49
    }
50
51
    public function postPersist(LifecycleEventArgs $args)
52
    {
53
        $this->handleEvent(DoctrineEvents::ENTITY_CREATED, $args);
54
    }
55
56
    public function postUpdate(LifecycleEventArgs $args)
57
    {
58
        $this->handleEvent(DoctrineEvents::ENTITY_UPDATED, $args);
59
    }
60
61
    public function preRemove(LifecycleEventArgs $args)
62
    {
63
        if (false === $this->isConfiguredToTrack($args->getEntity(), DoctrineEvents::ENTITY_DELETED)) {
64
            return;
65
        }
66
67
        $className = ClassUtils::getClass($args->getEntity());
68
69
        if (!isset($this->toBeDeleted[$className])) {
70
            $this->toBeDeleted[$className] = [];
71
        }
72
73
        $this->toBeDeleted[$className][spl_object_hash($args->getEntity())] = $this->getIdentity($args, $className);
74
    }
75
76
    public function postRemove(LifecycleEventArgs $args)
77
    {
78
        $identity = $this->getToBeDeletedId($args->getEntity());
79
80
        if (null !== $identity) {
81
            $this->container->get('event_dispatcher')->dispatch(DoctrineEvents::ENTITY_DELETED,
82
                new DoctrineEntityEvent($args, $identity)
83
            );
84
        }
85
    }
86
87
    private function getToBeDeletedId($entity)
88
    {
89
        if($this->isScheduledForDelete($entity)) {
90
            return $this->toBeDeleted[ClassUtils::getClass($entity)][spl_object_hash($entity)];
91
        }
92
93
        return null;
94
    }
95
96
    /**
97
     * @param string $eventName
98
     * @param LifecycleEventArgs $args
99
     */
100
    private function handleEvent($eventName, LifecycleEventArgs $args)
101
    {
102
        if (true === $this->isConfiguredToTrack($args->getEntity(), $eventName)) {
103
            $this->container->get('event_dispatcher')->dispatch($eventName,
104
                new DoctrineEntityEvent($args, $this->getIdentity($args, ClassUtils::getClass($args->getEntity())))
105
            );
106
        }
107
    }
108
109
    /**
110
     * @param $entity
111
     * @param string $eventName
112
     * @return bool
113
     */
114
    private function isConfiguredToTrack($entity, $eventName = '')
115
    {
116
        $class = ClassUtils::getClass($entity);
117
        $eventType = DoctrineEvents::getShortEventType($eventName);
118
119
        if (null !== $track = $this->isAnnotatedEvent($entity, $eventType)) {
120
            return $track;
121
        }
122
123
        if (!$this->isConfigured($class)) {
124
            return FALSE;
125
        }
126
127
        if ($this->shouldTrackAllEventType($class)) {
128
            return TRUE;
129
        }
130
131
        return $this->shouldTrackEventType($eventType, $class);
132
    }
133
134
    /**
135
     * @param $entity
136
     * @param string $eventType
137
     * @return bool|null
138
     */
139
    protected function isAnnotatedEvent($entity, $eventType)
140
    {
141
        $metaData = $this->hasAnnotation($entity);
142
143
        if (!$metaData) {
144
            return null;
145
        }
146
147
        return empty($metaData->events) || in_array($eventType, $metaData->events);
148
    }
149
150
    /**
151
     * @param $entity
152
     * @return null|object
153
     */
154
    protected function hasAnnotation($entity)
155
    {
156
        $reflection = $this->getReflectionClassFromObject($entity);
157
158
        return $this
159
            ->getAnnotationReader()
160
            ->getClassAnnotation($reflection, 'Xiidea\EasyAuditBundle\Annotation\ORMSubscribedEvents');
161
162
    }
163
164
    /**
165
     * @return \Doctrine\Common\Annotations\Reader
166
     */
167
    protected function getAnnotationReader()
168
    {
169
        return $this->annotationReader;
170
    }
171
172
    /**
173
     * @param $object
174
     * @return \ReflectionClass
175
     */
176
    protected function getReflectionClassFromObject($object)
177
    {
178
        $class = ClassUtils::getClass($object);
179
180
        return new \ReflectionClass($class);
181
    }
182
183
    /**
184
     * @param string $eventType
185
     * @param string $class
186
     * @return bool
187
     */
188
    private function shouldTrackEventType($eventType, $class)
189
    {
190
        return (is_array($this->entities[$class]) && in_array($eventType, $this->entities[$class]));
191
    }
192
193
    /**
194
     * @param string $class
195
     * @return bool
196
     */
197
    private function shouldTrackAllEventType($class)
198
    {
199
        return empty($this->entities[$class]);
200
    }
201
202
    /**
203
     * @param string $class
204
     * @return bool
205
     */
206
    protected function isConfigured($class)
207
    {
208
        return isset($this->entities[$class]);
209
    }
210
211
    /**
212
     * @param \Doctrine\Common\Annotations\Reader $annotationReader
213
     */
214
    public function setAnnotationReader($annotationReader = null)
215
    {
216
        $this->annotationReader = $annotationReader;
217
    }
218
219
    /**
220
     * @param LifecycleEventArgs $args
221
     * @param $className
222
     * @return array
223
     */
224
    protected function getIdentity(LifecycleEventArgs $args, $className)
225
    {
226
        return $args->getEntityManager()->getClassMetadata($className)->getIdentifierValues($args->getEntity());
227
    }
228
229
    /**
230
     * @param $entity
231
     * @return boolean
232
     */
233
    private function isScheduledForDelete($entity)
234
    {
235
        $originalClassName = ClassUtils::getClass($entity);
236
237
        return isset($this->toBeDeleted[$originalClassName]) && isset($this->toBeDeleted[$originalClassName][spl_object_hash($entity)]);
238
    }
239
}
240