Passed
Branch 3.0.0 (98e096)
by Pieter
02:47
created

CorePlugin::getNormalizers()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 33
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 24
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 33
rs 9.536
1
<?php
2
3
namespace W2w\Lib\Apie\Plugins;
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\DenormalizerInterface;
33
use Symfony\Component\Serializer\Normalizer\JsonSerializableNormalizer;
34
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
35
use Symfony\Component\Serializer\Serializer;
36
use W2w\Lib\Apie\ApiResources\ApplicationInfo;
37
use W2w\Lib\Apie\ApiResources\Status;
38
use W2w\Lib\Apie\BaseGroupLoader;
39
use W2w\Lib\Apie\Encodings\FormatRetriever;
40
use W2w\Lib\Apie\Encodings\FormatRetrieverInterface;
41
use W2w\Lib\Apie\Normalizers\ApieObjectNormalizer;
42
use W2w\Lib\Apie\Normalizers\ContextualNormalizer;
43
use W2w\Lib\Apie\Normalizers\EvilReflectionPropertyNormalizer;
44
use W2w\Lib\Apie\Normalizers\ExceptionNormalizer;
45
use W2w\Lib\Apie\PluginInterfaces\AnnotationReaderProviderInterface;
46
use W2w\Lib\Apie\PluginInterfaces\ApieAwareInterface;
47
use W2w\Lib\Apie\PluginInterfaces\ApieAwareTrait;
48
use W2w\Lib\Apie\PluginInterfaces\ApiResourceFactoryProviderInterface;
49
use W2w\Lib\Apie\PluginInterfaces\CacheItemPoolProviderInterface;
50
use W2w\Lib\Apie\PluginInterfaces\EncoderProviderInterface;
51
use W2w\Lib\Apie\PluginInterfaces\NormalizerProviderInterface;
52
use W2w\Lib\Apie\PluginInterfaces\ResourceProviderInterface;
53
use W2w\Lib\Apie\PluginInterfaces\SerializerProviderInterface;
54
use W2w\Lib\Apie\PluginInterfaces\SymfonyComponentProviderInterface;
55
use W2w\Lib\Apie\ResourceFactories\ApiResourceFactoryInterface;
56
use W2w\Lib\Apie\ResourceFactories\FallbackFactory;
57
use W2w\Lib\Apie\Serializers\ResourceSerializerInterface;
58
use W2w\Lib\Apie\Serializers\SymfonySerializerAdapter;
59
60
class CorePlugin implements SerializerProviderInterface, ResourceProviderInterface, ApieAwareInterface, NormalizerProviderInterface, EncoderProviderInterface, SymfonyComponentProviderInterface, CacheItemPoolProviderInterface, AnnotationReaderProviderInterface, ApiResourceFactoryProviderInterface
61
{
62
    use ApieAwareTrait;
63
64
    private $classMetadataFactory;
65
66
    private $propertyConverter;
67
68
    private $propertyAccessor;
69
70
    private $propertyTypeExtractor;
71
72
    private $annotationReader;
73
74
    /**
75
     * Returns a list of Api resources.
76
     *
77
     * @return string[]
78
     */
79
    public function getResources(): array
80
    {
81
        return [ApplicationInfo::class, Status::class];
82
    }
83
84
    public function getResourceSerializer(): ResourceSerializerInterface
85
    {
86
        $normalizers = $this->getApie()->getNormalizers();
87
        $encoders = $this->getApie()->getEncoders();
88
        $serializer = new Serializer($normalizers, $encoders);
89
        return new SymfonySerializerAdapter($serializer, $this->getApie()->getFormatRetriever());
90
    }
91
92
    /**
93
     * @return NormalizerInterface[]|DenormalizerInterface[]
94
     */
95
    public function getNormalizers(): array
96
    {
97
        $classMetadataFactory = $this->getApie()->getClassMetadataFactory();
98
99
        $classDiscriminator = new ClassDiscriminatorFromClassMetadata($classMetadataFactory);
100
101
        $objectNormalizer = new ApieObjectNormalizer(
102
            $classMetadataFactory,
103
            $this->getApie()->getPropertyConverter(),
104
            $this->getApie()->getPropertyAccessor(),
105
            $this->getApie()->getPropertyTypeExtractor(),
106
            $classDiscriminator,
107
            null,
108
            []
109
        );
110
        $evilObjectNormalizer = new EvilReflectionPropertyNormalizer(
111
            $classMetadataFactory,
112
            $this->getApie()->getPropertyConverter(),
113
            $this->getApie()->getPropertyAccessor(),
114
            $this->getApie()->getPropertyTypeExtractor(),
115
            $classDiscriminator,
116
            null,
117
            []
118
        );
119
        ContextualNormalizer::disableDenormalizer(EvilReflectionPropertyNormalizer::class);
120
        ContextualNormalizer::disableNormalizer(EvilReflectionPropertyNormalizer::class);
121
122
        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\Normalizers\ExceptionNormalizer which are incompatible with the return type Symfony\Component\Serial...r\DenormalizerInterface mandated by W2w\Lib\Apie\PluginInter...rface::getNormalizers().
Loading history...
123
            new ExceptionNormalizer($this->getApie()->isDebug()),
124
            new JsonSerializableNormalizer(),
125
            new ArrayDenormalizer(),
126
            new ContextualNormalizer([$evilObjectNormalizer]),
127
            $objectNormalizer
128
        ];
129
130
    }
