Passed
Pull Request — master (#58)
by
unknown
02:40
created

DoctrineSubscriber::hasAnnotation()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 4
dl 0
loc 7
c 0
b 0
f 0
rs 10
cc 1
nc 1
nop 1

1 Method

Rating   Name   Duplication   Size   Complexity  
A DoctrineSubscriber::getIdentity() 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 Xiidea\EasyAuditBundle\Attribute\SubscribeDoctrineEvents;
17
use Xiidea\EasyAuditBundle\Events\DoctrineEvents;
18
use Xiidea\EasyAuditBundle\Events\DoctrineObjectEvent;
19
20
class DoctrineSubscriber
21
{
22
    private array $toBeDeleted = [];
23
    private  $dispatcher = null;
24
25
    public function __construct(private array $entities = [])
26
    {
27
    }
28
29
    public function postPersist(LifecycleEventArgs $args)
30
    {
31
        $this->handleEvent(DoctrineEvents::ENTITY_CREATED, $args);
32
    }
33
34
    public function postUpdate(LifecycleEventArgs $args)
35
    {
36
        $this->handleEvent(DoctrineEvents::ENTITY_UPDATED, $args);
37
    }
38
39
    public function preRemove(LifecycleEventArgs $args)
40
    {
41
        if (false === $this->isConfiguredToTrack($args->getObject(), DoctrineEvents::ENTITY_DELETED)) {
42
            return;
43
        }
44
45
        $className = ClassUtils::getClass($args->getObject());
46
47
        if (!isset($this->toBeDeleted[$className])) {
48
            $this->toBeDeleted[$className] = [];
49
        }
50
51
        $this->toBeDeleted[$className][spl_object_hash($args->getObject())] = $this->getIdentity($args, $className);
52
    }
53
54
    public function postRemove(LifecycleEventArgs $args)
55
    {
56
        $identity = $this->getToBeDeletedId($args->getObject());
57
58
        if (null !== $identity) {
59
            $this->dispatcher->dispatch(new DoctrineObjectEvent($args, $identity), DoctrineEvents::ENTITY_DELETED);
60
        }
61
    }
62
63
    private function getToBeDeletedId($entity)
64
    {
65
        if ($this->isScheduledForDelete($entity)) {
66
            return $this->toBeDeleted[ClassUtils::getClass($entity)][spl_object_hash($entity)];
67
        }
68
69
        return null;
70
    }
71
72
    /**
73
     * @param  string  $eventName
74
     * @param  LifecycleEventArgs  $args
75
     */
76
    private function handleEvent($eventName, LifecycleEventArgs $args)
77
    {
78
        if (true === $this->isConfiguredToTrack($args->getObject(), $eventName)) {
79
            $this->dispatcher->dispatch(
80
                new DoctrineObjectEvent($args, $this->getIdentity($args, ClassUtils::getClass($args->getObject()))),
81
                $eventName
82
            );
83
        }
84
    }
85
86
    /**
87
     * @param $entity
88
     * @param  string  $eventName
89
     *
90
     * @return bool
91
     */
92
    private function isConfiguredToTrack($entity, $eventName = '')
93
    {
94
        $class = ClassUtils::getClass($entity);
95
        $eventType = DoctrineEvents::getShortEventType($eventName);
96
97
        if (null !== $track = $this->isAttributedEvent($entity, $eventType)) {
98
            return $track;
99
        }
100
101
        if (!isset($this->entities[$class])) {
102
            return false;
103
        }
104
105
        if ($this->shouldTrackAllEventType($class)) {
106
            return true;
107
        }
108
109
        return $this->shouldTrackEventType($eventType, $class);
110
    }
111
112
    /**
113
     * @param $entity
114
     * @param string $eventType
115
     * @return bool|null
116
     * @throws \ReflectionException
117
     */
118
    protected function isAttributedEvent($entity, $eventType)
119
    {
120
        $reflection = new \ReflectionClass($entity);
121
        $attribute = $reflection->getAttributes(SubscribeDoctrineEvents::class);
122
        if (!$attribute) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $attribute of type ReflectionAttribute[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
123
            return null;
124
        }
125
126
        $instance = $attribute[0]->newInstance();
127
128
        return empty($instance->events) || in_array($eventType, $instance->events);
129
    }
130
131
132
    /**
133
     * @param  string  $eventType
134
     * @param  string  $class
135
     *
136
     * @return bool
137
     */
138
    private function shouldTrackEventType($eventType, $class)
139
    {
140
        return is_array($this->entities[$class]) && in_array($eventType, $this->entities[$class]);
141
    }
142
143
    /**
144
     * @param  string  $class
145
     *
146
     * @return bool
147
     */
148
    private function shouldTrackAllEventType($class)
149
    {
150
        return empty($this->entities[$class]);
151
    }
152
153
    /**
154
     * @param  LifecycleEventArgs  $args
155
     * @param $className
156
     *
157
     * @return array
158
     */
159
    protected function getIdentity(LifecycleEventArgs $args, $className)
160
    {
161
        return $args->getObjectManager()->getClassMetadata($className)->getIdentifierValues($args->getObject());
162
    }
163
164
    /**
165
     * @param $entity
166
     *
167
     * @return bool
168
     */
169
    private function isScheduledForDelete($entity)
170
    {
171
        $originalClassName = ClassUtils::getClass($entity);
172
173
        return isset($this->toBeDeleted[$originalClassName]) && isset(
174
                $this->toBeDeleted[$originalClassName][spl_object_hash(
175
                    $entity
176
                )]
177
            );
178
    }
179
180
    /**
181
     * @param  EventDispatcherInterface  $dispatcher
0 ignored issues
show
Bug introduced by
The type Xiidea\EasyAuditBundle\S...ventDispatcherInterface was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
182
     */
183
    public function setDispatcher($dispatcher)
184
    {
185
        $this->dispatcher = $dispatcher;
186
    }
187
}
188