Passed
Branch 3.0.0 (3c68a7)
by Pieter
04:04
created

CorePlugin   A

Complexity

Total Complexity 18

Size/Duplication

Total Lines 210
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 94
c 1
b 0
f 0
dl 0
loc 210
rs 10
wmc 18

11 Methods

Rating   Name   Duplication   Size   Complexity  
A getEncoders() 0 7 1
A getFormatRetriever() 0 5 1
A getCacheItemPool() 0 3 1
A getClassMetadataFactory() 0 11 2
A getAnnotationReader() 0 15 4
A getApiResourceFactory() 0 5 1
A getResourceSerializer() 0 6 1
A getPropertyAccessor() 0 8 2
A getNormalizers() 0 33 1
A getPropertyTypeExtractor() 0 28 2
A getPropertyConverter() 0 10 2
1
<?php
2
3
namespace W2w\Lib\Apie\Plugins\Core;
4
5
use Doctrine\Common\Annotations\AnnotationReader;
6
use Doctrine\Common\Annotations\AnnotationRegistry;
7
use Doctrine\Common\Annotations\CachedReader;
8
use Doctrine\Common\Annotations\Reader;
9
use Doctrine\Common\Cache\PhpFileCache;
10
use Psr\Cache\CacheItemPoolInterface;
11
use Symfony\Component\Cache\Adapter\ArrayAdapter;
12
use Symfony\Component\PropertyAccess\PropertyAccess;
13
use Symfony\Component\PropertyAccess\PropertyAccessor;
14
use Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor;
15
use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor;
16
use Symfony\Component\PropertyInfo\Extractor\SerializerExtractor;
17
use Symfony\Component\PropertyInfo\PropertyInfoExtractor;
18
use Symfony\Component\PropertyInfo\PropertyTypeExtractorInterface;
19
use Symfony\Component\Serializer\Encoder\JsonDecode;
20
use Symfony\Component\Serializer\Encoder\JsonEncode;
21
use Symfony\Component\Serializer\Encoder\JsonEncoder;
22
use Symfony\Component\Serializer\Encoder\XmlEncoder;
23
use Symfony\Component\Serializer\Mapping\ClassDiscriminatorFromClassMetadata;
24
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory;
25
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface;
26
use Symfony\Component\Serializer\Mapping\Loader\AnnotationLoader;
27
use Symfony\Component\Serializer\Mapping\Loader\LoaderChain;
28
use Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter;
29
use Symfony\Component\Serializer\NameConverter\MetadataAwareNameConverter;
30
use Symfony\Component\Serializer\NameConverter\NameConverterInterface;
31
use Symfony\Component\Serializer\Normalizer\ArrayDenormalizer;
32
use Symfony\Component\Serializer\Normalizer\JsonSerializableNormalizer;
33
use Symfony\Component\Serializer\Serializer;
34
use W2w\Lib\Apie\Interfaces\ApiResourceFactoryInterface;
35
use W2w\Lib\Apie\Interfaces\FormatRetrieverInterface;
36
use W2w\Lib\Apie\Interfaces\ResourceSerializerInterface;
37
use W2w\Lib\Apie\PluginInterfaces\AnnotationReaderProviderInterface;
38
use W2w\Lib\Apie\PluginInterfaces\ApieAwareInterface;
39
use W2w\Lib\Apie\PluginInterfaces\ApieAwareTrait;
40
use W2w\Lib\Apie\PluginInterfaces\ApiResourceFactoryProviderInterface;
41
use W2w\Lib\Apie\PluginInterfaces\CacheItemPoolProviderInterface;
42
use W2w\Lib\Apie\PluginInterfaces\EncoderProviderInterface;
43
use W2w\Lib\Apie\PluginInterfaces\NormalizerProviderInterface;
44
use W2w\Lib\Apie\PluginInterfaces\SerializerProviderInterface;
45
use W2w\Lib\Apie\PluginInterfaces\SymfonyComponentProviderInterface;
46
use W2w\Lib\Apie\Plugins\Core\Encodings\FormatRetriever;
47
use W2w\Lib\Apie\Plugins\Core\ResourceFactories\FallbackFactory;
48
use W2w\Lib\Apie\Plugins\Core\Serializers\Mapping\BaseGroupLoader;
49
use W2w\Lib\Apie\Plugins\Core\Normalizers\ApieObjectNormalizer;
50
use W2w\Lib\Apie\Plugins\Core\Normalizers\ContextualNormalizer;
51
use W2w\Lib\Apie\Plugins\Core\Normalizers\EvilReflectionPropertyNormalizer;
52
use W2w\Lib\Apie\Plugins\Core\Normalizers\ExceptionNormalizer;
53
use W2w\Lib\Apie\Plugins\Core\Serializers\SymfonySerializerAdapter;
54
55
/**
56
 * Plugin with most default functionality.
57
 */
