Completed
Push — master ( f9521c...a16a3a )
by Roni
02:17
created

Resolver/EntityEventResolver.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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\Resolver;
13
14
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
15
use Symfony\Component\DependencyInjection\ContainerAwareTrait;
16
use Symfony\Component\EventDispatcher\Event;
17
use Symfony\Component\PropertyAccess\Exception\NoSuchPropertyException;
18
use Symfony\Component\PropertyAccess\PropertyAccess;
19
use Xiidea\EasyAuditBundle\Events\DoctrineEntityEvent;
20
use Xiidea\EasyAuditBundle\Events\DoctrineEvents;
21
22
/** Custom Event Resolver Example Class */
23
class EntityEventResolver implements ContainerAwareInterface, EventResolverInterface
24
{
25
    use ContainerAwareTrait;
26
27
    protected $candidateProperties = array('name', 'title');
28
29
    protected $propertiesFound = array();
30
31
    protected $eventShortName;
32
33
    /** @var  $event DoctrineEntityEvent */
34
    protected $event;
35
36
    protected $entity;
37
38
    protected $eventName;
39
40
41
    /**
42
     * @param Event|DoctrineEntityEvent $event
43
     * @param $eventName
44
     *
45
     * @return array
46
     */
47
    public function getEventLogInfo(Event $event, $eventName)
48
    {
49
        if (!$event instanceof DoctrineEntityEvent) {
50
            return null;
51
        }
52
53
        $this->initialize($event, $eventName);
54
55
        if ($this->isUpdateEvent() && null === $this->getChangeSets($this->entity)) {
56
            return null;
57
        }
58
59
        $entityClass = $this->getReflectionClassFromObject($this->entity);
60
61
        return array(
62
            'description' => $this->getDescription($entityClass),
63
            'type' => $this->getEventType($entityClass->getShortName()),
64
        );
65
66
    }
67
68
    /**
69
     * @param DoctrineEntityEvent $event
70
     * @param string $eventName
71
     */
72
    private function initialize(DoctrineEntityEvent $event, $eventName)
73
    {
74
        $this->eventShortName = null;
75
        $this->propertiesFound = array();
76
        $this->eventName = $eventName;
77
        $this->event = $event;
78
        $this->entity = $event->getLifecycleEventArgs()->getEntity();
79
    }
80
81
    protected function getChangeSets($entity)
82
    {
83
        return $this->isUpdateEvent() ? $this->getUnitOfWork()->getEntityChangeSet($entity) : null;
84
    }
85
86
    protected function isUpdateEvent()
87
    {
88
        return $this->getEventShortName() == 'updated';
89
    }
90
91
    /**
92
     * @param string $name
93
     * @return string|mixed
94
     */
95
    protected function getProperty($name)
96
    {
97
        $propertyAccessor = PropertyAccess::createPropertyAccessor();
98
99
        try {
100
            return $propertyAccessor->getValue($this->entity, $this->propertiesFound[$name]);
101
        } catch (NoSuchPropertyException $e) {
102
            return '{INACCESSIBLE} property! ' . $e->getMessage();
103
        }
104
    }
105
106
107
    /**
108
     * @param string $typeName
109
     * @return string
110
     */
111
    protected function getEventType($typeName)
112
    {
113
        return $typeName . " " . $this->getEventShortName();
114
    }
115
116
    /**
117
     * @param \ReflectionClass $reflectionClass
118
     * @return string
119
     */
120
    protected function getDescription(\ReflectionClass $reflectionClass)
121
    {
122
        $property = $this->getBestCandidatePropertyForIdentify($reflectionClass);
123
124
        $descriptionTemplate = '%s has been %s';
125
126
        if ($property) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $property of type null|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
127
            $descriptionTemplate .= sprintf(' with %s = "%s"', $property, $this->getProperty($property));
128
        }
129
130
        return sprintf(
131
            $descriptionTemplate,
132
            $reflectionClass->getShortName(),
133
            $this->getEventShortName()
134
        );
135
    }
136
137
    /**
138
     * @return string
139
     */
140
    protected function getEventShortName()
141
    {
142
        if (null === $this->eventShortName) {
143
            $this->eventShortName = DoctrineEvents::getShortEventType($this->getName());
144
        }
145
146
        return $this->eventShortName;
147
    }
148
149
    /**
150
     * @param \ReflectionClass $reflectionClass
151
     * @return null|string
152
     */
153
    protected function getBestCandidatePropertyForIdentify(\ReflectionClass $reflectionClass)
154
    {
155
        $properties = $reflectionClass->getProperties(
156
            \ReflectionProperty::IS_PROTECTED | \ReflectionProperty::IS_PRIVATE | \ReflectionProperty::IS_PUBLIC
157
        );
158
159
        return $this->getNameOrIdPropertyFromPropertyList($properties,
160
            strtolower($reflectionClass->getShortName()) . "id"
161
        );
162
    }
163
164
    /**
165
     * @param string $propertyName
166
     * @param \ReflectionProperty $property
167
     * @return null | string
168
     */
169
    protected function getPropertyNameInCandidateList($propertyName, \ReflectionProperty $property)
170
    {
171
        foreach ($this->candidateProperties as $candidate) {
172
            if ($propertyName == $candidate) {
173
                return $this->propertiesFound[$candidate] = $property->name;
174
            }
175
        }
176
177
        return null;
178
    }
179
180
    /**
181
     * @param string $property
182
     * @param string $entityIdStr
183
     * @return bool
184
     */
185
    protected function isIdProperty($property, $entityIdStr)
186
    {
187
        return $property == 'id' || $property == $entityIdStr;
188
    }
189
190
    /**
191
     * @return string
192
     */
193
    protected function getName()
194
    {
195
        return $this->eventName;
196
    }
197
198
    /**
199
     * @param $object
200
     * @return \ReflectionClass
201
     */
202
    protected function getReflectionClassFromObject($object)
203
    {
204
        return new \ReflectionClass(get_class($object));
205
    }
206
207
    /**
208
     * @return \Doctrine\ORM\UnitOfWork
209
     */
210
    protected function getUnitOfWork()
211
    {
212
        return $this->container->get('doctrine')->getManager()->getUnitOfWork();
213
    }
214
215
    /**
216
     * @param $properties
217
     * @param $entityIdStr
218
     * @return null|string
219
     */
220
    private function getNameOrIdPropertyFromPropertyList($properties, $entityIdStr)
221
    {
222
        $propertyName = null;
223
224
        foreach ($properties as $property) {
225
            $propertyNameLower = strtolower($property->name);
226
227
            if (null !== $foundPropertyName = $this->getPropertyNameInCandidateList($propertyNameLower, $property)) {
228
                return $foundPropertyName;
229
            }
230
231
            if (null === $propertyName && $this->isIdProperty($propertyNameLower, $entityIdStr)) {
232
                $this->propertiesFound['id'] = $propertyName = $property->name;
233
            }
234
        }
235
236
        return $propertyName;
237
    }
238
}
239