Passed
Push — develop ( d79e08...dfb521 )
by Daniel
05:19
created

ApiNormalizer::getPublicPath()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 4

Importance

Changes 0
Metric Value
cc 4
eloc 5
nc 3
nop 1
dl 0
loc 8
ccs 6
cts 6
cp 1
crap 4
rs 9.2
c 0
b 0
f 0
1
<?php
2
3
namespace Silverback\ApiComponentBundle\Serializer;
4
5
use ApiPlatform\Core\DataProvider\ContextAwareCollectionDataProviderInterface;
6
use Doctrine\Common\Collections\ArrayCollection;
7
use Doctrine\ORM\EntityManagerInterface;
8
use Liip\ImagineBundle\Imagine\Cache\CacheManager;
9
use Silverback\ApiComponentBundle\Entity\Content\Component\Collection\Collection;
10
use Silverback\ApiComponentBundle\Entity\Content\Component\ComponentLocation;
11
use Silverback\ApiComponentBundle\Entity\Content\Component\Form\Form;
12
use Silverback\ApiComponentBundle\Entity\Content\Dynamic\AbstractDynamicPage;
13
use Silverback\ApiComponentBundle\Entity\Content\FileInterface;
14
use Silverback\ApiComponentBundle\Entity\Content\Page;
15
use Silverback\ApiComponentBundle\Entity\Layout\Layout;
16
use Silverback\ApiComponentBundle\Factory\Entity\Content\Component\Form\FormViewFactory;
17
use Silverback\ApiComponentBundle\Imagine\PathResolver;
18
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
19
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
20
use Symfony\Component\Serializer\SerializerAwareInterface;
21
use Symfony\Component\Serializer\SerializerInterface;
22
23
final class ApiNormalizer implements NormalizerInterface, DenormalizerInterface, SerializerAwareInterface
24
{
25
    private $decorated;
26
    private $imagineCacheManager;
27
    private $formViewFactory;
28
    private $pathResolver;
29
    private $em;
30
    private $projectDir;
31
    private $collectionDataProvider;
32
33
    /**
34
     * FileNormalizer constructor.
35
     * @param NormalizerInterface $decorated
36
     * @param CacheManager $imagineCacheManager
37
     * @param FormViewFactory $formViewFactory
38
     * @param PathResolver $pathResolver
39
     * @param EntityManagerInterface $entityManager
40
     * @param ContextAwareCollectionDataProviderInterface $collectionDataProvider
41
     * @param string $projectDir
42
     */
43 10
    public function __construct(
44
        NormalizerInterface $decorated,
45
        CacheManager $imagineCacheManager,
46
        FormViewFactory $formViewFactory,
47
        PathResolver $pathResolver,
48
        EntityManagerInterface $entityManager,
49
        ContextAwareCollectionDataProviderInterface $collectionDataProvider,
50
        string $projectDir = '/'
51
    ) {
52 10
        if (!$decorated instanceof DenormalizerInterface) {
53
            throw new \InvalidArgumentException(sprintf('The decorated normalizer must implement the %s.', DenormalizerInterface::class));
54
        }
55 10
        $this->decorated = $decorated;
56 10
        $this->imagineCacheManager = $imagineCacheManager;
57 10
        $this->formViewFactory = $formViewFactory;
58 10
        $this->pathResolver = $pathResolver;
59 10
        $this->em = $entityManager;
60 10
        $this->collectionDataProvider = $collectionDataProvider;
61 10
        $this->projectDir = $projectDir;
62 10
    }
63
64
    /**
65
     * @param mixed $data
66
     * @param string|null $format
67
     * @return bool
68
     */
69 5
    public function supportsNormalization($data, $format = null): bool
70
    {
71 5
        return $this->decorated->supportsNormalization($data, $format);
72
    }
73
74
    /**
75
     * @param $object
76
     * @param string|null $format
77
     * @param array $context
78
     * @return array|bool|float|int|string
79
     * @throws \Symfony\Component\Serializer\Exception\LogicException
80
     * @throws \Symfony\Component\Serializer\Exception\InvalidArgumentException
81
     * @throws \Symfony\Component\Serializer\Exception\CircularReferenceException
82
     * @throws \ApiPlatform\Core\Exception\ResourceClassNotSupportedException
83
     */
84 6
    public function normalize($object, $format = null, array $context = [])
85
    {
86 6
        if ($object instanceof Page) {
87
            if (!$object->getLayout()) {
88
                $object->setLayout($this->em->getRepository(Layout::class)->findOneBy(['default' => true]));
89
            }
90
        }
91 6
        if ($object instanceof Form && !$object->getForm()) {
92 1
            $object->setForm($this->formViewFactory->create($object));
93
        }
94 6
        if ($object instanceof Collection) {
95
            // We should really find whatever the data provider is currently for the resource instead of just using the default
96
            $object->setCollection($this->collectionDataProvider->getCollection($object->getResource(), 'GET', $context));
97
        }
98 6
        if ($object instanceof AbstractDynamicPage) {
99
            $collection = new ArrayCollection;
100
            foreach ($object->getCollection() as $item) {
0 ignored issues
show
Bug introduced by
The method getCollection() does not exist on Silverback\ApiComponentB...mic\AbstractDynamicPage. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

100
            foreach ($object->/** @scrutinizer ignore-call */ getCollection() as $item) {

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
101
                if (!$item instanceof ComponentLocation) {
102
                    $item = new ComponentLocation($object, $item);
103
                }
104
                $collection->add($item);
105
            }
106
            $object->setCollection($collection);
0 ignored issues
show
Bug introduced by
The method setCollection() does not exist on Silverback\ApiComponentB...mic\AbstractDynamicPage. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

106
            $object->/** @scrutinizer ignore-call */ 
107
                     setCollection($collection);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
107
        }
108 6
        $data = $this->decorated->normalize($object, $format, $context);
109
110 6
        if ($object instanceof FileInterface) {
111 1
            $data = array_merge($data, $this->getFileData($object));
112
        }
113 6
        return $data;
114
    }
115
116
    /**
117
     * @param \Silverback\ApiComponentBundle\Entity\Content\FileInterface $object
118
     * @return array
119
     */
120 1
    private function getFileData(FileInterface $object): array
121
    {
122 1
        $data = [];
123 1
        $filePath = $object->getFilePath();
124 1
        if ($filePath) {
125 1
            if (false !== \exif_imagetype($filePath)) {
126 1
                [$width, $height] = getimagesize($filePath);
127
            } else {
128
                $width = $height = 0;
129
            }
130 1
            $data['width'] = $width;
131 1
            $data['height'] = $height;
132
133 1
            $supported = $this->isImagineSupportedFile($filePath);
134 1
            foreach ($object::getImagineFilters() as $returnKey => $filter) {
135 1
                $data[$returnKey] = $supported ? parse_url(
136 1
                    $this->imagineCacheManager->getBrowserPath($this->pathResolver->resolve($filePath), $filter),
137 1
                    PHP_URL_PATH
138 1
                ) : null;
139
            }
140
141 1
            $data['filePath'] = $this->getPublicPath($filePath);
142
        }
143 1
        return $data;
144
    }
145
146 1
    private function getPublicPath(string $filePath) {
147 1
        $publicPaths = [$this->projectDir, '/public/', '/web/'];
148 1
        foreach ($publicPaths as $path) {
149 1
            if (mb_strpos($filePath, $path) === 0 && $start = \strlen($path)) {
150 1
                $filePath = mb_substr($filePath, $start);
151
            }
152
        }
153 1
        return $filePath;
154
    }
155
156
    /**
157
     * @param mixed $data
158
     * @param string $type
159
     * @param string|null $format
160
     * @return bool
161
     */
162 5
    public function supportsDenormalization($data, $type, $format = null): bool
163
    {
164 5
        return $this->decorated->supportsDenormalization($data, $type, $format);
165
    }
166
167
    /**
168
     * @param mixed $data
169
     * @param string $class
170
     * @param string|null $format
171
     * @param array $context
172
     * @return object
173
     * @throws \Symfony\Component\Serializer\Exception\UnexpectedValueException
174
     * @throws \Symfony\Component\Serializer\Exception\RuntimeException
175
     * @throws \Symfony\Component\Serializer\Exception\LogicException
176
     * @throws \Symfony\Component\Serializer\Exception\InvalidArgumentException
177
     * @throws \Symfony\Component\Serializer\Exception\ExtraAttributesException
178
     * @throws \Symfony\Component\Serializer\Exception\BadMethodCallException
179
     * @throws \InvalidArgumentException
180
     */
181 1
    public function denormalize($data, $class, $format = null, array $context = [])
182
    {
183 1
        $context['allow_extra_attributes'] = $class === Form::class;
184 1
        return $this->decorated->denormalize($data, $class, $format, $context);
185
    }
186
187
    /**
188
     * @param SerializerInterface $serializer
189
     */
190 5
    public function setSerializer(SerializerInterface $serializer)
191
    {
192 5
        if ($this->decorated instanceof SerializerAwareInterface) {
193 5
            $this->decorated->setSerializer($serializer);
194
        }
195 5
    }
196
197
    /**
198
     * @param string $filePath
199
     * @return bool
200
     */
201 3
    public function isImagineSupportedFile(?string $filePath): bool
202
    {
203 3
        if (!$filePath) {
204
            return false;
205
        }
206
        try {
207 3
            $imageType = \exif_imagetype($filePath);
208 1
        } catch (\Exception $e) {
209 1
            return false;
210
        }
211 3
        return \in_array($imageType, [IMAGETYPE_JPEG, IMAGETYPE_JPEG2000, IMAGETYPE_PNG, IMAGETYPE_GIF], true);
212
    }
213
}
214