Passed
Push — develop ( 32fbc0...1b1d1e )
by Daniel
05:39
created

ApiNormalizer::isImagineSupportedFile()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 11
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 3.0261

Importance

Changes 0
Metric Value
cc 3
eloc 7
nc 3
nop 1
dl 0
loc 11
ccs 6
cts 7
cp 0.8571
crap 3.0261
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
namespace Silverback\ApiComponentBundle\Serializer;
4
5
use ApiPlatform\Core\DataProvider\ContextAwareCollectionDataProviderInterface;
6
use Doctrine\ORM\EntityManagerInterface;
7
use Liip\ImagineBundle\Imagine\Cache\CacheManager;
8
use Silverback\ApiComponentBundle\Entity\Content\Component\Collection\Collection;
9
use Silverback\ApiComponentBundle\Entity\Content\Component\Form\Form;
10
use Silverback\ApiComponentBundle\Entity\Content\FileInterface;
11
use Silverback\ApiComponentBundle\Entity\Content\Page;
12
use Silverback\ApiComponentBundle\Entity\Layout\Layout;
13
use Silverback\ApiComponentBundle\Factory\Entity\Content\Component\Form\FormViewFactory;
14
use Silverback\ApiComponentBundle\Imagine\PathResolver;
15
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
16
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
17
use Symfony\Component\Serializer\SerializerAwareInterface;
18
use Symfony\Component\Serializer\SerializerInterface;
19
20
final class ApiNormalizer implements NormalizerInterface, DenormalizerInterface, SerializerAwareInterface
21
{
22
    private $decorated;
23
    private $imagineCacheManager;
24
    private $formViewFactory;
25
    private $pathResolver;
26
    private $em;
27
    private $projectDir;
28
    private $collectionDataProvider;
29
30
    /**
31
     * FileNormalizer constructor.
32
     * @param NormalizerInterface $decorated
33
     * @param CacheManager $imagineCacheManager
34
     * @param FormViewFactory $formViewFactory
35
     * @param PathResolver $pathResolver
36
     * @param EntityManagerInterface $entityManager
37
     * @param ContextAwareCollectionDataProviderInterface $collectionDataProvider
38
     * @param string $projectDir
39
     */
40 10
    public function __construct(
41
        NormalizerInterface $decorated,
42
        CacheManager $imagineCacheManager,
43
        FormViewFactory $formViewFactory,
44
        PathResolver $pathResolver,
45
        EntityManagerInterface $entityManager,
46
        ContextAwareCollectionDataProviderInterface $collectionDataProvider,
47
        string $projectDir = '/'
48
    ) {
49 10
        if (!$decorated instanceof DenormalizerInterface) {
50
            throw new \InvalidArgumentException(sprintf('The decorated normalizer must implement the %s.', DenormalizerInterface::class));
51
        }
52 10
        $this->decorated = $decorated;
53 10
        $this->imagineCacheManager = $imagineCacheManager;
54 10
        $this->formViewFactory = $formViewFactory;
55 10
        $this->pathResolver = $pathResolver;
56 10
        $this->em = $entityManager;
57 10
        $this->collectionDataProvider = $collectionDataProvider;
58 10
        $this->projectDir = $projectDir;
59 10
    }
60
61
    /**
62
     * @param mixed $data
63
     * @param string|null $format
64
     * @return bool
65
     */
66 5
    public function supportsNormalization($data, $format = null): bool
67
    {
68 5
        return $this->decorated->supportsNormalization($data, $format);
69
    }
70
71
    /**
72
     * @param $object
73
     * @param string|null $format
74
     * @param array $context
75
     * @return array|bool|float|int|string
76
     * @throws \Symfony\Component\Serializer\Exception\LogicException
77
     * @throws \Symfony\Component\Serializer\Exception\InvalidArgumentException
78
     * @throws \Symfony\Component\Serializer\Exception\CircularReferenceException
79
     * @throws \ApiPlatform\Core\Exception\ResourceClassNotSupportedException
80
     */
81 6
    public function normalize($object, $format = null, array $context = [])
82
    {
83 6
        if ($object instanceof Page) {
84
            if (!$object->getLayout()) {
85
                $object->setLayout($this->em->getRepository(Layout::class)->findOneBy(['default' => true]));
86
            }
87
        }
88 6
        if ($object instanceof Form && !$object->getForm()) {
89 1
            $object->setForm($this->formViewFactory->create($object));
90
        }
91 6
        if ($object instanceof Collection) {
92
            // We should really find whatever the data provider is currently for the resource instead of just using the default
93
            $object->setCollection($this->collectionDataProvider->getCollection($object->getResource(), 'GET', $context));
94
        }
95 6
        $data = $this->decorated->normalize($object, $format, $context);
96
97 6
        if ($object instanceof FileInterface) {
98 1
            $data = array_merge($data, $this->getFileData($object));
99
        }
100 6
        return $data;
101
    }
102
103
    /**
104
     * @param \Silverback\ApiComponentBundle\Entity\Content\FileInterface $object
105
     * @return array
106
     */
107 1
    private function getFileData(FileInterface $object): array
108
    {
109 1
        $data = [];
110 1
        $filePath = $object->getFilePath();
111 1
        if ($filePath) {
112 1
            if (false !== \exif_imagetype($filePath)) {
113 1
                [$width, $height] = getimagesize($filePath);
114
            } else {
115
                $width = $height = 0;
116
            }
117 1
            $data['width'] = $width;
118 1
            $data['height'] = $height;
119
120 1
            $supported = $this->isImagineSupportedFile($filePath);
121 1
            foreach ($object::getImagineFilters() as $returnKey => $filter) {
122 1
                $data[$returnKey] = $supported ? parse_url(
123 1
                    $this->imagineCacheManager->getBrowserPath($this->pathResolver->resolve($filePath), $filter),
124 1
                    PHP_URL_PATH
125 1
                ) : null;
126
            }
127
128 1
            $data['filePath'] = $this->getPublicPath($filePath);
129
        }
130 1
        return $data;
131
    }
132
133 1
    private function getPublicPath(string $filePath) {
134 1
        $publicPaths = [$this->projectDir, '/public/', '/web/'];
135 1
        foreach ($publicPaths as $path) {
136 1
            if (mb_strpos($filePath, $path) === 0 && $start = \strlen($path)) {
137 1
                $filePath = mb_substr($filePath, $start);
138
            }
139
        }
140 1
        return $filePath;
141
    }
142
143
    /**
144
     * @param mixed $data
145
     * @param string $type
146
     * @param string|null $format
147
     * @return bool
148
     */
149 5
    public function supportsDenormalization($data, $type, $format = null): bool
150
    {
151 5
        return $this->decorated->supportsDenormalization($data, $type, $format);
152
    }
153
154
    /**
155
     * @param mixed $data
156
     * @param string $class
157
     * @param string|null $format
158
     * @param array $context
159
     * @return object
160
     * @throws \Symfony\Component\Serializer\Exception\UnexpectedValueException
161
     * @throws \Symfony\Component\Serializer\Exception\RuntimeException
162
     * @throws \Symfony\Component\Serializer\Exception\LogicException
163
     * @throws \Symfony\Component\Serializer\Exception\InvalidArgumentException
164
     * @throws \Symfony\Component\Serializer\Exception\ExtraAttributesException
165
     * @throws \Symfony\Component\Serializer\Exception\BadMethodCallException
166
     * @throws \InvalidArgumentException
167
     */
168 1
    public function denormalize($data, $class, $format = null, array $context = [])
169
    {
170 1
        $context['allow_extra_attributes'] = $class === Form::class;
171 1
        return $this->decorated->denormalize($data, $class, $format, $context);
172
    }
173
174
    /**
175
     * @param SerializerInterface $serializer
176
     */
177 5
    public function setSerializer(SerializerInterface $serializer)
178
    {
179 5
        if ($this->decorated instanceof SerializerAwareInterface) {
180 5
            $this->decorated->setSerializer($serializer);
181
        }
182 5
    }
183
184
    /**
185
     * @param string $filePath
186
     * @return bool
187
     */
188 3
    public function isImagineSupportedFile(?string $filePath): bool
189
    {
190 3
        if (!$filePath) {
191
            return false;
192
        }
193
        try {
194 3
            $imageType = \exif_imagetype($filePath);
195 1
        } catch (\Exception $e) {
196 1
            return false;
197
        }
198 3
        return \in_array($imageType, [IMAGETYPE_JPEG, IMAGETYPE_JPEG2000, IMAGETYPE_PNG, IMAGETYPE_GIF], true);
199
    }
200
}
201