Completed
Push — master ( 9d95dd...590d86 )
by Bukashk0zzz
02:11
created

JmsSerializeListener::onPostSerialize()   D

Complexity

Conditions 10
Paths 6

Size

Total Lines 37
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 2 Features 0
Metric Value
c 2
b 2
f 0
dl 0
loc 37
rs 4.8196
cc 10
eloc 20
nc 6
nop 1

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/*
3
 * This file is part of the Bukashk0zzzLiipImagineSerializationBundle
4
 *
5
 * (c) Denis Golubovskiy <[email protected]>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
11
namespace Bukashk0zzz\LiipImagineSerializationBundle\EventListener;
12
13
use Bukashk0zzz\LiipImagineSerializationBundle\Annotation\LiipImagineSerializableClass;
14
use Bukashk0zzz\LiipImagineSerializationBundle\Annotation\LiipImagineSerializableField;
15
use Doctrine\Common\Annotations\CachedReader;
16
use Doctrine\Common\Util\ClassUtils;
17
use JMS\Serializer\EventDispatcher\ObjectEvent;
18
use Symfony\Component\Routing\RequestContext;
19
use Doctrine\Common\Persistence\Proxy;
20
use Liip\ImagineBundle\Imagine\Cache\CacheManager;
21
use Vich\UploaderBundle\Storage\StorageInterface;
22
23
/**
24
 * JmsSerializeListener
25
 *
26
 * @author Denis Golubovskiy <[email protected]>
27
 */
