Completed
Push — master ( c5da41...e1d486 )
by Pieter
22s queued 14s
created

Apie::getObjectAccess()   A

Complexity

Conditions 5
Paths 4

Size

Total Lines 15
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 10
c 0
b 0
f 0
nc 4
nop 0
dl 0
loc 15
rs 9.6111
1
<?php
2
3
namespace W2w\Lib\Apie;
4
5
use Doctrine\Common\Annotations\Reader;
6
use erasys\OpenApi\Spec\v3\Document;
7
use erasys\OpenApi\Spec\v3\Info;
8
use Psr\Cache\CacheItemPoolInterface;
9
use Symfony\Component\PropertyAccess\PropertyAccessor;
10
use Symfony\Component\PropertyInfo\PropertyTypeExtractorInterface;
11
use Symfony\Component\Serializer\Encoder\DecoderInterface;
12
use Symfony\Component\Serializer\Encoder\EncoderInterface;
13
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface;
14
use Symfony\Component\Serializer\NameConverter\NameConverterInterface;
15
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
16
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
17
use W2w\Lib\Apie\Core\ApieCore;
18
use W2w\Lib\Apie\Core\ApiResourceFacade;
19
use W2w\Lib\Apie\Core\ApiResourceMetadataFactory;
20
use W2w\Lib\Apie\Core\ClassResourceConverter;
21
use W2w\Lib\Apie\Core\Encodings\ChainableFormatRetriever;
22
use W2w\Lib\Apie\Core\IdentifierExtractor;
23
use W2w\Lib\Apie\Core\PluginContainer;
24
use W2w\Lib\Apie\Core\ResourceFactories\ChainableFactory;
25
use W2w\Lib\Apie\Exceptions\BadConfigurationException;
26
use W2w\Lib\Apie\Interfaces\ApiResourceFactoryInterface;
27
use W2w\Lib\Apie\Interfaces\FormatRetrieverInterface;
28
use W2w\Lib\Apie\Interfaces\ResourceSerializerInterface;
29
use W2w\Lib\Apie\OpenApiSchema\OpenApiSpecGenerator;
30
use W2w\Lib\Apie\OpenApiSchema\SchemaGenerator;
31
use W2w\Lib\Apie\PluginInterfaces\AnnotationReaderProviderInterface;
32
use W2w\Lib\Apie\PluginInterfaces\ApieAwareInterface;
33
use W2w\Lib\Apie\PluginInterfaces\ApieConfigInterface;
34
use W2w\Lib\Apie\PluginInterfaces\ApiResourceFactoryProviderInterface;
35
use W2w\Lib\Apie\PluginInterfaces\CacheItemPoolProviderInterface;
36
use W2w\Lib\Apie\PluginInterfaces\EncoderProviderInterface;
37
use W2w\Lib\Apie\PluginInterfaces\NormalizerProviderInterface;
38
use W2w\Lib\Apie\PluginInterfaces\ObjectAccessProviderInterface;
39
use W2w\Lib\Apie\PluginInterfaces\OpenApiEventProviderInterface;
40
use W2w\Lib\Apie\PluginInterfaces\OpenApiInfoProviderInterface;
41
use W2w\Lib\Apie\PluginInterfaces\PropertyInfoExtractorProviderInterface;
42
use W2w\Lib\Apie\PluginInterfaces\ResourceLifeCycleInterface;
43
use W2w\Lib\Apie\PluginInterfaces\ResourceProviderInterface;
44
use W2w\Lib\Apie\PluginInterfaces\SchemaProviderInterface;
45
use W2w\Lib\Apie\PluginInterfaces\SerializerProviderInterface;
46
use W2w\Lib\Apie\PluginInterfaces\SymfonyComponentProviderInterface;
47
use W2w\Lib\Apie\Plugins\Core\CorePlugin;
48
use W2w\Lib\Apie\Plugins\PrimaryKey\PrimaryKeyPlugin;
49
use W2w\Lib\ApieObjectAccessNormalizer\ObjectAccess\CachedObjectAccess;
50
use W2w\Lib\ApieObjectAccessNormalizer\ObjectAccess\GroupedObjectAccess;
51
use W2w\Lib\ApieObjectAccessNormalizer\ObjectAccess\ObjectAccess;
52
use W2w\Lib\ApieObjectAccessNormalizer\ObjectAccess\ObjectAccessInterface;
53
54
final class Apie implements SerializerProviderInterface,
55
    ResourceProviderInterface,