131
132
    public function getClassMetadataFactory(): ClassMetadataFactoryInterface
133
    {
134
        if (!$this->classMetadataFactory) {
135
            $this->classMetadataFactory = new ClassMetadataFactory(
136
                new LoaderChain([
137
                    new AnnotationLoader($this->getApie()->getAnnotationReader()),
138
                    new BaseGroupLoader(['read', 'write', 'get', 'post', 'put']),
139
                ])
140
            );
141
        }
142
        return $this->classMetadataFactory;
143
    }
144
145
    public function getPropertyConverter(): NameConverterInterface
146
    {
147
        if (!$this->propertyConverter) {
148
            $classMetadataFactory = $this->getApie()->getClassMetadataFactory();
149
            $this->propertyConverter = new MetadataAwareNameConverter(
150
                $classMetadataFactory,
151
                new CamelCaseToSnakeCaseNameConverter()
152
            );
153
        }
154
        return $this->propertyConverter;
155
    }
156
157
    public function getPropertyAccessor(): PropertyAccessor
158
    {
159
        if (!$this->propertyAccessor) {
160
            $this->propertyAccessor = PropertyAccess::createPropertyAccessorBuilder()
161
                ->setCacheItemPool($this->getApie()->getCacheItemPool())
162
                ->getPropertyAccessor();
163
        }
164
        return $this->propertyAccessor;
165
    }
166
167
    public function getPropertyTypeExtractor(): PropertyTypeExtractorInterface
168
    {
169
        if (!$this->propertyTypeExtractor) {
170
            $factory = $this->getApie()->getClassMetadataFactory();
171
            $reflectionExtractor = new ReflectionExtractor();
172
            $phpDocExtractor = new PhpDocExtractor();
173
174
            $this->propertyTypeExtractor = new PropertyInfoExtractor(
175
                [
176
                    new SerializerExtractor($factory),
177
                    $reflectionExtractor,
178
                ],
179
                [
180
                    $phpDocExtractor,
181
                    $reflectionExtractor,
182
                ],
183
                [
184
                    $phpDocExtractor,
185
                ],
186
                [
187
                    $reflectionExtractor,
188
                ],
189
                [
190
                    $reflectionExtractor,
191
                ]
192
            );
193
        }
194
        return $this->propertyTypeExtractor;
195
    }
196
197
    public function getCacheItemPool(): CacheItemPoolInterface
198
    {
199
        return new ArrayAdapter(0, true);
200
    }
201
202
    /**
203
     * @return Reader
204
     */
205
    public function getAnnotationReader(): Reader
206
    {
207
        if (!$this->annotationReader) {
208
            /** @scrutinizer ignore-deprecated */AnnotationRegistry::registerLoader('class_exists');
209
            if (class_exists(PhpFileCache::class) && $this->getApie()->getCacheFolder()) {
210
                $this->annotationReader = new CachedReader(
211
                    new AnnotationReader(),
212
                    new PhpFileCache($this->getCacheFolder() . DIRECTORY_SEPARATOR . '/doctrine-cache'),
0 ignored issues
show
Bug introduced by
The method getCacheFolder() does not exist on W2w\Lib\Apie\Plugins\CorePlugin. ( Ignorable by Annotation )

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

212
                    new PhpFileCache($this->/** @scrutinizer ignore-call */ getCacheFolder() . DIRECTORY_SEPARATOR . '/doctrine-cache'),

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...
213
                    $this->isDebug()
0 ignored issues
show
Bug introduced by
The method isDebug() does not exist on W2w\Lib\Apie\Plugins\CorePlugin. ( Ignorable by Annotation )

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

213
                    $this->/** @scrutinizer ignore-call */ 
214
                           isDebug()

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...
214
                );
215
            } else {
216
                $this->annotationReader = new AnnotationReader();
217
            }
218
        }
219
        return $this->annotationReader;
220
    }
221
222
    public function getEncoders(): array
223
    {
224
        return [
225
            new XmlEncoder([XmlEncoder::ROOT_NODE_NAME => 'item']),
226
            new JsonEncoder(
227
                new JsonEncode([JsonEncode::OPTIONS => JSON_UNESCAPED_SLASHES]),
228
                new JsonDecode([JsonDecode::ASSOCIATIVE => false])
229
            )
230
        ];
231
    }
232
233
    public function getFormatRetriever(): FormatRetrieverInterface
234
    {
235
        return new FormatRetriever([
236
            'application/json' => 'json',
237
            'application/xml' => 'xml',
238
        ]);
239
    }
240
241
    public function getApiResourceFactory(): ApiResourceFactoryInterface
242
    {
243
        return new FallbackFactory(
244
            $this->getApie()->getPropertyAccessor(),
245
            $this->getApie()->getIdentifierExtractor(),
246
            $this->getApie()->isDebug()
247
        );
248
    }
249
}
250