28
class JmsSerializeListener
29
{
30
    /**
31
     * @var RequestContext $requestContext Request context
32
     */
33
    private $requestContext;
34
35
    /**
36
     * @var CachedReader $annotationReader Cached annotation reader
37
     */
38
    private $annotationReader;
39
40
    /**
41
     * @var CacheManager $cacheManager LiipImagineBundle Cache Manager
42
     */
43
    private $cacheManager;
44
45
    /**
46
     * @var StorageInterface $storage Vich storage
47
     */
48
    private $vichStorage;
49
50
    /**
51
     * @var array $config Bundle config
52
     */
53
    private $config;
54
55
    /**
56
     * @var array $serializedObjects Pre Serialized objects
57
     */
58
    private $preSerializedObjects = [];
59
60
    /**
61
     * @var array $postSerializedObjects Post Serialized objects
62
     */
63
    private $postSerializedObjects = [];
64
65
    /** @noinspection MoreThanThreeArgumentsInspection
66
     *
67
     * JmsSerializeListener constructor.
68
     * @param RequestContext   $requestContext
69
     * @param CachedReader     $annotationReader
70
     * @param CacheManager     $cacheManager
71
     * @param StorageInterface $vichStorage
72
     * @param array            $config
73
     */
74
    public function __construct(
75
        RequestContext $requestContext,
76
        CachedReader $annotationReader,
77
        CacheManager $cacheManager,
78
        StorageInterface $vichStorage,
79
        array $config
80
    ) {
81
        $this->requestContext = $requestContext;
82
        $this->annotationReader = $annotationReader;
83
        $this->cacheManager = $cacheManager;
84
        $this->vichStorage = $vichStorage;
85
        $this->config = $config;
86
    }
87
88
    /**
89
     * On pre serialize
90
     *
91
     * @param ObjectEvent $event Event
92
     */
93
    public function onPreSerialize(ObjectEvent $event)
94
    {
95
        $object = $this->getObject($event);
96
        $objectUid = spl_object_hash($object);
97
98
        if (in_array($objectUid, $this->preSerializedObjects, true)) {
99
            return;
100
        }
101
102
        $classAnnotation = $this->annotationReader->getClassAnnotation(
103
            new \ReflectionClass(ClassUtils::getClass($object)),
104
            LiipImagineSerializableClass::class
105
        );
106
107
        if ($classAnnotation instanceof LiipImagineSerializableClass) {
108
            $reflectionClass = ClassUtils::newReflectionClass(get_class($object));
109
110
            foreach ($reflectionClass->getProperties() as $property) {
111
                $liipImagineAnnotation = $this->annotationReader->getPropertyAnnotation($property, LiipImagineSerializableField::class);
112
                $property->setAccessible(true);
113
114
                if ($liipImagineAnnotation instanceof LiipImagineSerializableField && $value = $property->getValue($object)) {
115
                    $vichField = $liipImagineAnnotation->getVichUploaderField();
116
117
                    if (!$liipImagineAnnotation->getVirtualField()) {
118
                        $property->setValue($object, $this->serializeValue($liipImagineAnnotation, $object, $value));
119
                    } elseif ($vichField && array_key_exists('vichUploaderSerialize', $this->config) && $this->config['vichUploaderSerialize']) {
120
                        $originalImageUri = $this->vichStorage->resolveUri($object, $vichField);
121
122
                        if (array_key_exists('includeHost', $this->config) && $this->config['includeHost']) {
123
                            $originalImageUri = $this->getHostUrl().$originalImageUri;
124
                        }
125
                        $property->setValue($object, $originalImageUri);
126
                    }
127
                }
128
            }
129
130
            $this->preSerializedObjects[$objectUid] = $objectUid;
131
        }
132
133
    }
134
135
    /**
136
     * On post serialize
137
     *
138
     * @param ObjectEvent $event Event
139
     */
140
    public function onPostSerialize(ObjectEvent $event)
141
    {
142
        $object = $this->getObject($event);
143
        $objectUid = spl_object_hash($object);
144
145
        if (in_array($objectUid, $this->postSerializedObjects, true)) {
146
            return;
147
        }
148
149
        $classAnnotation = $this->annotationReader->getClassAnnotation(
150
            new \ReflectionClass(ClassUtils::getClass($object)),
151
            LiipImagineSerializableClass::class
152
        );
153
154
        if ($classAnnotation instanceof LiipImagineSerializableClass) {
155
            $reflectionClass = ClassUtils::newReflectionClass(get_class($object));
156
157
            foreach ($reflectionClass->getProperties() as $property) {
158
                $liipImagineAnnotation = $this->annotationReader->getPropertyAnnotation($property, LiipImagineSerializableField::class);
159
                $property->setAccessible(true);
160
161
                if ($liipImagineAnnotation instanceof LiipImagineSerializableField && ($value = $property->getValue($object)) && ($virtualField = $liipImagineAnnotation->getVirtualField())) {
162
                    if (array_key_exists('vichUploaderSerialize', $this->config) && $this->config['vichUploaderSerialize'] && $liipImagineAnnotation->getVichUploaderField()) {
163
                        $valueArray = explode('/', $value);
164
                        $value = end($valueArray);
165
                        $property->setValue($object, $value);
166
                    }
167
168
                    /** @noinspection PhpUndefinedMethodInspection */
169
                    $event->getVisitor()->addData($virtualField, $this->serializeValue($liipImagineAnnotation, $object, $value));
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface JMS\Serializer\VisitorInterface as the method addData() does only exist in the following implementations of said interface: JMS\Serializer\GenericSerializationVisitor, JMS\Serializer\JsonSerializationVisitor.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
170
                }
171
            }
172
173
            $this->postSerializedObjects[$objectUid] = $objectUid;
174
        }
175
176
    }
177
178
    /**
179
     * @param ObjectEvent $event Event
180
     * @return mixed
181
     */
182
    protected function getObject($event)
183
    {
184
        $object = $event->getObject();
185
186
        if ($object instanceof Proxy
187
            && ! $object->__isInitialized()
188
        ) {
189
            $object->__load();
190
        }
191
192
        return $object;
193
    }
194
195
    /** @noinspection GenericObjectTypeUsageInspection
196
     * @param LiipImagineSerializableField $liipImagineAnnotation
197
     * @param object $object Serialized object
198
     * @param string $value Value of field
199
     * @return string
200
     */
201
    private function serializeValue(LiipImagineSerializableField $liipImagineAnnotation, $object, $value)
202
    {
203
        if ($vichField = $liipImagineAnnotation->getVichUploaderField()) {
204
            $value = $this->vichStorage->resolveUri($object, $vichField);
205
        }
206
207
        return $this->cacheManager->getBrowserPath($value, $liipImagineAnnotation->getFilter());
208
    }
209
210
    /**
211
     * Get host url (scheme, host, port)
212
     *
213
     * @return string Host url
214
     */
215
    private function getHostUrl()
216
    {
217
        $url = $this->requestContext->getScheme().'://'.$this->requestContext->getHost();
218
219
        if ($this->requestContext->getScheme() === 'http' && $this->requestContext->getHttpPort() && $this->requestContext->getHttpPort() !== 80) {
220
            $url .= ':'.$this->requestContext->getHttpPort();
221
        } elseif ($this->requestContext->getScheme() === 'https' && $this->requestContext->getHttpsPort() && $this->requestContext->getHttpsPort() !== 443) {
222
            $url .= ':'.$this->requestContext->getHttpsPort();
223
        }
224
225
        return $url;
226
    }
227
}
228