56
    NormalizerProviderInterface,
57
    EncoderProviderInterface,
58
    SymfonyComponentProviderInterface,
59
    CacheItemPoolProviderInterface,
60
    AnnotationReaderProviderInterface,
61
    ApiResourceFactoryProviderInterface,
62
    OpenApiInfoProviderInterface,
63
    ApieConfigInterface,
64
    SchemaProviderInterface,
65
    OpenApiEventProviderInterface,
66
    PropertyInfoExtractorProviderInterface
0 ignored issues
show
Deprecated Code introduced by
The interface W2w\Lib\Apie\PluginInter...ractorProviderInterface has been deprecated: use ObjectAccessProviderInterface instead ( Ignorable by Annotation )

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

66
    /** @scrutinizer ignore-deprecated */ PropertyInfoExtractorProviderInterface

This interface has been deprecated. The supplier of the interface has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the interface will be removed and what other interface to use instead.

Loading history...
67
{
68
    const VERSION = "3.0";
69
70
    /**
71
     * @var bool
72
     */
73
    private $debug;
74
75
    /**
76
     * @var string|null
77
     */
78
    private $cacheFolder;
79
80
    /**
81
     * @var PluginContainer
82
     */
83
    private $pluginContainer;
84
85
    /**
86
     * @var ApieCore
87
     */
88
    private $apieCore;
89
90
    /**
91
     * @var ChainableFactory|null
92
     */
93
    private $chainableFactory;
94
95
    /**
96
     * @var ChainableFormatRetriever|null
97
     */
98
    private $chainableFormatRetriever;
99
100
    /**
101
102
     * @param object[] $plugins
103
     * @param bool $debug
104
     * @param string|null $cacheFolder
105
     * @param bool $addCorePlugin
106
     */
107
    public function __construct(array $plugins, bool $debug = false, ?string $cacheFolder = null, bool $addCorePlugin = true)
108
    {
109
        $this->debug = $debug;
110
        $this->cacheFolder = $cacheFolder;
111
        if ($addCorePlugin) {
112
            $plugins[] = new PrimaryKeyPlugin();
113
            $plugins[] = new CorePlugin();
114
        }
115
        $this->pluginContainer = new PluginContainer($plugins);
116
        $this->pluginContainer->each(
117
            ApieAwareInterface::class,
118
            function (ApieAwareInterface $plugin) {
119
                $plugin->setApie($this);
120
            }
121
        );
122
        $this->apieCore = new ApieCore($this, $this->pluginContainer);
123
    }
124
125
    /**
126
     * Creates a new instance of Apie reusing the services/instances of the current Apie instance.
127
     *
128
     * @param array $plugins
129
     * @return Apie
130
     */
131
    public function createContext(array $plugins = []): self
132
    {
133
        $plugins[] = new PrimaryKeyPlugin();
134
        $plugins[] = $this;
135
        return new Apie($plugins, $this->debug, $this->cacheFolder, false);
136
    }
137
138
    /**
139
     * @return bool
140
     */
141
    public function isDebug(): bool
142
    {
143
        return $this->debug;
144
    }
145
146
    /**
147
     * @return string|null
148
     */
149
    public function getCacheFolder(): ?string
150
    {
151
        return $this->cacheFolder;
152
    }
153
154
    public function getPlugin(string $pluginClass): object
155
    {
156
        return $this->pluginContainer->getPlugin($pluginClass);
157
    }
158
159
    /**
160
     * @return ResourceSerializerInterface
161
     */
162
    public function getResourceSerializer(): ResourceSerializerInterface
163
    {
164
        $serializer = $this->pluginContainer->first(
165
            SerializerProviderInterface::class,
166
            new BadConfigurationException('I have no resource serializer set up')
167
        )->getResourceSerializer();
168
        if (!is_callable([$serializer, 'decodeRequestBody'])) {
169
            @trigger_error(
170
                'Class ' . get_class($serializer) . ' has no method decodeRequestBody and this will be required in Apie version 4',
171
                E_USER_DEPRECATED
172
            );
173
        }
174
        return $serializer;
175
    }
176
177
    /**
178
     * @internal
179
     * @deprecated is only added in CorePlugin, will be removed in 4.0.
180
     * @return iterable
181
     */
182
    public function getResourceLifecycles(): iterable
183
    {
184
        return $this->pluginContainer->getPluginsWithInterface(ResourceLifeCycleInterface::class);
185
    }
186
187
    /**
188
     * Returns a list of Api resources.
189
     *
190
     * @return string[]
191
     */
192
    public function getResources(): array
193
    {
194
        return array_values(array_unique($this->pluginContainer->merge(ResourceProviderInterface::class, 'getResources')));
195
    }
196
197
    /**
198
     * @return NormalizerInterface[]|DenormalizerInterface[]
199
     */
200
    public function getNormalizers(): array
201
    {
202
        return $this->pluginContainer->merge(NormalizerProviderInterface::class, 'getNormalizers');
203
    }
204
205
    /**
206
     * @return EncoderInterface[]|DecoderInterface[]
207
     */
208
    public function getEncoders(): array
209
    {
210
        return $this->pluginContainer->merge(EncoderProviderInterface::class, 'getEncoders');
211
    }
212
213
    public function getClassMetadataFactory(): ClassMetadataFactoryInterface
214
    {
215
        return $this->pluginContainer->first(
216
            SymfonyComponentProviderInterface::class,
217
            new BadConfigurationException('I have no symfony component provider set up')
218
        )->getClassMetadataFactory();
219
    }
220
221
    public function getPropertyConverter(): NameConverterInterface
222
    {
223
        return $this->pluginContainer->first(
224
            SymfonyComponentProviderInterface::class,
225
            new BadConfigurationException('I have no symfony component provider set up')
226
        )->getPropertyConverter();
227
    }
228
229
    public function getPropertyAccessor(): PropertyAccessor
230
    {
231
        return $this->pluginContainer->first(
232
            SymfonyComponentProviderInterface::class,
233
            new BadConfigurationException('I have no symfony component provider set up')
234
        )->getPropertyAccessor();
235
    }
236
237
    public function getPropertyTypeExtractor(): PropertyTypeExtractorInterface
238
    {
239
        return $this->pluginContainer->first(
240
            SymfonyComponentProviderInterface::class,
241
            new BadConfigurationException('I have no symfony component provider set up')
242
        )->getPropertyTypeExtractor();
243
    }
244
245
    public function getCacheItemPool(): CacheItemPoolInterface
246
    {
247
        return $this->pluginContainer->first(
248
            CacheItemPoolProviderInterface::class,
249
            new BadConfigurationException('I have no cache item pool provider set up')
250
        )->getCacheItemPool();
251
    }
252
253
    public function getAnnotationReader(): Reader
254
    {
255
        return $this->pluginContainer->first(
256
            AnnotationReaderProviderInterface::class,
257
            new BadConfigurationException('I have no annotation reader set up')
258
        )->getAnnotationReader();
259
    }
260
261
    public function getFormatRetriever(): FormatRetrieverInterface
262
    {
263
        if (!$this->chainableFormatRetriever) {
264
            $this->chainableFormatRetriever = new ChainableFormatRetriever(
265
                iterator_to_array($this->pluginContainer->combine(EncoderProviderInterface::class, 'getFormatRetriever'))
266
            );
267
        }
268
        return $this->chainableFormatRetriever;
269
    }
270
271
    public function getIdentifierExtractor(): IdentifierExtractor
272
    {
273
        return $this->apieCore->getIdentifierExtractor();
274
    }
275
276
    public function getApiResourceMetadataFactory(): ApiResourceMetadataFactory
277
    {
278
        return $this->apieCore->getApiResourceMetadataFactory();
279
    }
280
281
    public function getApiResourceFacade(): ApiResourceFacade
282
    {
283
        return $this->apieCore->getApiResourceFacade();
284
    }
285
286
    public function getOpenApiSpecGenerator(): OpenApiSpecGenerator
287
    {
288
        return $this->apieCore->getOpenApiSpecGenerator();
289
    }
290
291
    public function getSchemaGenerator(): SchemaGenerator
292
    {
293
        return $this->apieCore->getSchemaGenerator();
294
    }
295
296
    public function getApiResourceFactory(): ApiResourceFactoryInterface
297
    {
298
        if (!$this->chainableFactory) {
299
            $this->chainableFactory = new ChainableFactory(
300
                iterator_to_array($this->pluginContainer->combine(ApiResourceFactoryProviderInterface::class, 'getApiResourceFactory'))
301
            );
302
        }
303
        return $this->chainableFactory;
304
    }
305
306
    public function createInfo(): Info
307
    {
308
        $res = $this->pluginContainer->first(OpenApiInfoProviderInterface::class, null);
309
310
        if (empty($res)) {
311
            return new Info('Apie', Apie::VERSION);
312
        }
313
        return $res->createInfo();
314
    }
315
316
    public function getBaseUrl(): string
317
    {
318
        return $this->pluginContainer->first(ApieConfigInterface::class, new BadConfigurationException('I have no config set up'))->getBaseUrl();
319
    }
320
321
    public function getDefinedStaticData(): array
322
    {
323
        $result = [];
324
        foreach (array_reverse($this->pluginContainer->getPluginsWithInterface(SchemaProviderInterface::class)) as $schemaDefinition) {
325
            foreach ($schemaDefinition->getDefinedStaticData() as $className => $schema) {
326
                $result[$className] = $schema;
327
            }
328
        }
329
        return $result;
330
    }
331
332
    public function getDynamicSchemaLogic(): array
333
    {
334
        $result = [];
335
        foreach (array_reverse($this->pluginContainer->getPluginsWithInterface(SchemaProviderInterface::class)) as $schemaDefinition) {
336
            foreach ($schemaDefinition->getDynamicSchemaLogic() as $className => $callable) {
337
                $result[$className] = $callable;
338
            }
339
        }
340
        return $result;
341
    }
342
343
    public function getClassResourceConverter(): ClassResourceConverter
344
    {
345
        return $this->apieCore->getClassResourceConverter();
346
    }
347
348
    public function onOpenApiDocGenerated(Document $document): Document
349
    {
350
        $this->pluginContainer->each(OpenApiEventProviderInterface::class, function (OpenApiEventProviderInterface $plugin) use (&$document) {
351
            $document = $plugin->onOpenApiDocGenerated($document);
352
        });
353
        return $document;
354
    }
355
356
    /**
357
     * @deprecated  use getObjectAccess instead
358
     */
359
    public function getListExtractors(): array
360
    {
361
        return $this->pluginContainer->merge(PropertyInfoExtractorProviderInterface::class, 'getListExtractors');
362
    }
363
364
    /**
365
     * @deprecated  use getObjectAccess instead
366
     */
367
    public function getTypeExtractors(): array
368
    {
369
        return $this->pluginContainer->merge(PropertyInfoExtractorProviderInterface::class, 'getTypeExtractors');
370
    }
371
372
    /**
373
     * @deprecated  use getObjectAccess instead
374
     */
375
    public function getDescriptionExtractors(): array
376
    {
377
        return $this->pluginContainer->merge(PropertyInfoExtractorProviderInterface::class, 'getDescriptionExtractors');
378
    }
379
380
    /**
381
     * @deprecated  use getObjectAccess instead
382
     */
383
    public function getAccessExtractors(): array
384
    {
385
        return $this->pluginContainer->merge(PropertyInfoExtractorProviderInterface::class, 'getAccessExtractors');
386
    }
387
388
    /**
389
     * @deprecated  use getObjectAccess instead
390
     */
391
    public function getInitializableExtractors(): array
392
    {
393
        return $this->pluginContainer->merge(PropertyInfoExtractorProviderInterface::class, 'getInitializableExtractors');
394
    }
395
396
    public function getObjectAccess(): ObjectAccessInterface
397
    {
398
        $objectAccess = new ObjectAccess();
399
        $objectAccesses = $this->pluginContainer->getPluginsWithInterface(ObjectAccessProviderInterface::class);
400
        if (!empty($objectAccesses)) {
401
            $list = [];
402
            foreach ($objectAccesses as $objectAccessPlugin) {
403
                $list = array_merge($list, $objectAccessPlugin->getObjectAccesses());
404
            }
405
            $objectAccess = new GroupedObjectAccess($objectAccess, $list);
406
        }
407
        if (!$this->debug && $this->cacheFolder) {
408
            return new CachedObjectAccess($objectAccess, $this->getCacheItemPool());
409
        }
410
        return $objectAccess;
411
    }
412
}
413