• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

api-platform / core / 10618078048

29 Aug 2024 03:28PM UTC coverage: 7.687% (-0.003%) from 7.69%
10618078048

push

github

web-flow
fix(laravel): cache metadata, add trace on debug mode (#6555)

0 of 143 new or added lines in 8 files covered. (0.0%)

3 existing lines in 1 file now uncovered.

12488 of 162451 relevant lines covered (7.69%)

22.92 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/Laravel/ApiPlatformProvider.php
1
<?php
2

3
/*
4
 * This file is part of the API Platform project.
5
 *
6
 * (c) Kévin Dunglas <dunglas@gmail.com>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11

12
declare(strict_types=1);
13

14
namespace ApiPlatform\Laravel;
15

16
use ApiPlatform\Documentation\Action\DocumentationAction;
17
use ApiPlatform\Documentation\Action\EntrypointAction;
18
use ApiPlatform\GraphQl\Error\ErrorHandler as GraphQlErrorHandler;
19
use ApiPlatform\GraphQl\Error\ErrorHandlerInterface;
20
use ApiPlatform\GraphQl\Executor;
21
use ApiPlatform\GraphQl\ExecutorInterface;
22
use ApiPlatform\GraphQl\Resolver\Factory\ResolverFactory;
23
use ApiPlatform\GraphQl\Resolver\Factory\ResolverFactoryInterface;
24
use ApiPlatform\GraphQl\Resolver\ResourceFieldResolver;
25
use ApiPlatform\GraphQl\Serializer\Exception\ErrorNormalizer as GraphQlErrorNormalizer;
26
use ApiPlatform\GraphQl\Serializer\Exception\HttpExceptionNormalizer as GraphQlHttpExceptionNormalizer;
27
use ApiPlatform\GraphQl\Serializer\Exception\RuntimeExceptionNormalizer as GraphQlRuntimeExceptionNormalizer;
28
use ApiPlatform\GraphQl\Serializer\Exception\ValidationExceptionNormalizer as GraphQlValidationExceptionNormalizer;
29
use ApiPlatform\GraphQl\Serializer\ItemNormalizer as GraphQlItemNormalizer;
30
use ApiPlatform\GraphQl\Serializer\ObjectNormalizer as GraphQlObjectNormalizer;
31
use ApiPlatform\GraphQl\Serializer\SerializerContextBuilder as GraphQlSerializerContextBuilder;
32
use ApiPlatform\GraphQl\State\Processor\NormalizeProcessor;
33
use ApiPlatform\GraphQl\State\Provider\DenormalizeProvider as GraphQlDenormalizeProvider;
34
use ApiPlatform\GraphQl\State\Provider\ReadProvider as GraphQlReadProvider;
35
use ApiPlatform\GraphQl\State\Provider\ResolverProvider;
36
use ApiPlatform\GraphQl\Type\ContextAwareTypeBuilderInterface;
37
use ApiPlatform\GraphQl\Type\FieldsBuilder;
38
use ApiPlatform\GraphQl\Type\FieldsBuilderEnumInterface;
39
use ApiPlatform\GraphQl\Type\SchemaBuilder;
40
use ApiPlatform\GraphQl\Type\SchemaBuilderInterface;
41
use ApiPlatform\GraphQl\Type\TypeBuilder;
42
use ApiPlatform\GraphQl\Type\TypeConverter;
43
use ApiPlatform\GraphQl\Type\TypeConverterInterface;
44
use ApiPlatform\GraphQl\Type\TypesContainer;
45
use ApiPlatform\GraphQl\Type\TypesContainerInterface;
46
use ApiPlatform\GraphQl\Type\TypesFactory;
47
use ApiPlatform\GraphQl\Type\TypesFactoryInterface;
48
use ApiPlatform\Hydra\JsonSchema\SchemaFactory as HydraSchemaFactory;
49
use ApiPlatform\Hydra\Serializer\CollectionNormalizer as HydraCollectionNormalizer;
50
use ApiPlatform\Hydra\Serializer\DocumentationNormalizer as HydraDocumentationNormalizer;
51
use ApiPlatform\Hydra\Serializer\EntrypointNormalizer as HydraEntrypointNormalizer;
52
use ApiPlatform\Hydra\State\HydraLinkProcessor;
53
use ApiPlatform\JsonApi\JsonSchema\SchemaFactory as JsonApiSchemaFactory;
54
use ApiPlatform\JsonApi\Serializer\CollectionNormalizer as JsonApiCollectionNormalizer;
55
use ApiPlatform\JsonApi\Serializer\EntrypointNormalizer as JsonApiEntrypointNormalizer;
56
use ApiPlatform\JsonApi\Serializer\ItemNormalizer as JsonApiItemNormalizer;
57
use ApiPlatform\JsonApi\Serializer\ObjectNormalizer as JsonApiObjectNormalizer;
58
use ApiPlatform\JsonApi\Serializer\ReservedAttributeNameConverter;
59
use ApiPlatform\JsonApi\State\JsonApiProvider;
60
use ApiPlatform\JsonLd\Action\ContextAction;
61
use ApiPlatform\JsonLd\AnonymousContextBuilderInterface;
62
use ApiPlatform\JsonLd\ContextBuilder as JsonLdContextBuilder;
63
use ApiPlatform\JsonLd\ContextBuilderInterface;
64
use ApiPlatform\JsonLd\Serializer\ItemNormalizer as JsonLdItemNormalizer;
65
use ApiPlatform\JsonLd\Serializer\ObjectNormalizer as JsonLdObjectNormalizer;
66
use ApiPlatform\JsonSchema\DefinitionNameFactory;
67
use ApiPlatform\JsonSchema\DefinitionNameFactoryInterface;
68
use ApiPlatform\JsonSchema\Metadata\Property\Factory\SchemaPropertyMetadataFactory;
69
use ApiPlatform\JsonSchema\SchemaFactory;
70
use ApiPlatform\JsonSchema\SchemaFactoryInterface;
71
use ApiPlatform\Laravel\ApiResource\Error;
72
use ApiPlatform\Laravel\Controller\ApiPlatformController;
73
use ApiPlatform\Laravel\Eloquent\Extension\FilterQueryExtension;
74
use ApiPlatform\Laravel\Eloquent\Extension\QueryExtensionInterface;
75
use ApiPlatform\Laravel\Eloquent\Filter\FilterInterface as EloquentFilterInterface;
76
use ApiPlatform\Laravel\Eloquent\Filter\SearchFilter;
77
use ApiPlatform\Laravel\Eloquent\Metadata\Factory\Property\EloquentAttributePropertyMetadataFactory;
78
use ApiPlatform\Laravel\Eloquent\Metadata\Factory\Property\EloquentPropertyMetadataFactory;
79
use ApiPlatform\Laravel\Eloquent\Metadata\Factory\Property\EloquentPropertyNameCollectionMetadataFactory;
80
use ApiPlatform\Laravel\Eloquent\Metadata\Factory\Resource\EloquentResourceCollectionMetadataFactory;
81
use ApiPlatform\Laravel\Eloquent\Metadata\IdentifiersExtractor as EloquentIdentifiersExtractor;
82
use ApiPlatform\Laravel\Eloquent\Metadata\ModelMetadata;
83
use ApiPlatform\Laravel\Eloquent\Metadata\ResourceClassResolver as EloquentResourceClassResolver;
84
use ApiPlatform\Laravel\Eloquent\PropertyAccess\PropertyAccessor as EloquentPropertyAccessor;
85
use ApiPlatform\Laravel\Eloquent\Serializer\SerializerContextBuilder as EloquentSerializerContextBuilder;
86
use ApiPlatform\Laravel\Eloquent\Serializer\SnakeCaseToCamelCaseNameConverter;
87
use ApiPlatform\Laravel\Eloquent\State\CollectionProvider;
88
use ApiPlatform\Laravel\Eloquent\State\ItemProvider;
89
use ApiPlatform\Laravel\Eloquent\State\LinksHandler;
90
use ApiPlatform\Laravel\Eloquent\State\LinksHandlerInterface;
91
use ApiPlatform\Laravel\Eloquent\State\PersistProcessor;
92
use ApiPlatform\Laravel\Eloquent\State\RemoveProcessor;
93
use ApiPlatform\Laravel\Exception\ErrorHandler;
94
use ApiPlatform\Laravel\GraphQl\Controller\EntrypointController as GraphQlEntrypointController;
95
use ApiPlatform\Laravel\GraphQl\Controller\GraphiQlController;
96
use ApiPlatform\Laravel\Metadata\CachePropertyMetadataFactory;
97
use ApiPlatform\Laravel\Metadata\CachePropertyNameCollectionMetadataFactory;
98
use ApiPlatform\Laravel\Metadata\CacheResourceCollectionMetadataFactory;
99
use ApiPlatform\Laravel\Metadata\ConcernsPropertyNameCollectionMetadataFactory;
100
use ApiPlatform\Laravel\Metadata\ConcernsResourceMetadataCollectionFactory;
101
use ApiPlatform\Laravel\Metadata\ConcernsResourceNameCollectionFactory;
102
use ApiPlatform\Laravel\Routing\IriConverter;
103
use ApiPlatform\Laravel\Routing\Router as UrlGeneratorRouter;
104
use ApiPlatform\Laravel\Routing\SkolemIriConverter;
105
use ApiPlatform\Laravel\Security\ResourceAccessChecker;
106
use ApiPlatform\Laravel\State\AccessCheckerProvider;
107
use ApiPlatform\Laravel\State\SwaggerUiProcessor;
108
use ApiPlatform\Laravel\State\SwaggerUiProvider;
109
use ApiPlatform\Laravel\State\ValidateProvider;
110
use ApiPlatform\Metadata\Exception\NotExposedHttpException;
111
use ApiPlatform\Metadata\Factory\Property\ClassLevelAttributePropertyNameCollectionFactory;
112
use ApiPlatform\Metadata\FilterInterface;
113
use ApiPlatform\Metadata\IdentifiersExtractor;
114
use ApiPlatform\Metadata\IdentifiersExtractorInterface;
115
use ApiPlatform\Metadata\InflectorInterface;
116
use ApiPlatform\Metadata\IriConverterInterface;
117
use ApiPlatform\Metadata\Operation\Factory\OperationMetadataFactory;
118
use ApiPlatform\Metadata\Operation\Factory\OperationMetadataFactoryInterface;
119
use ApiPlatform\Metadata\Operation\PathSegmentNameGeneratorInterface;
120
use ApiPlatform\Metadata\Operation\UnderscorePathSegmentNameGenerator;
121
use ApiPlatform\Metadata\Property\Factory\AttributePropertyMetadataFactory;
122
use ApiPlatform\Metadata\Property\Factory\PropertyInfoPropertyMetadataFactory;
123
use ApiPlatform\Metadata\Property\Factory\PropertyInfoPropertyNameCollectionFactory;
124
use ApiPlatform\Metadata\Property\Factory\PropertyMetadataFactoryInterface;
125
use ApiPlatform\Metadata\Property\Factory\PropertyNameCollectionFactoryInterface;
126
use ApiPlatform\Metadata\Property\Factory\SerializerPropertyMetadataFactory;
127
use ApiPlatform\Metadata\Resource\Factory\AlternateUriResourceMetadataCollectionFactory;
128
use ApiPlatform\Metadata\Resource\Factory\AttributesResourceMetadataCollectionFactory;
129
use ApiPlatform\Metadata\Resource\Factory\AttributesResourceNameCollectionFactory;
130
use ApiPlatform\Metadata\Resource\Factory\FiltersResourceMetadataCollectionFactory;
131
use ApiPlatform\Metadata\Resource\Factory\FormatsResourceMetadataCollectionFactory;
132
use ApiPlatform\Metadata\Resource\Factory\InputOutputResourceMetadataCollectionFactory;
133
use ApiPlatform\Metadata\Resource\Factory\LinkFactory;
134
use ApiPlatform\Metadata\Resource\Factory\LinkFactoryInterface;
135
use ApiPlatform\Metadata\Resource\Factory\LinkResourceMetadataCollectionFactory;
136
use ApiPlatform\Metadata\Resource\Factory\NotExposedOperationResourceMetadataCollectionFactory;
137
use ApiPlatform\Metadata\Resource\Factory\OperationNameResourceMetadataCollectionFactory;
138
use ApiPlatform\Metadata\Resource\Factory\ParameterResourceMetadataCollectionFactory;
139
use ApiPlatform\Metadata\Resource\Factory\PhpDocResourceMetadataCollectionFactory;
140
use ApiPlatform\Metadata\Resource\Factory\ResourceMetadataCollectionFactoryInterface;
141
use ApiPlatform\Metadata\Resource\Factory\ResourceNameCollectionFactoryInterface;
142
use ApiPlatform\Metadata\Resource\Factory\UriTemplateResourceMetadataCollectionFactory;
143
use ApiPlatform\Metadata\ResourceAccessCheckerInterface;
144
use ApiPlatform\Metadata\ResourceClassResolver;
145
use ApiPlatform\Metadata\ResourceClassResolverInterface;
146
use ApiPlatform\Metadata\UrlGeneratorInterface;
147
use ApiPlatform\Metadata\Util\Inflector;
148
use ApiPlatform\OpenApi\Factory\OpenApiFactory;
149
use ApiPlatform\OpenApi\Factory\OpenApiFactoryInterface;
150
use ApiPlatform\OpenApi\Options;
151
use ApiPlatform\OpenApi\Serializer\OpenApiNormalizer;
152
use ApiPlatform\Serializer\Filter\FilterInterface as SerializerFilterInterface;
153
use ApiPlatform\Serializer\Filter\PropertyFilter;
154
use ApiPlatform\Serializer\ItemNormalizer;
155
use ApiPlatform\Serializer\JsonEncoder;
156
use ApiPlatform\Serializer\Mapping\Factory\ClassMetadataFactory as SerializerClassMetadataFactory;
157
use ApiPlatform\Serializer\Parameter\SerializerFilterParameterProvider;
158
use ApiPlatform\Serializer\SerializerContextBuilder;
159
use ApiPlatform\State\CallableProcessor;
160
use ApiPlatform\State\CallableProvider;
161
use ApiPlatform\State\Pagination\Pagination;
162
use ApiPlatform\State\Pagination\PaginationOptions;
163
use ApiPlatform\State\ParameterProviderInterface;
164
use ApiPlatform\State\Processor\AddLinkHeaderProcessor;
165
use ApiPlatform\State\Processor\RespondProcessor;
166
use ApiPlatform\State\Processor\SerializeProcessor;
167
use ApiPlatform\State\Processor\WriteProcessor;
168
use ApiPlatform\State\ProcessorInterface;
169
use ApiPlatform\State\Provider\ContentNegotiationProvider;
170
use ApiPlatform\State\Provider\DeserializeProvider;
171
use ApiPlatform\State\Provider\ParameterProvider;
172
use ApiPlatform\State\Provider\ReadProvider;
173
use ApiPlatform\State\ProviderInterface;
174
use ApiPlatform\State\SerializerContextBuilderInterface;
175
use Illuminate\Config\Repository as ConfigRepository;
176
use Illuminate\Contracts\Debug\ExceptionHandler as ExceptionHandlerInterface;
177
use Illuminate\Contracts\Foundation\Application;
178
use Illuminate\Contracts\Foundation\CachesRoutes;
179
use Illuminate\Http\Request;
180
use Illuminate\Routing\Route;
181
use Illuminate\Routing\RouteCollection;
182
use Illuminate\Routing\Router;
183
use Illuminate\Support\ServiceProvider;
184
use Negotiation\Negotiator;
185
use phpDocumentor\Reflection\DocBlockFactory;
186
use Psr\Log\LoggerInterface;
187
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
188
use Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor;
189
use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor;
190
use Symfony\Component\PropertyInfo\PropertyInfoExtractor;
191
use Symfony\Component\PropertyInfo\PropertyInfoExtractorInterface;
192
use Symfony\Component\Routing\RequestContext;
193
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory;
194
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface;
195
use Symfony\Component\Serializer\Mapping\Loader\AttributeLoader;
196
use Symfony\Component\Serializer\Mapping\Loader\LoaderInterface;
197
use Symfony\Component\Serializer\NameConverter\MetadataAwareNameConverter;
198
use Symfony\Component\Serializer\NameConverter\NameConverterInterface;
199
use Symfony\Component\Serializer\Normalizer\ArrayDenormalizer;
200
use Symfony\Component\Serializer\Normalizer\DateIntervalNormalizer;
201
use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer;
202
use Symfony\Component\Serializer\Normalizer\DateTimeZoneNormalizer;
203
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
204
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
205
use Symfony\Component\Serializer\Serializer;
206
use Symfony\Component\Serializer\SerializerInterface;
207
use Symfony\Component\WebLink\HttpHeaderSerializer;
208

209
class ApiPlatformProvider extends ServiceProvider
210
{
211
    /**
212
     * Register services.
213
     */
214
    public function register(): void
215
    {
216
        $this->mergeConfigFrom(__DIR__.'/config/api-platform.php', 'api-platform');
×
UNCOV
217
        $defaultContext = [];
×
218

219
        $this->app->singleton(PropertyInfoExtractorInterface::class, function () {
×
220
            $phpDocExtractor = class_exists(DocBlockFactory::class) ? new PhpDocExtractor() : null;
×
221
            $reflectionExtractor = new ReflectionExtractor();
×
222

223
            return new PropertyInfoExtractor(
×
224
                [$reflectionExtractor],
×
225
                $phpDocExtractor ? [$phpDocExtractor, $reflectionExtractor] : [$reflectionExtractor],
×
226
                $phpDocExtractor ? [$phpDocExtractor] : [],
×
227
                [$reflectionExtractor],
×
228
                [$reflectionExtractor]
×
229
            );
×
230
        });
×
231

232
        $this->app->bind(LoaderInterface::class, AttributeLoader::class);
×
233
        $this->app->bind(ClassMetadataFactoryInterface::class, ClassMetadataFactory::class);
×
234
        $this->app->singleton(ClassMetadataFactory::class, function () {
×
235
            return new ClassMetadataFactory(new AttributeLoader());
×
236
        });
×
237

238
        $this->app->singleton(SerializerClassMetadataFactory::class, function (Application $app) {
×
239
            return new SerializerClassMetadataFactory($app->make(ClassMetadataFactoryInterface::class));
×
240
        });
×
241

242
        $this->app->bind(PathSegmentNameGeneratorInterface::class, UnderscorePathSegmentNameGenerator::class);
×
243

NEW
244
        $this->app->singleton(ResourceNameCollectionFactoryInterface::class, function (Application $app) {
×
245
            /** @var ConfigRepository */
NEW
246
            $config = $app['config'];
×
247
            $paths = $config->get('api-platform.resources') ?? [];
×
248
            $refl = new \ReflectionClass(Error::class);
×
249
            $paths[] = \dirname($refl->getFileName());
×
250

251
            return new ConcernsResourceNameCollectionFactory($paths, new AttributesResourceNameCollectionFactory($paths));
×
252
        });
×
253

254
        $this->app->bind(ResourceClassResolverInterface::class, ResourceClassResolver::class);
×
255
        $this->app->singleton(ResourceClassResolver::class, function (Application $app) {
×
256
            return new EloquentResourceClassResolver(new ResourceClassResolver($app->make(ResourceNameCollectionFactoryInterface::class)));
×
257
        });
×
258

259
        $this->app->singleton(PropertyMetadataFactoryInterface::class, function (Application $app) {
×
260
            return new PropertyInfoPropertyMetadataFactory(
×
261
                $app->make(PropertyInfoExtractorInterface::class),
×
262
                new EloquentPropertyMetadataFactory(
×
263
                    $app->make(ModelMetadata::class),
×
264
                )
×
265
            );
×
266
        });
×
267

268
        $this->app->extend(PropertyMetadataFactoryInterface::class, function (PropertyInfoPropertyMetadataFactory $inner, Application $app) {
×
269
            /** @var ConfigRepository */
NEW
270
            $config = $app['config'];
×
271

NEW
272
            return new CachePropertyMetadataFactory(
×
NEW
273
                new SchemaPropertyMetadataFactory(
×
NEW
274
                    $app->make(ResourceClassResolverInterface::class),
×
NEW
275
                    new SerializerPropertyMetadataFactory(
×
NEW
276
                        $app->make(SerializerClassMetadataFactory::class),
×
NEW
277
                        new AttributePropertyMetadataFactory(
×
NEW
278
                            new EloquentAttributePropertyMetadataFactory(
×
NEW
279
                                $inner,
×
NEW
280
                            )
×
NEW
281
                        ),
×
NEW
282
                        $app->make(ResourceClassResolverInterface::class)
×
283
                    ),
×
284
                ),
×
NEW
285
                true === $config->get('app.debug') ? 'array' : 'file'
×
286
            );
×
287
        });
×
288

289
        $this->app->singleton(PropertyNameCollectionFactoryInterface::class, function (Application $app) {
×
290
            /** @var ConfigRepository */
NEW
291
            $config = $app['config'];
×
292

NEW
293
            return new CachePropertyNameCollectionMetadataFactory(
×
NEW
294
                new ClassLevelAttributePropertyNameCollectionFactory(
×
NEW
295
                    new ConcernsPropertyNameCollectionMetadataFactory(
×
NEW
296
                        new EloquentPropertyNameCollectionMetadataFactory(
×
NEW
297
                            $app->make(ModelMetadata::class),
×
NEW
298
                            new PropertyInfoPropertyNameCollectionFactory($app->make(PropertyInfoExtractorInterface::class)),
×
NEW
299
                            $app->make(ResourceClassResolverInterface::class)
×
NEW
300
                        )
×
301
                    )
×
NEW
302
                ),
×
NEW
303
                true === $config->get('app.debug') ? 'array' : 'file'
×
304
            );
×
305
        });
×
306

307
        $this->app->singleton(LinkFactoryInterface::class, function (Application $app) {
×
308
            return new LinkFactory(
×
309
                $app->make(PropertyNameCollectionFactoryInterface::class),
×
310
                $app->make(PropertyMetadataFactoryInterface::class),
×
311
                $app->make(ResourceClassResolverInterface::class),
×
312
            );
×
313
        });
×
314

315
        // TODO: add cached metadata factories
NEW
316
        $this->app->singleton(ResourceMetadataCollectionFactoryInterface::class, function (Application $app) {
×
317
            /** @var ConfigRepository */
NEW
318
            $config = $app['config'];
×
319

NEW
320
            return new CacheResourceCollectionMetadataFactory(
×
NEW
321
                new EloquentResourceCollectionMetadataFactory(
×
NEW
322
                    new ParameterResourceMetadataCollectionFactory(
×
NEW
323
                        $this->app->make(PropertyNameCollectionFactoryInterface::class),
×
NEW
324
                        new AlternateUriResourceMetadataCollectionFactory(
×
NEW
325
                            new FiltersResourceMetadataCollectionFactory(
×
NEW
326
                                new FormatsResourceMetadataCollectionFactory(
×
NEW
327
                                    new InputOutputResourceMetadataCollectionFactory(
×
NEW
328
                                        new PhpDocResourceMetadataCollectionFactory(
×
NEW
329
                                            new OperationNameResourceMetadataCollectionFactory(
×
NEW
330
                                                new LinkResourceMetadataCollectionFactory(
×
331
                                                    $app->make(LinkFactoryInterface::class),
×
NEW
332
                                                    new UriTemplateResourceMetadataCollectionFactory(
×
333
                                                        $app->make(LinkFactoryInterface::class),
×
NEW
334
                                                        $app->make(PathSegmentNameGeneratorInterface::class),
×
NEW
335
                                                        new NotExposedOperationResourceMetadataCollectionFactory(
×
NEW
336
                                                            $app->make(LinkFactoryInterface::class),
×
NEW
337
                                                            new ConcernsResourceMetadataCollectionFactory(
×
NEW
338
                                                                new AttributesResourceMetadataCollectionFactory(
×
NEW
339
                                                                    null,
×
NEW
340
                                                                    $app->make(LoggerInterface::class),
×
NEW
341
                                                                    [
×
NEW
342
                                                                        'routePrefix' => $config->get('api-platform.routes.prefix') ?? '/',
×
NEW
343
                                                                    ],
×
NEW
344
                                                                    $config->get('api-platform.graphql.enabled'),
×
NEW
345
                                                                ),
×
346
                                                                $app->make(LoggerInterface::class),
×
347
                                                                [
×
348
                                                                    'routePrefix' => $config->get('api-platform.routes.prefix') ?? '/',
×
349
                                                                ],
×
350
                                                                $config->get('api-platform.graphql.enabled'),
×
NEW
351
                                                            )
×
352
                                                        )
×
353
                                                    )
×
354
                                                )
×
355
                                            )
×
356
                                        )
×
NEW
357
                                    ),
×
NEW
358
                                    $config->get('api-platform.formats'),
×
NEW
359
                                    $config->get('api-platform.patch_formats'),
×
NEW
360
                                )
×
361
                            )
×
NEW
362
                        ),
×
NEW
363
                        $app->make(FilterInterface::class)
×
NEW
364
                    )
×
NEW
365
                ),
×
NEW
366
                true === $config->get('app.debug') ? 'array' : 'file'
×
367
            );
×
368
        });
×
369

370
        $this->app->bind(PropertyAccessorInterface::class, function () {
×
371
            return new EloquentPropertyAccessor();
×
372
        });
×
373

374
        $this->app->bind(NameConverterInterface::class, function (Application $app) {
×
375
            return new MetadataAwareNameConverter($app->make(ClassMetadataFactoryInterface::class), $app->make(SnakeCaseToCamelCaseNameConverter::class));
×
376
        });
×
377

378
        $this->app->bind(OperationMetadataFactoryInterface::class, OperationMetadataFactory::class);
×
379

380
        $this->app->tag([SearchFilter::class], EloquentFilterInterface::class);
×
381
        $this->app->tag([SearchFilter::class, PropertyFilter::class], FilterInterface::class);
×
382
        $this->app->singleton(FilterInterface::class, function (Application $app) {
×
383
            $tagged = iterator_to_array($app->tagged(FilterInterface::class));
×
384

385
            return new ServiceLocator($tagged);
×
386
        });
×
387

388
        $this->app->bind(FilterQueryExtension::class, function (Application $app) {
×
389
            $tagged = iterator_to_array($app->tagged(EloquentFilterInterface::class));
×
390

391
            return new FilterQueryExtension(new ServiceLocator($tagged));
×
392
        });
×
393

394
        $this->app->tag([FilterQueryExtension::class], QueryExtensionInterface::class);
×
395

396
        $this->app->singleton(ItemProvider::class, function (Application $app) {
×
397
            $tagged = iterator_to_array($app->tagged(LinksHandlerInterface::class));
×
398

399
            return new ItemProvider(new LinksHandler($app), new ServiceLocator($tagged));
×
400
        });
×
401
        $this->app->singleton(CollectionProvider::class, function (Application $app) {
×
402
            $tagged = iterator_to_array($app->tagged(LinksHandlerInterface::class));
×
403

404
            return new CollectionProvider($app->make(Pagination::class), new LinksHandler($app), $app->tagged(QueryExtensionInterface::class), new ServiceLocator($tagged));
×
405
        });
×
406
        $this->app->tag([ItemProvider::class, CollectionProvider::class], ProviderInterface::class);
×
407

408
        $this->app->singleton(CallableProvider::class, function (Application $app) {
×
409
            $tagged = iterator_to_array($app->tagged(ProviderInterface::class));
×
410

411
            return new CallableProvider(new ServiceLocator($tagged));
×
412
        });
×
413

414
        $this->app->singleton(ReadProvider::class, function (Application $app) {
×
415
            return new ReadProvider($app->make(CallableProvider::class));
×
416
        });
×
417

418
        $this->app->singleton(SwaggerUiProvider::class, function (Application $app) {
×
419
            return new SwaggerUiProvider($app->make(ReadProvider::class), $app->make(OpenApiFactoryInterface::class));
×
420
        });
×
421

422
        $this->app->singleton(ValidateProvider::class, function (Application $app) {
×
423
            return new ValidateProvider($app->make(SwaggerUiProvider::class), $app);
×
424
        });
×
425

NEW
426
        $this->app->singleton(JsonApiProvider::class, function (Application $app) {
×
427
            /** @var ConfigRepository */
NEW
428
            $config = $app['config'];
×
429

430
            return new JsonApiProvider($app->make(ValidateProvider::class), $config->get('api-platform.collection.order.parameter_name'));
×
431
        });
×
432

433
        $this->app->singleton(DeserializeProvider::class, function (Application $app) {
×
434
            return new DeserializeProvider($app->make(JsonApiProvider::class), $app->make(SerializerInterface::class), $app->make(SerializerContextBuilderInterface::class));
×
435
        });
×
436

437
        $this->app->tag([PropertyFilter::class], SerializerFilterInterface::class);
×
438

439
        $this->app->singleton(SerializerFilterParameterProvider::class, function (Application $app) {
×
440
            $tagged = iterator_to_array($app->tagged(SerializerFilterInterface::class));
×
441

442
            return new SerializerFilterParameterProvider(new ServiceLocator($tagged));
×
443
        });
×
444

445
        $this->app->tag([SerializerFilterParameterProvider::class], ParameterProviderInterface::class);
×
446

447
        $this->app->singleton(ParameterProvider::class, function (Application $app) {
×
448
            $tagged = iterator_to_array($app->tagged(ParameterProviderInterface::class));
×
449

450
            return new ParameterProvider($app->make(DeserializeProvider::class), new ServiceLocator($tagged));
×
451
        });
×
452

453
        $this->app->singleton(AccessCheckerProvider::class, function (Application $app) {
×
454
            return new AccessCheckerProvider($app->make(ParameterProvider::class), $app->make(ResourceAccessCheckerInterface::class));
×
455
        });
×
456

NEW
457
        $this->app->singleton(Negotiator::class, function (Application $app) {
×
NEW
458
            return new Negotiator();
×
NEW
459
        });
×
NEW
460
        $this->app->singleton(ContentNegotiationProvider::class, function (Application $app) {
×
461
            /** @var ConfigRepository */
NEW
462
            $config = $app['config'];
×
463

464
            return new ContentNegotiationProvider($app->make(AccessCheckerProvider::class), $app->make(Negotiator::class), $config->get('api-platform.formats'), $config->get('api-platform.error_formats'));
×
465
        });
×
466

467
        $this->app->bind(ProviderInterface::class, ContentNegotiationProvider::class);
×
468

469
        $this->app->tag([RemoveProcessor::class, PersistProcessor::class], ProcessorInterface::class);
×
470
        $this->app->singleton(CallableProcessor::class, function (Application $app) {
×
471
            $tagged = iterator_to_array($app->tagged(ProcessorInterface::class));
×
472
            // TODO: tag SwaggerUiProcessor instead?
473
            $tagged['api_platform.swagger_ui.processor'] = $app->make(SwaggerUiProcessor::class);
×
474

475
            return new CallableProcessor(new ServiceLocator($tagged));
×
476
        });
×
477

478
        $this->app->singleton(WriteProcessor::class, function (Application $app) {
×
479
            return new WriteProcessor($app->make(SerializeProcessor::class), $app->make(CallableProcessor::class));
×
480
        });
×
481

NEW
482
        $this->app->singleton(SerializerContextBuilder::class, function (Application $app) {
×
483
            /** @var ConfigRepository */
NEW
484
            $config = $app['config'];
×
485

NEW
486
            return new SerializerContextBuilder($app->make(ResourceMetadataCollectionFactoryInterface::class), $config->get('app.debug'));
×
487
        });
×
488
        $this->app->bind(SerializerContextBuilderInterface::class, EloquentSerializerContextBuilder::class);
×
489
        $this->app->singleton(EloquentSerializerContextBuilder::class, function (Application $app) {
×
490
            return new EloquentSerializerContextBuilder(
×
491
                $app->make(SerializerContextBuilder::class),
×
492
                $app->make(PropertyNameCollectionFactoryInterface::class)
×
493
            );
×
494
        });
×
495

496
        $this->app->singleton(SerializeProcessor::class, function (Application $app) {
×
497
            return new SerializeProcessor($app->make(RespondProcessor::class), $app->make(Serializer::class), $app->make(SerializerContextBuilderInterface::class));
×
498
        });
×
499

500
        $this->app->singleton(HydraLinkProcessor::class, function (Application $app) {
×
501
            return new HydraLinkProcessor($app->make(WriteProcessor::class), $app->make(UrlGeneratorInterface::class));
×
502
        });
×
503

504
        $this->app->singleton(RespondProcessor::class, function () {
×
505
            return new AddLinkHeaderProcessor(new RespondProcessor(), new HttpHeaderSerializer());
×
506
        });
×
507

508
        $this->app->bind(ProcessorInterface::class, HydraLinkProcessor::class);
×
509

510
        $this->app->singleton(ObjectNormalizer::class, function () {
×
511
            return new ObjectNormalizer();
×
512
        });
×
513

514
        $this->app->singleton(DateTimeNormalizer::class, function () {
×
515
            return new DateTimeNormalizer();
×
516
        });
×
517

518
        $this->app->singleton(DateTimeZoneNormalizer::class, function () {
×
519
            return new DateTimeZoneNormalizer();
×
520
        });
×
521

522
        $this->app->singleton(DateIntervalNormalizer::class, function () {
×
523
            return new DateIntervalNormalizer();
×
524
        });
×
525

526
        $this->app->singleton(JsonEncoder::class, function () {
×
527
            return new JsonEncoder('jsonld');
×
528
        });
×
529

530
        $this->app->bind(IriConverterInterface::class, IriConverter::class);
×
531
        $this->app->singleton(IriConverter::class, function (Application $app) {
×
532
            return new IriConverter($app->make(CallableProvider::class), $app->make(OperationMetadataFactoryInterface::class), $app->make(UrlGeneratorRouter::class), $app->make(IdentifiersExtractorInterface::class), $app->make(ResourceClassResolverInterface::class), $app->make(ResourceMetadataCollectionFactoryInterface::class), $app->make(SkolemIriConverter::class));
×
533
        });
×
534

535
        $this->app->singleton(SkolemIriConverter::class, function (Application $app) {
×
536
            return new SkolemIriConverter($app->make(UrlGeneratorRouter::class));
×
537
        });
×
538

539
        $this->app->bind(IdentifiersExtractorInterface::class, IdentifiersExtractor::class);
×
540
        $this->app->singleton(IdentifiersExtractor::class, function (Application $app) {
×
541
            return new EloquentIdentifiersExtractor(
×
542
                new IdentifiersExtractor(
×
543
                    $app->make(ResourceMetadataCollectionFactoryInterface::class),
×
544
                    $app->make(ResourceClassResolverInterface::class),
×
545
                    $app->make(PropertyNameCollectionFactoryInterface::class),
×
546
                    $app->make(PropertyMetadataFactoryInterface::class),
×
547
                    $app->make(PropertyAccessorInterface::class)
×
548
                )
×
549
            );
×
550
        });
×
551

552
        $this->app->bind(UrlGeneratorInterface::class, UrlGeneratorRouter::class);
×
553
        $this->app->singleton(UrlGeneratorRouter::class, function (Application $app) {
×
554
            $request = $app->make('request');
×
555
            // https://github.com/laravel/framework/blob/2bfb70bca53e24227a6f921f39d84ba452efd8e0/src/Illuminate/Routing/CompiledRouteCollection.php#L112
556
            $trimmedRequest = $request->duplicate();
×
557
            $parts = explode('?', $request->server->get('REQUEST_URI'), 2);
×
558
            $trimmedRequest->server->set(
×
559
                'REQUEST_URI',
×
560
                rtrim($parts[0], '/').(isset($parts[1]) ? '?'.$parts[1] : '')
×
561
            );
×
562

563
            $urlGenerator = new UrlGeneratorRouter($app->make(Router::class));
×
564
            $urlGenerator->setContext((new RequestContext())->fromRequest($trimmedRequest));
×
565

566
            return $urlGenerator;
×
567
        });
×
568

569
        $this->app->bind(ContextBuilderInterface::class, JsonLdContextBuilder::class);
×
570
        $this->app->singleton(JsonLdContextBuilder::class, function (Application $app) {
×
571
            return new JsonLdContextBuilder(
×
572
                $app->make(ResourceNameCollectionFactoryInterface::class),
×
573
                $app->make(ResourceMetadataCollectionFactoryInterface::class),
×
574
                $app->make(PropertyNameCollectionFactoryInterface::class),
×
575
                $app->make(PropertyMetadataFactoryInterface::class),
×
576
                $app->make(UrlGeneratorInterface::class),
×
577
                $app->make(IriConverterInterface::class),
×
578
                $app->make(NameConverterInterface::class)
×
579
            );
×
580
        });
×
581

582
        $this->app->singleton(HydraEntrypointNormalizer::class, function (Application $app) {
×
583
            return new HydraEntrypointNormalizer($app->make(ResourceMetadataCollectionFactoryInterface::class), $app->make(IriConverterInterface::class), $app->make(UrlGeneratorInterface::class));
×
584
        });
×
585

586
        $this->app->singleton(ResourceAccessCheckerInterface::class, function () {
×
587
            return new ResourceAccessChecker();
×
588
        });
×
589

590
        $this->app->singleton(ItemNormalizer::class, function (Application $app) use ($defaultContext) {
×
591
            return new ItemNormalizer(
×
592
                $app->make(PropertyNameCollectionFactoryInterface::class),
×
593
                $app->make(PropertyMetadataFactoryInterface::class),
×
594
                $app->make(IriConverterInterface::class),
×
595
                $app->make(ResourceClassResolverInterface::class),
×
596
                $app->make(PropertyAccessorInterface::class),
×
597
                $app->make(NameConverterInterface::class),
×
598
                $app->make(ClassMetadataFactoryInterface::class),
×
599
                $app->make(LoggerInterface::class),
×
600
                $app->make(ResourceMetadataCollectionFactoryInterface::class),
×
601
                $app->make(ResourceAccessCheckerInterface::class),
×
602
                $defaultContext
×
603
            );
×
604
        });
×
605

606
        $this->app->bind(AnonymousContextBuilderInterface::class, JsonLdContextBuilder::class);
×
607

608
        $this->app->singleton(JsonLdObjectNormalizer::class, function (Application $app) {
×
609
            return new JsonLdObjectNormalizer(
×
610
                $app->make(ObjectNormalizer::class),
×
611
                $app->make(IriConverterInterface::class),
×
612
                $app->make(AnonymousContextBuilderInterface::class)
×
613
            );
×
614
        });
×
615

NEW
616
        $this->app->singleton(Options::class, function (Application $app) {
×
617
            /** @var ConfigRepository */
NEW
618
            $config = $app['config'];
×
619

620
            return new Options(title: $config->get('api-platform.title') ?? '');
×
621
        });
×
622

NEW
623
        $this->app->singleton(DocumentationAction::class, function (Application $app) {
×
624
            /** @var ConfigRepository */
NEW
625
            $config = $app['config'];
×
626

627
            return new DocumentationAction($app->make(ResourceNameCollectionFactoryInterface::class), $config->get('api-platform.title') ?? '', $config->get('api-platform.description') ?? '', $config->get('api-platform.version') ?? '', $app->make(OpenApiFactoryInterface::class), $app->make(ProviderInterface::class), $app->make(ProcessorInterface::class), $app->make(Negotiator::class), $config->get('api-platform.docs_formats'));
×
628
        });
×
629

NEW
630
        $this->app->singleton(EntrypointAction::class, function (Application $app) {
×
631
            /** @var ConfigRepository */
NEW
632
            $config = $app['config'];
×
633

634
            return new EntrypointAction($app->make(ResourceNameCollectionFactoryInterface::class), $app->make(ProviderInterface::class), $app->make(ProcessorInterface::class), $config->get('api-platform.docs_formats'));
×
635
        });
×
636

NEW
637
        $this->app->singleton(Pagination::class, function (Application $app) {
×
638
            /** @var ConfigRepository */
NEW
639
            $config = $app['config'];
×
640

641
            return new Pagination($config->get('api-platform.collection.pagination'), []);
×
642
        });
×
643

NEW
644
        $this->app->singleton(PaginationOptions::class, function (Application $app) {
×
645
            /** @var ConfigRepository */
NEW
646
            $config = $app['config'];
×
UNCOV
647
            $pagination = $config->get('api-platform.collection.pagination');
×
648

649
            return new PaginationOptions(
×
650
                $pagination['enabled'],
×
651
                $pagination['page_parameter_name'],
×
652
                $pagination['client_items_per_page'],
×
653
                $pagination['items_per_page_parameter_name'],
×
654
                $pagination['client_enabled'],
×
655
                $pagination['enabled_parameter_name'],
×
656
                $pagination['items_per_page'],
×
657
                $pagination['maximum_items_per_page'],
×
658
                $pagination['partial'],
×
659
                $pagination['client_partial'],
×
660
                $pagination['partial_parameter_name'],
×
661
            );
×
662
        });
×
663

664
        $this->app->bind(OpenApiFactoryInterface::class, OpenApiFactory::class);
×
NEW
665
        $this->app->singleton(OpenApiFactory::class, function (Application $app) {
×
666
            /** @var ConfigRepository */
NEW
667
            $config = $app['config'];
×
668

669
            return new OpenApiFactory(
×
670
                $app->make(ResourceNameCollectionFactoryInterface::class),
×
671
                $app->make(ResourceMetadataCollectionFactoryInterface::class),
×
672
                $app->make(PropertyNameCollectionFactoryInterface::class),
×
673
                $app->make(PropertyMetadataFactoryInterface::class),
×
674
                $app->make(SchemaFactoryInterface::class),
×
675
                $app->make(FilterInterface::class),
×
676
                $config->get('api-platform.formats'),
×
677
                null, // ?Options $openApiOptions = null,
×
678
                $app->make(PaginationOptions::class), // ?PaginationOptions $paginationOptions = null,
×
679
                // ?RouterInterface $router = null
×
680
            );
×
681
        });
×
682

683
        $this->app->bind(DefinitionNameFactoryInterface::class, DefinitionNameFactory::class);
×
NEW
684
        $this->app->singleton(DefinitionNameFactory::class, function (Application $app) {
×
685
            /** @var ConfigRepository */
NEW
686
            $config = $app['config'];
×
687

688
            return new DefinitionNameFactory($config->get('api-platform.formats'));
×
689
        });
×
690

NEW
691
        $this->app->singleton(SchemaFactory::class, function (Application $app) {
×
692
            /** @var ConfigRepository */
NEW
693
            $config = $app['config'];
×
694

695
            return new SchemaFactory(
×
696
                $app->make(ResourceMetadataCollectionFactoryInterface::class),
×
697
                $app->make(PropertyNameCollectionFactoryInterface::class),
×
698
                $app->make(PropertyMetadataFactoryInterface::class),
×
699
                $app->make(NameConverterInterface::class),
×
700
                $app->make(ResourceClassResolverInterface::class),
×
701
                $config->get('api-platform.formats'),
×
702
                $app->make(DefinitionNameFactoryInterface::class),
×
703
            );
×
704
        });
×
705
        $this->app->singleton(JsonApiSchemaFactory::class, function (Application $app) {
×
706
            return new JsonApiSchemaFactory(
×
707
                $app->make(SchemaFactory::class),
×
708
                $app->make(PropertyMetadataFactoryInterface::class),
×
709
                $app->make(ResourceClassResolverInterface::class),
×
710
                $app->make(ResourceMetadataCollectionFactoryInterface::class),
×
711
                $app->make(DefinitionNameFactoryInterface::class),
×
712
            );
×
713
        });
×
714
        $this->app->singleton(HydraSchemaFactory::class, function (Application $app) {
×
715
            return new HydraSchemaFactory(
×
716
                $app->make(JsonApiSchemaFactory::class),
×
717
            );
×
718
        });
×
719

720
        $this->app->bind(SchemaFactoryInterface::class, HydraSchemaFactory::class);
×
721

722
        $this->app->singleton(OpenApiNormalizer::class, function (Application $app) {
×
723
            return new OpenApiNormalizer($app->make(ObjectNormalizer::class));
×
724
        });
×
725

726
        $this->app->singleton(HydraDocumentationNormalizer::class, function (Application $app) {
×
727
            return new HydraDocumentationNormalizer(
×
728
                $app->make(ResourceMetadataCollectionFactoryInterface::class),
×
729
                $app->make(PropertyNameCollectionFactoryInterface::class),
×
730
                $app->make(PropertyMetadataFactoryInterface::class),
×
731
                $app->make(ResourceClassResolverInterface::class),
×
732
                $app->make(UrlGeneratorInterface::class),
×
733
                $app->make(NameConverterInterface::class)
×
734
            );
×
735
        });
×
736

737
        $this->app->singleton(HydraCollectionNormalizer::class, function (Application $app) use ($defaultContext) {
×
738
            return new HydraCollectionNormalizer(
×
739
                $app->make(ContextBuilderInterface::class),
×
740
                $app->make(ResourceClassResolverInterface::class),
×
741
                $app->make(IriConverterInterface::class),
×
742
                $app->make(ResourceMetadataCollectionFactoryInterface::class),
×
743
                $defaultContext
×
744
            );
×
745
        });
×
746

747
        $this->app->singleton(ReservedAttributeNameConverter::class, function (Application $app) {
×
748
            return new ReservedAttributeNameConverter($app->make(NameConverterInterface::class));
×
749
        });
×
750

751
        $this->app->singleton(JsonApiEntrypointNormalizer::class, function (Application $app) {
×
752
            return new JsonApiEntrypointNormalizer(
×
753
                $app->make(ResourceMetadataCollectionFactoryInterface::class),
×
754
                $app->make(IriConverterInterface::class),
×
755
                $app->make(UrlGeneratorInterface::class),
×
756
            );
×
757
        });
×
758

NEW
759
        $this->app->singleton(JsonApiCollectionNormalizer::class, function (Application $app) {
×
760
            /** @var ConfigRepository */
NEW
761
            $config = $app['config'];
×
762

763
            return new JsonApiCollectionNormalizer(
×
764
                $app->make(ResourceClassResolverInterface::class),
×
765
                $config->get('api-platform.collection.pagination.page_parameter_name'),
×
766
                $app->make(ResourceMetadataCollectionFactoryInterface::class),
×
767
            );
×
768
        });
×
769

770
        $this->app->singleton(JsonApiItemNormalizer::class, function (Application $app) use ($defaultContext) {
×
771
            return new JsonApiItemNormalizer(
×
772
                $app->make(PropertyNameCollectionFactoryInterface::class),
×
773
                $app->make(PropertyMetadataFactoryInterface::class),
×
774
                $app->make(IriConverterInterface::class),
×
775
                $app->make(ResourceClassResolverInterface::class),
×
776
                $app->make(PropertyAccessorInterface::class),
×
777
                $app->make(NameConverterInterface::class),
×
778
                $app->make(ClassMetadataFactoryInterface::class),
×
779
                $defaultContext,
×
780
                $app->make(ResourceMetadataCollectionFactoryInterface::class),
×
781
                $app->make(ResourceAccessCheckerInterface::class),
×
782
                null
×
783
                // $app->make(TagCollectorInterface::class),
×
784
            );
×
785
        });
×
786

787
        $this->app->singleton(JsonApiObjectNormalizer::class, function (Application $app) {
×
788
            return new JsonApiObjectNormalizer(
×
789
                $app->make(ObjectNormalizer::class),
×
790
                $app->make(IriConverterInterface::class),
×
791
                $app->make(ResourceClassResolverInterface::class),
×
792
                $app->make(ResourceMetadataCollectionFactoryInterface::class),
×
793
            );
×
794
        });
×
795

NEW
796
        if ($this->app['config']->get('api-platform.graphql.enabled')) {
×
797
            $this->app->singleton(GraphQlItemNormalizer::class, function (Application $app) {
×
798
                return new GraphQlItemNormalizer(
×
799
                    $app->make(PropertyNameCollectionFactoryInterface::class),
×
800
                    $app->make(PropertyMetadataFactoryInterface::class),
×
801
                    $app->make(IriConverterInterface::class),
×
802
                    $app->make(IdentifiersExtractorInterface::class),
×
803
                    $app->make(ResourceClassResolverInterface::class),
×
804
                    $app->make(PropertyAccessorInterface::class),
×
805
                    $app->make(NameConverterInterface::class),
×
806
                    $app->make(SerializerClassMetadataFactory::class),
×
807
                    null,
×
808
                    $app->make(ResourceMetadataCollectionFactoryInterface::class),
×
809
                    $app->make(ResourceAccessCheckerInterface::class)
×
810
                );
×
811
            });
×
812

813
            $this->app->singleton(GraphQlObjectNormalizer::class, function (Application $app) {
×
814
                return new GraphQlObjectNormalizer(
×
815
                    $app->make(ObjectNormalizer::class),
×
816
                    $app->make(IriConverterInterface::class),
×
817
                    $app->make(IdentifiersExtractorInterface::class),
×
818
                );
×
819
            });
×
820
        }
821

822
        $this->app->singleton(GraphQlErrorNormalizer::class, function () {
×
823
            return new GraphQlErrorNormalizer();
×
824
        });
×
825

NEW
826
        $this->app->singleton(GraphQlValidationExceptionNormalizer::class, function (Application $app) {
×
827
            /** @var ConfigRepository */
NEW
828
            $config = $app['config'];
×
829

830
            return new GraphQlValidationExceptionNormalizer($config->get('api-platform.exception_to_status'));
×
831
        });
×
832

833
        $this->app->singleton(GraphQlHttpExceptionNormalizer::class, function () {
×
834
            return new GraphQlHttpExceptionNormalizer();
×
835
        });
×
836

837
        $this->app->singleton(GraphQlRuntimeExceptionNormalizer::class, function () {
×
838
            return new GraphQlHttpExceptionNormalizer();
×
839
        });
×
840

841
        $this->app->bind(SerializerInterface::class, Serializer::class);
×
842
        $this->app->bind(NormalizerInterface::class, Serializer::class);
×
NEW
843
        $this->app->singleton(Serializer::class, function (Application $app) {
×
844
            /** @var ConfigRepository */
NEW
845
            $config = $app['config'];
×
846
            $list = new \SplPriorityQueue();
×
847
            $list->insert($app->make(HydraEntrypointNormalizer::class), -800);
×
848
            $list->insert($app->make(HydraCollectionNormalizer::class), -800);
×
849
            $list->insert($app->make(JsonLdItemNormalizer::class), -890);
×
850
            $list->insert($app->make(JsonLdObjectNormalizer::class), -995);
×
851
            $list->insert($app->make(ArrayDenormalizer::class), -990);
×
852
            $list->insert($app->make(DateTimeZoneNormalizer::class), -915);
×
853
            $list->insert($app->make(DateIntervalNormalizer::class), -915);
×
854
            $list->insert($app->make(DateTimeNormalizer::class), -910);
×
855
            $list->insert($app->make(ObjectNormalizer::class), -1000);
×
856
            $list->insert($app->make(ItemNormalizer::class), -895);
×
857
            $list->insert($app->make(OpenApiNormalizer::class), -780);
×
858
            $list->insert($app->make(HydraDocumentationNormalizer::class), -790);
×
859

860
            $list->insert($app->make(JsonApiEntrypointNormalizer::class), -800);
×
861
            $list->insert($app->make(JsonApiCollectionNormalizer::class), -985);
×
862
            $list->insert($app->make(JsonApiItemNormalizer::class), -890);
×
863
            $list->insert($app->make(JsonApiObjectNormalizer::class), -995);
×
864

865
            if ($config->get('api-platform.graphql.enabled')) {
×
866
                $list->insert($app->make(GraphQlItemNormalizer::class), -890);
×
867
                $list->insert($app->make(GraphQlObjectNormalizer::class), -995);
×
868
                $list->insert($app->make(GraphQlErrorNormalizer::class), -790);
×
869
                $list->insert($app->make(GraphQlValidationExceptionNormalizer::class), -780);
×
870
                $list->insert($app->make(GraphQlHttpExceptionNormalizer::class), -780);
×
871
                $list->insert($app->make(GraphQlRuntimeExceptionNormalizer::class), -780);
×
872
            }
873

874
            // TODO: unused + implement hal/jsonapi ?
875
            // $list->insert($dataUriNormalizer, -920);
876
            // $list->insert($unwrappingDenormalizer, 1000);
877
            // $list->insert($halItemNormalizer, -890);
878
            // $list->insert($halEntrypointNormalizer, -800);
879
            // $list->insert($halCollectionNormalizer, -985);
880
            // $list->insert($halObjectNormalizer, -995);
881
            // $list->insert($jsonserializableNormalizer, -900);
882
            // $list->insert($uuidDenormalizer, -895); //Todo ramsey uuid support ?
883

884
            return new Serializer(iterator_to_array($list), [new JsonEncoder('json'), $app->make(JsonEncoder::class), new JsonEncoder('jsonopenapi'), new JsonEncoder('jsonapi')]);
×
885
        });
×
886

887
        $this->app->singleton(JsonLdItemNormalizer::class, function (Application $app) use ($defaultContext) {
×
888
            return new JsonLdItemNormalizer(
×
889
                $app->make(ResourceMetadataCollectionFactoryInterface::class),
×
890
                $app->make(PropertyNameCollectionFactoryInterface::class),
×
891
                $app->make(PropertyMetadataFactoryInterface::class),
×
892
                $app->make(IriConverterInterface::class),
×
893
                $app->make(ResourceClassResolverInterface::class),
×
894
                $app->make(ContextBuilderInterface::class),
×
895
                $app->make(PropertyAccessorInterface::class),
×
896
                $app->make(NameConverterInterface::class),
×
897
                $app->make(ClassMetadataFactoryInterface::class),
×
898
                $defaultContext,
×
899
                $app->make(ResourceAccessCheckerInterface::class)
×
900
            );
×
901
        });
×
902

903
        $this->app->singleton(
×
904
            ExceptionHandlerInterface::class,
×
NEW
905
            function (Application $app) {
×
906
                /** @var ConfigRepository */
NEW
907
                $config = $app['config'];
×
908

909
                return new ErrorHandler(
×
910
                    $app,
×
911
                    $app->make(ResourceMetadataCollectionFactoryInterface::class),
×
912
                    $app->make(ApiPlatformController::class),
×
913
                    $app->make(IdentifiersExtractorInterface::class),
×
914
                    $app->make(ResourceClassResolverInterface::class),
×
915
                    $app->make(Negotiator::class),
×
NEW
916
                    $config->get('api-platform.exception_to_status'),
×
NEW
917
                    $config->get('app.debug')
×
918
                );
×
919
            }
×
920
        );
×
921

922
        $this->app->singleton(InflectorInterface::class, function (Application $app) {
×
923
            return new Inflector();
×
924
        });
×
925

NEW
926
        if ($this->app['config']->get('api-platform.graphql.enabled')) {
×
NEW
927
            $this->registerGraphQl($this->app);
×
928
        }
929
    }
930

931
    private function registerGraphQl(Application $app): void
932
    {
933
        $app->singleton('api_platform.graphql.type_locator', function (Application $app) {
×
934
            $tagged = iterator_to_array($app->tagged('api_platform.graphql.type'));
×
935

936
            return new ServiceLocator($tagged);
×
937
        });
×
938

939
        $app->singleton(TypesFactoryInterface::class, function (Application $app) {
×
940
            $tagged = iterator_to_array($app->tagged('api_platform.graphql.type'));
×
941

942
            return new TypesFactory($app->make('api_platform.graphql.type_locator'), array_keys($tagged));
×
943
        });
×
944
        $app->singleton(TypesContainerInterface::class, function () {
×
945
            return new TypesContainer();
×
946
        });
×
947

948
        $app->singleton(ResourceFieldResolver::class, function (Application $app) {
×
949
            return new ResourceFieldResolver($app->make(IriConverterInterface::class));
×
950
        });
×
951

952
        $app->singleton(ContextAwareTypeBuilderInterface::class, function (Application $app) {
×
953
            return new TypeBuilder(
×
954
                $app->make(TypesContainerInterface::class),
×
955
                $app->make(ResourceFieldResolver::class),
×
956
                null,
×
957
                $app->make(Pagination::class)
×
958
            );
×
959
        });
×
960

961
        $app->singleton(TypeConverterInterface::class, function (Application $app) {
×
962
            return new TypeConverter(
×
963
                $app->make(ContextAwareTypeBuilderInterface::class),
×
964
                $app->make(TypesContainerInterface::class),
×
965
                $app->make(ResourceMetadataCollectionFactoryInterface::class),
×
966
                $app->make(PropertyMetadataFactoryInterface::class),
×
967
            );
×
968
        });
×
969

970
        $app->singleton(GraphQlSerializerContextBuilder::class, function (Application $app) {
×
971
            return new GraphQlSerializerContextBuilder($app->make(NameConverterInterface::class));
×
972
        });
×
973

NEW
974
        $app->singleton('api_platform.graphql.state_provider', function (Application $app) {
×
975
            /** @var ConfigRepository */
NEW
976
            $config = $app['config'];
×
977
            $tagged = iterator_to_array($app->tagged(ParameterProviderInterface::class));
×
978
            $resolvers = iterator_to_array($app->tagged('api_platform.graphql.resolver'));
×
979

980
            return new GraphQlReadProvider(
×
981
                new GraphQlDenormalizeProvider(
×
982
                    new ResolverProvider(
×
983
                        new ParameterProvider(
×
984
                            $app->make(CallableProvider::class),
×
985
                            new ServiceLocator($tagged)
×
986
                        ),
×
987
                        new ServiceLocator($resolvers),
×
988
                    ),
×
989
                    $app->make(SerializerInterface::class),
×
990
                    $app->make(GraphQlSerializerContextBuilder::class)
×
991
                ),
×
992
                $app->make(IriConverterInterface::class),
×
993
                $app->make(GraphQlSerializerContextBuilder::class),
×
994
                $config->get('api-platform.graphql.nesting_separator') ?? '__'
×
995
            );
×
996
        });
×
997

998
        $app->singleton('api_platform.graphql.state_processor', function (Application $app) {
×
999
            return new WriteProcessor(
×
1000
                new NormalizeProcessor(
×
1001
                    $app->make(SerializerInterface::class),
×
1002
                    $app->make(GraphQlSerializerContextBuilder::class),
×
1003
                    $app->make(Pagination::class)
×
1004
                ),
×
1005
                $app->make(CallableProcessor::class),
×
1006
            );
×
1007
        });
×
1008

1009
        $app->singleton(ResolverFactoryInterface::class, function (Application $app) {
×
1010
            return new ResolverFactory(
×
1011
                $app->make('api_platform.graphql.state_provider'),
×
1012
                $app->make('api_platform.graphql.state_processor')
×
1013
            );
×
1014
        });
×
1015

NEW
1016
        $app->singleton(FieldsBuilderEnumInterface::class, function (Application $app) {
×
1017
            /** @var ConfigRepository */
NEW
1018
            $config = $app['config'];
×
1019

1020
            return new FieldsBuilder(
×
1021
                $app->make(PropertyNameCollectionFactoryInterface::class),
×
1022
                $app->make(PropertyMetadataFactoryInterface::class),
×
1023
                $app->make(ResourceMetadataCollectionFactoryInterface::class),
×
1024
                $app->make(ResourceClassResolverInterface::class),
×
1025
                $app->make(TypesContainerInterface::class),
×
1026
                $app->make(ContextAwareTypeBuilderInterface::class),
×
1027
                $app->make(TypeConverterInterface::class),
×
1028
                $app->make(ResolverFactoryInterface::class),
×
1029
                $app->make(FilterInterface::class),
×
1030
                $app->make(Pagination::class),
×
1031
                $app->make(NameConverterInterface::class),
×
1032
                $config->get('api-platform.graphql.nesting_separator') ?? '__',
×
1033
                $app->make(InflectorInterface::class)
×
1034
            );
×
1035
        });
×
1036

1037
        $app->singleton(SchemaBuilderInterface::class, function (Application $app) {
×
1038
            return new SchemaBuilder($app->make(ResourceNameCollectionFactoryInterface::class), $app->make(ResourceMetadataCollectionFactoryInterface::class), $app->make(TypesFactoryInterface::class), $app->make(TypesContainerInterface::class), $app->make(FieldsBuilderEnumInterface::class));
×
1039
        });
×
1040

1041
        $app->singleton(ErrorHandlerInterface::class, function () {
×
1042
            return new GraphQlErrorHandler();
×
1043
        });
×
1044

NEW
1045
        $app->singleton(ExecutorInterface::class, function (Application $app) {
×
1046
            /** @var ConfigRepository */
NEW
1047
            $config = $app['config'];
×
1048

1049
            return new Executor($config->get('api-platform.graphql.introspection.enabled') ?? false);
×
1050
        });
×
1051

NEW
1052
        $app->singleton(GraphiQlController::class, function (Application $app) {
×
1053
            /** @var ConfigRepository */
NEW
1054
            $config = $app['config'];
×
UNCOV
1055
            $prefix = $config->get('api-platform.routes.prefix') ?? '';
×
1056

1057
            return new GraphiQlController($prefix);
×
1058
        });
×
1059

1060
        $app->singleton(GraphQlEntrypointController::class, function (Application $app) {
×
1061
            /** @var ConfigRepository */
NEW
1062
            $config = $app['config'];
×
1063

1064
            return new GraphQlEntrypointController(
×
1065
                $app->make(SchemaBuilderInterface::class),
×
1066
                $app->make(ExecutorInterface::class),
×
1067
                $app->make(GraphiQlController::class),
×
1068
                $app->make(SerializerInterface::class),
×
1069
                $app->make(ErrorHandlerInterface::class),
×
NEW
1070
                debug: $config->get('app.debug'),
×
1071
                negotiator: $app->make(Negotiator::class)
×
1072
            );
×
1073
        });
×
1074
    }
1075

1076
    /**
1077
     * Bootstrap services.
1078
     */
1079
    public function boot(ResourceNameCollectionFactoryInterface $resourceNameCollectionFactory, ResourceMetadataCollectionFactoryInterface $resourceMetadataFactory, Router $router): void
1080
    {
1081
        if ($this->app->runningInConsole()) {
×
1082
            $this->publishes([
×
1083
                __DIR__.'/config/api-platform.php' => $this->app->configPath('api-platform.php'),
×
1084
            ], 'laravel-assets');
×
1085

1086
            $this->publishes([
×
1087
                __DIR__.'/public' => $this->app->publicPath('vendor/api-platform'),
×
1088
            ], 'laravel-assets');
×
1089
        }
1090

1091
        $this->loadViewsFrom(__DIR__.'/resources/views', 'api-platform');
×
1092

1093
        $fieldsBuilder = $this->app->make(FieldsBuilderEnumInterface::class);
×
1094
        $typeBuilder = $this->app->make(ContextAwareTypeBuilderInterface::class);
×
1095
        $typeBuilder->setFieldsBuilderLocator(new ServiceLocator(['api_platform.graphql.fields_builder' => $fieldsBuilder]));
×
1096

1097
        if (!$this->shouldRegisterRoutes()) {
×
1098
            return;
×
1099
        }
1100

1101
        $config = $this->app['config'];
×
1102
        $routeCollection = new RouteCollection();
×
1103
        foreach ($resourceNameCollectionFactory->create() as $resourceClass) {
×
1104
            foreach ($resourceMetadataFactory->create($resourceClass) as $resourceMetadata) {
×
1105
                foreach ($resourceMetadata->getOperations() as $operation) {
×
1106
                    $uriTemplate = $operation->getUriTemplate();
×
1107
                    // _format is read by the middleware
1108
                    $uriTemplate = $operation->getRoutePrefix().str_replace('{._format}', '{_format?}', $uriTemplate);
×
1109
                    $route = (new Route([$operation->getMethod()], $uriTemplate, [ApiPlatformController::class, '__invoke']))
×
NEW
1110
                        ->name($operation->getName())
×
NEW
1111
                        ->setDefaults(['_api_operation_name' => $operation->getName(), '_api_resource_class' => $operation->getClass()]);
×
1112

1113
                    $route->middleware(ApiPlatformMiddleware::class.':'.$operation->getName());
×
1114
                    $route->middleware($config->get('api-platform.routes.middleware'));
×
1115
                    $route->middleware($operation->getMiddleware());
×
1116

1117
                    $routeCollection->add($route);
×
1118
                }
1119
            }
1120
        }
1121

1122
        $prefix = $config->get('api-platform.routes.prefix') ?? '';
×
1123
        $route = new Route(['GET'], $prefix.'/contexts/{shortName?}{_format?}', [ContextAction::class, '__invoke']);
×
1124
        $route->name('api_jsonld_context')->middleware(ApiPlatformMiddleware::class);
×
1125
        $routeCollection->add($route);
×
1126
        // Maybe that we can alias Symfony Request to Laravel Request within the provider ?
1127
        $route = new Route(['GET'], $prefix.'/docs{_format?}', function (Request $request, Application $app) {
×
1128
            $documentationAction = $app->make(DocumentationAction::class);
×
1129

1130
            return $documentationAction->__invoke($request);
×
1131
        });
×
1132
        $route->name('api_doc')->middleware(ApiPlatformMiddleware::class);
×
1133
        $routeCollection->add($route);
×
1134

1135
        $route = new Route(['GET'], $prefix.'/{index?}{_format?}', function (Request $request, Application $app) {
×
1136
            $entrypointAction = $app->make(EntrypointAction::class);
×
1137

1138
            return $entrypointAction->__invoke($request);
×
1139
        });
×
1140
        $route->where('index', 'index');
×
1141
        $route->name('api_entrypoint')->middleware(ApiPlatformMiddleware::class);
×
1142
        $routeCollection->add($route);
×
1143
        $route = new Route(['GET'], $prefix.'/.well-known/genid/{id}', function (): void {
×
1144
            throw new NotExposedHttpException('This route is not exposed on purpose. It generates an IRI for a collection resource without identifier nor item operation.');
×
1145
        });
×
1146
        $route->name('api_genid')->middleware(ApiPlatformMiddleware::class);
×
1147
        $routeCollection->add($route);
×
1148

1149
        if ($config->get('api-platform.graphql.enabled')) {
×
1150
            $route = new Route(['POST', 'GET'], $prefix.'/graphql', function (Application $app, Request $request) {
×
1151
                $entrypointAction = $app->make(GraphQlEntrypointController::class);
×
1152

1153
                return $entrypointAction->__invoke($request);
×
1154
            });
×
1155
            $routeCollection->add($route);
×
1156

1157
            $route = new Route(['GET'], $prefix.'/graphiql', function (Application $app) {
×
1158
                $controller = $app->make(GraphiQlController::class);
×
1159

1160
                return $controller->__invoke();
×
1161
            });
×
1162
            $routeCollection->add($route);
×
1163
        }
1164

1165
        $router->setRoutes($routeCollection);
×
1166
    }
1167

1168
    private function shouldRegisterRoutes(): bool
1169
    {
1170
        if ($this->app instanceof CachesRoutes && $this->app->routesAreCached()) {
×
1171
            return false;
×
1172
        }
1173

1174
        return true;
×
1175
    }
1176
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2024 Coveralls, Inc