58
class CorePlugin implements SerializerProviderInterface,
59
    ApieAwareInterface,
60
    NormalizerProviderInterface,
61
    EncoderProviderInterface,
62
    SymfonyComponentProviderInterface,
63
    CacheItemPoolProviderInterface,
64
    AnnotationReaderProviderInterface,
65
    ApiResourceFactoryProviderInterface
66
{
67
    use ApieAwareTrait;
68
69
    private $classMetadataFactory;
70
71
    private $propertyConverter;
72
73
    private $propertyAccessor;
74
75
    private $propertyTypeExtractor;
76
77
    private $annotationReader;
78
79
    /**
80
     * {@inheritDoc}
81
     */
82
    public function getResourceSerializer(): ResourceSerializerInterface
83
    {
84
        $normalizers = $this->getApie()->getNormalizers();
85
        $encoders = $this->getApie()->getEncoders();
86
        $serializer = new Serializer($normalizers, $encoders);
87
        return new SymfonySerializerAdapter($serializer, $this->getApie()->getFormatRetriever());
88
    }
89
90
    /**
91
     * {@inheritDoc}
92
     */
93
    public function getNormalizers(): array
94
    {
95
        $classMetadataFactory = $this->getApie()->getClassMetadataFactory();
96
97
        $classDiscriminator = new ClassDiscriminatorFromClassMetadata($classMetadataFactory);
98
99
        $objectNormalizer = new ApieObjectNormalizer(
100
            $classMetadataFactory,
101
            $this->getApie()->getPropertyConverter(),
102
            $this->getApie()->getPropertyAccessor(),
103
            $this->getApie()->getPropertyTypeExtractor(),
104
            $classDiscriminator,
105
            null,
106
            []
107
        );
108
        $evilObjectNormalizer = new EvilReflectionPropertyNormalizer(
109
            $classMetadataFactory,
110
            $this->getApie()->getPropertyConverter(),
111
            $this->getApie()->getPropertyAccessor(),
112
            $this->getApie()->getPropertyTypeExtractor(),
113
            $classDiscriminator,
114
            null,
115
            []
116
        );
117
        ContextualNormalizer::disableDenormalizer(EvilReflectionPropertyNormalizer::class);
118
        ContextualNormalizer::disableNormalizer(EvilReflectionPropertyNormalizer::class);
119
120
        return [
0 ignored issues
show
introduced by
The expression return array(new W2w\Lib...r)), $objectNormalizer) returns an array which contains values of type W2w\Lib\Apie\Plugins\Cor...ers\ExceptionNormalizer which are incompatible with the return type Symfony\Component\Serial...r\DenormalizerInterface mandated by W2w\Lib\Apie\PluginInter...rface::getNormalizers().
Loading history...
121
            new ExceptionNormalizer($this->getApie()->isDebug()),
122
            new JsonSerializableNormalizer(),
123
            new ArrayDenormalizer(),
124
            new ContextualNormalizer([$evilObjectNormalizer]),
125
            $objectNormalizer
126
        ];
127
128
    }
129
130
    /**
131
     * {@inheritDoc}
132
     */
133
    public function getClassMetadataFactory(): ClassMetadataFactoryInterface
134
    {
135
        if (!$this->classMetadataFactory) {
136
            $this->classMetadataFactory = new ClassMetadataFactory(
137
                new LoaderChain([
138
                    new AnnotationLoader($this->getApie()->getAnnotationReader()),
139
                    new BaseGroupLoader(['read', 'write', 'get', 'post', 'put']),
140
                ])
141
            );
142
        }
143
        return $this->classMetadataFactory;
144
    }
