DoctrineSubscriber   A
last analyzed

Complexity

Total Complexity 26

Size/Duplication

Total Lines 166
Duplicated Lines 0 %

Importance

Changes 7
Bugs 0 Features 0
Metric Value
wmc 26
eloc 44
c 7
b 0
f 0
dl 0
loc 166
rs 10

14 Methods

Rating   Name   Duplication   Size   Complexity  
A preRemove() 0 13 3
A postRemove() 0 6 2
A postPersist() 0 3 1
A shouldTrackEventType() 0 3 2
A handleEvent() 0 6 2
A isConfiguredToTrack() 0 18 4
A postUpdate() 0 3 1
A getToBeDeletedId() 0 7 2
A isAttributedEvent() 0 11 3
A __construct() 0 2 1
A shouldTrackAllEventType() 0 3 1
A isScheduledForDelete() 0 7 2
A getIdentity() 0 3 1
A setDispatcher() 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\Util\ClassUtils;
15
use Doctrine\Persistence\Event\LifecycleEventArgs;
16
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
17
use Xiidea\EasyAuditBundle\Attribute\SubscribeDoctrineEvents;
18
use Xiidea\EasyAuditBundle\Events\DoctrineEvents;
19
use Xiidea\EasyAuditBundle\Events\DoctrineObjectEvent;
20
21
class DoctrineSubscriber
22
{
23
    private array $toBeDeleted = [];
24
    private  $dispatcher = null;
25
26
    public function __construct(private array $entities = [])
27
    {
28
    }
29
30
    public function postPersist(LifecycleEventArgs $args)
31
    {
32
        $this->handleEvent(DoctrineEvents::ENTITY_CREATED, $args);
33
    }
34
35
    public function postUpdate(LifecycleEventArgs $args)
36
    {
37
        $this->handleEvent(DoctrineEvents::ENTITY_UPDATED, $args);
38
    }
39
40
    public function preRemove(LifecycleEventArgs $args)
41
    {
42
        if (false === $this->isConfiguredToTrack($args->getObject(), DoctrineEvents::ENTITY_DELETED)) {
43
            return;
44
        }
45
46
        $className = ClassUtils::getClass($args->getObject());
47
48
        if (!isset($this->toBeDeleted[$className])) {
49
            $this->toBeDeleted[$className] = [];
50
        }
51
52
        $this->toBeDeleted[$className][spl_object_hash($args->getObject())] = $this->getIdentity($args, $className);
53
    }
54
55
    public function postRemove(LifecycleEventArgs $args)
56
    {
57
        $identity = $this->getToBeDeletedId($args->getObject());
58
59
        if (null !== $identity) {
60
            $this->dispatcher->dispatch(new DoctrineObjectEvent($args, $identity), DoctrineEvents::ENTITY_DELETED);
61
        }
62
    }
63
64
    private function getToBeDeletedId($entity)
65
    {
66
        if ($this->isScheduledForDelete($entity)) {
67
            return $this->toBeDeleted[ClassUtils::getClass($entity)][spl_object_hash($entity)];
68
        }
69
70
        return null;
71
    }
72
73
    /**
74
     * @param  string  $eventName
75
     * @param  LifecycleEventArgs  $args
76
     */
77
    private function handleEvent($eventName, LifecycleEventArgs $args)
78
    {
79
        if (true === $this->isConfiguredToTrack($args->getObject(), $eventName)) {
80
            $this->dispatcher->dispatch(
81
                new DoctrineObjectEvent($args, $this->getIdentity($args, ClassUtils::getClass($args->getObject()))),
82
                $eventName
83
            );
84
        }
85
    }
86
87
    /**
88
     * @param $entity
89
     * @param  string  $eventName
90
     *
91
     * @return bool
92
     */
93
    private function isConfiguredToTrack($entity, $eventName = '')
94
    {
95
        $class = ClassUtils::getClass($entity);
96
        $eventType = DoctrineEvents::getShortEventType($eventName);
97
98
        if (null !== $track = $this->isAttributedEvent($entity, $eventType)) {
99
            return $track;
100
        }
101
102
        if (!isset($this->entities[$class])) {
103
            return false;
104
        }
105
106
        if ($this->shouldTrackAllEventType($class)) {
107
            return true;
108
        }
109
110
        return $this->shouldTrackEventType($eventType, $class);
111
    }
112
113
    /**
114
     * @param $entity
115
     * @param string $eventType
116
     * @return bool|null
117
     * @throws \ReflectionException
118
     */
119
    protected function isAttributedEvent($entity, $eventType)
120
    {
121
        $reflection = new \ReflectionClass($entity);
122
        $attribute = $reflection->getAttributes(SubscribeDoctrineEvents::class);
123
        if (empty($attribute)) {
124
            return null;
125
        }
126
127
        $instance = $attribute[0]->newInstance();
128
129
        return empty($instance->events) || in_array($eventType, $instance->events);
130
    }
131
132
133
    /**
134
     * @param  string  $eventType
135
     * @param  string  $class
136
     *
137
     * @return bool
138
     */
139
    private function shouldTrackEventType($eventType, $class)
140
    {
141
        return is_array($this->entities[$class]) && in_array($eventType, $this->entities[$class]);
142
    }
143
144
    /**
145
     * @param  string  $class
146
     *
147
     * @return bool
148
     */
149
    private function shouldTrackAllEventType($class)
150
    {
151
        return empty($this->entities[$class]);
152
    }
153
154
    /**
155
     * @param  LifecycleEventArgs  $args
156
     * @param $className
157
     *
158
     * @return array
159
     */
160
    protected function getIdentity(LifecycleEventArgs $args, $className)
161
    {
162
        return $args->getObjectManager()->getClassMetadata($className)->getIdentifierValues($args->getObject());
163
    }
164
165
    /**
166
     * @param $entity
167
     *
168
     * @return bool
169
     */
170
    private function isScheduledForDelete($entity)
171
    {
172
        $originalClassName = ClassUtils::getClass($entity);
173
174
        return isset($this->toBeDeleted[$originalClassName]) && isset(
175
                $this->toBeDeleted[$originalClassName][spl_object_hash(
176
                    $entity
177
                )]
178
            );
179
    }
180
181
    /**
182
     * @param  EventDispatcherInterface  $dispatcher
183
     */
184
    public function setDispatcher($dispatcher)
185
    {
186
        $this->dispatcher = $dispatcher;
187
    }
188
}
189