Completed
Pull Request — master (#15)
by Artem
05:22 queued 04:14
created

JmsSerializerSubscriber::getHostUrl()   B

Complexity

Conditions 7
Paths 3

Size

Total Lines 15
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 15
rs 8.2222
cc 7
eloc 9
nc 3
nop 0
1
<?php
2
/*
3
 * This file is part of the FreshVichUploaderSerializationBundle
4
 *
5
 * (c) Artem Henvald <[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 Fresh\VichUploaderSerializationBundle\EventListener;
12
13
use Doctrine\Common\Annotations\CachedReader;
14
use Doctrine\Common\Persistence\Proxy;
15
use Doctrine\Common\Util\ClassUtils;
16
use Fresh\VichUploaderSerializationBundle\Annotation\VichSerializableClass;
17
use Fresh\VichUploaderSerializationBundle\Annotation\VichSerializableField;
18
use Fresh\VichUploaderSerializationBundle\Exception\IncompatibleUploadableAndSerializableFieldAnnotationException;
19
use JMS\Serializer\EventDispatcher\Events;
20
use JMS\Serializer\EventDispatcher\EventSubscriberInterface;
21
use JMS\Serializer\EventDispatcher\ObjectEvent;
22
use JMS\Serializer\EventDispatcher\PreSerializeEvent;
23
use Monolog\Logger;
24
use Symfony\Component\PropertyAccess\PropertyAccessor;
25
use Symfony\Component\Routing\RequestContext;
26
use Vich\UploaderBundle\Mapping\Annotation\UploadableField;
27
use Vich\UploaderBundle\Storage\StorageInterface;
28
29
/**
30
 * JmsPreSerializeListener Class.
31
 *
32
 * @author Artem Henvald <[email protected]>
33
 */
34
class JmsSerializerSubscriber implements EventSubscriberInterface
35
{
36
    /** @var StorageInterface */
37
    private $storage;
38
39
    /** @var RequestContext */
40
    private $requestContext;
41
42
    /** @var CachedReader */
43
    private $annotationReader;
44
45
    /** @var PropertyAccessor */
46
    private $propertyAccessor;
47
48
    /** @var Logger */
49
    private $logger;
50
51
    /** @var array */
52
    private $serializedObjects = [];
53
54
    /**
55
     * @param StorageInterface $storage
56
     * @param RequestContext   $requestContext
57
     * @param CachedReader     $annotationReader
58
     * @param PropertyAccessor $propertyAccessor
59
     * @param Logger           $logger
60
     */
61
    public function __construct(StorageInterface $storage, RequestContext $requestContext, CachedReader $annotationReader, PropertyAccessor $propertyAccessor, Logger $logger)
62
    {
63
        $this->storage = $storage;
64
        $this->requestContext = $requestContext;
65
        $this->annotationReader = $annotationReader;
66
        $this->propertyAccessor = $propertyAccessor;
67
        $this->logger = $logger;
68
    }
69
70
    /**
71
     * @return array
72
     */
73
    public static function getSubscribedEvents()
74
    {
75
        return [
76
            ['event' => Events::PRE_SERIALIZE, 'method' => 'onPreSerialize'],
77
            ['event' => Events::POST_SERIALIZE, 'method' => 'onPostSerialize'],
78
        ];
79
    }
80
81
    /**
82
     * @param PreSerializeEvent $event
83
     *
84
     * @throws IncompatibleUploadableAndSerializableFieldAnnotationException
85
     */
86
    public function onPreSerialize(PreSerializeEvent $event)
87
    {
88
        $object = $event->getObject();
89
90
        if ($object instanceof Proxy && !$object->__isInitialized()) {
91
            $object->__load();
92
        }
93
94
        $objectUid = \spl_object_hash($object);
95
        if (\array_key_exists($objectUid, $this->serializedObjects)) {
96
            return;
97
        }
98
99
        $classAnnotation = $this->annotationReader->getClassAnnotation(
100
            new \ReflectionClass(ClassUtils::getClass($object)),
101
            VichSerializableClass::class
102
        );
103
104
        if ($classAnnotation instanceof VichSerializableClass) {
105
            $reflectionClass = ClassUtils::newReflectionClass(\get_class($object));
106
            $this->logger->debug(\sprintf(
107
                'Found @VichSerializableClass annotation for the class "%s"',
108
                $reflectionClass->getName()
0 ignored issues
show
Bug introduced by
Consider using $reflectionClass->name. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
109
            ));
110
111
            foreach ($reflectionClass->getProperties() as $property) {
112
                $vichSerializableAnnotation = $this->annotationReader->getPropertyAnnotation($property, VichSerializableField::class);
113
114
                if ($vichSerializableAnnotation instanceof VichSerializableField) {
115
                    $vichUploadableFileAnnotation = $this->annotationReader->getPropertyAnnotation($property, UploadableField::class);
116
117
                    if ($vichUploadableFileAnnotation instanceof UploadableField) {
118
                        throw new IncompatibleUploadableAndSerializableFieldAnnotationException(\sprintf(
119
                            'The field "%s" in the class "%s" cannot have @UploadableField and @VichSerializableField annotations at the same moment.',
120
                            $property->getName(),
121
                            $reflectionClass->getName()
0 ignored issues
show
Bug introduced by
Consider using $reflectionClass->name. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
122
                        ));
123
                    }
124
                    $this->logger->debug(\sprintf(
125
                        'Found @VichSerializableField annotation for the field "%s" in the class "%s"',
126
                        $property->getName(),
127
                        $reflectionClass->getName()
0 ignored issues
show
Bug introduced by
Consider using $reflectionClass->name. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
128
                    ));
129
130
                    $uri = null;
131
                    $property->setAccessible(true);
132
133
                    if ($property->getValue($event->getObject())) {
134
                        $uri = $this->storage->resolveUri($object, $vichSerializableAnnotation->getField());
135
                        if ($vichSerializableAnnotation->isIncludeHost()) {
136
                            $uri = $this->getHostUrl().$uri;
137
                        }
138
                    }
139
                    $property->setValue($object, $uri);
140
                    $this->serializedObjects[$objectUid][$property->getName()] = $property->getValue($event->getObject());
141
                }
142
            }
143
        }
144
    }
145
146
    /**
147
     * @param ObjectEvent $event
148
     */
149
    public function onPostSerialize(ObjectEvent $event)
150
    {
151
        $object = $event->getObject();
152
153
        if ($object instanceof Proxy && !$object->__isInitialized()) {
154
            $object->__load();
155
        }
156
157
        $objectUid = \spl_object_hash($object);
158
        if (!\array_key_exists($objectUid, $this->serializedObjects)) {
159
            return;
160
        }
161
162
        foreach ($this->serializedObjects[$objectUid] as $propertyName => $propertyValue) {
163
            $this->propertyAccessor->setValue($object, $propertyName, $propertyValue);
164
        }
165
    }
166
167
    /**
168
     * Get host url (scheme://host:port).
169
     *
170
     * @return string
171
     */
172
    private function getHostUrl()
173
    {
174
        $scheme = $this->requestContext->getScheme();
175
        $hostPort = $this->requestContext->getHttpPort();
176
177
        $url = $scheme.'://'.$this->requestContext->getHost();
178
179
        if ('http' === $scheme && $hostPort && 80 !== $hostPort) {
180
            $url .= ':'.$hostPort;
181
        } elseif ('https' === $scheme && $hostPort && 443 !== $hostPort) {
182
            $url .= ':'.$hostPort;
183
        }
184
185
        return $url;
186
    }
187
}
188