145
146
    /**
147
     * {@inheritDoc}
148
     */
149
    public function getPropertyConverter(): NameConverterInterface
150
    {
151
        if (!$this->propertyConverter) {
152
            $classMetadataFactory = $this->getApie()->getClassMetadataFactory();
153
            $this->propertyConverter = new MetadataAwareNameConverter(
154
                $classMetadataFactory,
155
                new CamelCaseToSnakeCaseNameConverter()
156
            );
157
        }
158
        return $this->propertyConverter;
159
    }
160
161
    /**
162
     * {@inheritDoc}
163
     */
164
    public function getPropertyAccessor(): PropertyAccessor
165
    {
166
        if (!$this->propertyAccessor) {
167
            $this->propertyAccessor = PropertyAccess::createPropertyAccessorBuilder()
168
                ->setCacheItemPool($this->getApie()->getCacheItemPool())
169
                ->getPropertyAccessor();
170
        }
171
        return $this->propertyAccessor;
172
    }
173
174
    /**
175
     * {@inheritDoc}
176
     */
177
    public function getPropertyTypeExtractor(): PropertyTypeExtractorInterface
178
    {
179
        if (!$this->propertyTypeExtractor) {
180
            $factory = $this->getApie()->getClassMetadataFactory();
181
            $reflectionExtractor = new ReflectionExtractor();
182
            $phpDocExtractor = new PhpDocExtractor();
183
184
            $this->propertyTypeExtractor = new PropertyInfoExtractor(
185
                [
186
                    new SerializerExtractor($factory),
187
                    $reflectionExtractor,
188
                ],
189
                [
190
                    $phpDocExtractor,
191
                    $reflectionExtractor,
192
                ],
193
                [
194
                    $phpDocExtractor,
195
                ],
196
                [
197
                    $reflectionExtractor,
198
                ],
199
                [
200
                    $reflectionExtractor,
201
                ]
202
            );
203
        }
204
        return $this->propertyTypeExtractor;
205
    }
206
207
    /**
208
     * {@inheritDoc}
209
     */
210
    public function getCacheItemPool(): CacheItemPoolInterface
211
    {
212
        return new ArrayAdapter(0, true);
213
    }
214
215
    /**
216
     * {@inheritDoc}
217
     */
218
    public function getAnnotationReader(): Reader
219
    {
220
        if (!$this->annotationReader) {
221
            /** @scrutinizer ignore-deprecated */AnnotationRegistry::registerLoader('class_exists');
222
            if (class_exists(PhpFileCache::class) && $this->getApie()->getCacheFolder()) {
223
                $this->annotationReader = new CachedReader(
224
                    new AnnotationReader(),
225
                    new PhpFileCache($this->getApie()->getCacheFolder() . DIRECTORY_SEPARATOR . '/doctrine-cache'),
226
                    $this->getApie()->isDebug()
227
                );
228
            } else {
229
                $this->annotationReader = new AnnotationReader();
230
            }
231
        }
232
        return $this->annotationReader;
233
    }
234
235
    /**
236
     * {@inheritDoc}
237
     */
238
    public function getEncoders(): array
239
    {
240
        return [
241
            new XmlEncoder([XmlEncoder::ROOT_NODE_NAME => 'item']),
242
            new JsonEncoder(
243
                new JsonEncode([JsonEncode::OPTIONS => JSON_UNESCAPED_SLASHES]),
244
                new JsonDecode([JsonDecode::ASSOCIATIVE => false])
245
            )
246
        ];
247
    }
248
249
    /**
250
     * {@inheritDoc}
251
     */
252
    public function getFormatRetriever(): FormatRetrieverInterface
253
    {
254
        return new FormatRetriever([
255
            'application/json' => 'json',
256
            'application/xml' => 'xml',
257
        ]);
258
    }
259
260
    /**
261
     * {@inheritDoc}
262
     */
263
    public function getApiResourceFactory(): ApiResourceFactoryInterface
264
    {
265
        return new FallbackFactory(
266
            $this->getApie()->getPropertyAccessor(),
267
            $this->getApie()->getIdentifierExtractor()
268
        );
269
    }
270
}
271