Completed
Push — master ( a78262...4e959e )
by Roni
11:36
created

DoctrineSubscriber::setAnnotationReader()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

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