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

api-platform / core / 17738646910

15 Sep 2025 03:40PM UTC coverage: 22.156% (-0.07%) from 22.227%
17738646910

Pull #7380

github

web-flow
Merge e3d95e940 into 4abec444e
Pull Request #7380: fix(laravel): http cache compatibility

0 of 152 new or added lines in 9 files covered. (0.0%)

4 existing lines in 4 files now uncovered.

11127 of 50221 relevant lines covered (22.16%)

23.41 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\GraphQl\Error\ErrorHandler as GraphQlErrorHandler;
17
use ApiPlatform\GraphQl\Error\ErrorHandlerInterface;
18
use ApiPlatform\GraphQl\Executor;
19
use ApiPlatform\GraphQl\ExecutorInterface;
20
use ApiPlatform\GraphQl\Metadata\RuntimeOperationMetadataFactory;
21
use ApiPlatform\GraphQl\Resolver\Factory\ResolverFactory;
22
use ApiPlatform\GraphQl\Resolver\Factory\ResolverFactoryInterface;
23
use ApiPlatform\GraphQl\Resolver\QueryCollectionResolverInterface;
24
use ApiPlatform\GraphQl\Resolver\QueryItemResolverInterface;
25
use ApiPlatform\GraphQl\Resolver\ResourceFieldResolver;
26
use ApiPlatform\GraphQl\Serializer\Exception\ErrorNormalizer as GraphQlErrorNormalizer;
27
use ApiPlatform\GraphQl\Serializer\Exception\HttpExceptionNormalizer as GraphQlHttpExceptionNormalizer;
28
use ApiPlatform\GraphQl\Serializer\Exception\RuntimeExceptionNormalizer as GraphQlRuntimeExceptionNormalizer;
29
use ApiPlatform\GraphQl\Serializer\Exception\ValidationExceptionNormalizer as GraphQlValidationExceptionNormalizer;
30
use ApiPlatform\GraphQl\Serializer\ItemNormalizer as GraphQlItemNormalizer;
31
use ApiPlatform\GraphQl\Serializer\ObjectNormalizer as GraphQlObjectNormalizer;
32
use ApiPlatform\GraphQl\Serializer\SerializerContextBuilder as GraphQlSerializerContextBuilder;
33
use ApiPlatform\GraphQl\State\Processor\NormalizeProcessor;
34
use ApiPlatform\GraphQl\State\Provider\DenormalizeProvider as GraphQlDenormalizeProvider;
35
use ApiPlatform\GraphQl\State\Provider\ReadProvider as GraphQlReadProvider;
36
use ApiPlatform\GraphQl\State\Provider\ResolverProvider;
37
use ApiPlatform\GraphQl\Type\ContextAwareTypeBuilderInterface;
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\Hal\Serializer\CollectionNormalizer as HalCollectionNormalizer;
49
use ApiPlatform\Hal\Serializer\EntrypointNormalizer as HalEntrypointNormalizer;
50
use ApiPlatform\Hal\Serializer\ItemNormalizer as HalItemNormalizer;
51
use ApiPlatform\Hal\Serializer\ObjectNormalizer as HalObjectNormalizer;
52
use ApiPlatform\HttpCache\State\AddHeadersProcessor;
53
use ApiPlatform\Hydra\JsonSchema\SchemaFactory as HydraSchemaFactory;
54
use ApiPlatform\Hydra\Serializer\CollectionFiltersNormalizer as HydraCollectionFiltersNormalizer;
55
use ApiPlatform\Hydra\Serializer\CollectionNormalizer as HydraCollectionNormalizer;
56
use ApiPlatform\Hydra\Serializer\DocumentationNormalizer as HydraDocumentationNormalizer;
57
use ApiPlatform\Hydra\Serializer\EntrypointNormalizer as HydraEntrypointNormalizer;
58
use ApiPlatform\Hydra\Serializer\HydraPrefixNameConverter;
59
use ApiPlatform\Hydra\Serializer\PartialCollectionViewNormalizer as HydraPartialCollectionViewNormalizer;
60
use ApiPlatform\Hydra\State\HydraLinkProcessor;
61
use ApiPlatform\JsonApi\JsonSchema\SchemaFactory as JsonApiSchemaFactory;
62
use ApiPlatform\JsonApi\Serializer\CollectionNormalizer as JsonApiCollectionNormalizer;
63
use ApiPlatform\JsonApi\Serializer\EntrypointNormalizer as JsonApiEntrypointNormalizer;
64
use ApiPlatform\JsonApi\Serializer\ErrorNormalizer as JsonApiErrorNormalizer;
65
use ApiPlatform\JsonApi\Serializer\ItemNormalizer as JsonApiItemNormalizer;
66
use ApiPlatform\JsonApi\Serializer\ObjectNormalizer as JsonApiObjectNormalizer;
67
use ApiPlatform\JsonApi\Serializer\ReservedAttributeNameConverter;
68
use ApiPlatform\JsonLd\AnonymousContextBuilderInterface;
69
use ApiPlatform\JsonLd\ContextBuilder as JsonLdContextBuilder;
70
use ApiPlatform\JsonLd\ContextBuilderInterface;
71
use ApiPlatform\JsonLd\Serializer\ItemNormalizer as JsonLdItemNormalizer;
72
use ApiPlatform\JsonLd\Serializer\ObjectNormalizer as JsonLdObjectNormalizer;
73
use ApiPlatform\JsonSchema\DefinitionNameFactory;
74
use ApiPlatform\JsonSchema\DefinitionNameFactoryInterface;
75
use ApiPlatform\JsonSchema\Metadata\Property\Factory\SchemaPropertyMetadataFactory;
76
use ApiPlatform\JsonSchema\SchemaFactory;
77
use ApiPlatform\JsonSchema\SchemaFactoryInterface;
78
use ApiPlatform\Laravel\ApiResource\Error;
79
use ApiPlatform\Laravel\ApiResource\ValidationError;
80
use ApiPlatform\Laravel\Controller\DocumentationController;
81
use ApiPlatform\Laravel\Controller\EntrypointController;
82
use ApiPlatform\Laravel\Eloquent\Filter\JsonApi\SortFilterParameterProvider;
83
use ApiPlatform\Laravel\Eloquent\Metadata\Factory\Property\EloquentAttributePropertyMetadataFactory;
84
use ApiPlatform\Laravel\Eloquent\Metadata\Factory\Property\EloquentPropertyMetadataFactory;
85
use ApiPlatform\Laravel\Eloquent\Metadata\Factory\Property\EloquentPropertyNameCollectionMetadataFactory;
86
use ApiPlatform\Laravel\Eloquent\Metadata\IdentifiersExtractor as EloquentIdentifiersExtractor;
87
use ApiPlatform\Laravel\Eloquent\Metadata\ModelMetadata;
88
use ApiPlatform\Laravel\Eloquent\Metadata\ResourceClassResolver as EloquentResourceClassResolver;
89
use ApiPlatform\Laravel\Eloquent\PropertyAccess\PropertyAccessor as EloquentPropertyAccessor;
90
use ApiPlatform\Laravel\Eloquent\PropertyInfo\EloquentExtractor;
91
use ApiPlatform\Laravel\Eloquent\Serializer\EloquentNameConverter;
92
use ApiPlatform\Laravel\Eloquent\Serializer\SerializerContextBuilder as EloquentSerializerContextBuilder;
93
use ApiPlatform\Laravel\GraphQl\Controller\EntrypointController as GraphQlEntrypointController;
94
use ApiPlatform\Laravel\GraphQl\Controller\GraphiQlController;
95
use ApiPlatform\Laravel\JsonApi\State\JsonApiProvider;
96
use ApiPlatform\Laravel\Metadata\CachePropertyMetadataFactory;
97
use ApiPlatform\Laravel\Metadata\CachePropertyNameCollectionMetadataFactory;
98
use ApiPlatform\Laravel\Routing\IriConverter;
99
use ApiPlatform\Laravel\Routing\Router as UrlGeneratorRouter;
100
use ApiPlatform\Laravel\Routing\SkolemIriConverter;
101
use ApiPlatform\Laravel\Security\ResourceAccessChecker;
102
use ApiPlatform\Laravel\State\AccessCheckerProvider;
103
use ApiPlatform\Laravel\State\SwaggerUiProcessor;
104
use ApiPlatform\Laravel\State\SwaggerUiProvider;
105
use ApiPlatform\Laravel\State\ValidateProvider;
106
use ApiPlatform\Metadata\IdentifiersExtractor;
107
use ApiPlatform\Metadata\IdentifiersExtractorInterface;
108
use ApiPlatform\Metadata\InflectorInterface;
109
use ApiPlatform\Metadata\IriConverterInterface;
110
use ApiPlatform\Metadata\Operation\Factory\OperationMetadataFactory;
111
use ApiPlatform\Metadata\Operation\Factory\OperationMetadataFactoryInterface;
112
use ApiPlatform\Metadata\Operation\PathSegmentNameGeneratorInterface;
113
use ApiPlatform\Metadata\Operation\UnderscorePathSegmentNameGenerator;
114
use ApiPlatform\Metadata\Property\Factory\AttributePropertyMetadataFactory;
115
use ApiPlatform\Metadata\Property\Factory\ClassLevelAttributePropertyNameCollectionFactory;
116
use ApiPlatform\Metadata\Property\Factory\ConcernsPropertyNameCollectionMetadataFactory;
117
use ApiPlatform\Metadata\Property\Factory\PropertyInfoPropertyMetadataFactory;
118
use ApiPlatform\Metadata\Property\Factory\PropertyInfoPropertyNameCollectionFactory;
119
use ApiPlatform\Metadata\Property\Factory\PropertyMetadataFactoryInterface;
120
use ApiPlatform\Metadata\Property\Factory\PropertyNameCollectionFactoryInterface;
121
use ApiPlatform\Metadata\Property\Factory\SerializerPropertyMetadataFactory;
122
use ApiPlatform\Metadata\Resource\Factory\AttributesResourceNameCollectionFactory;
123
use ApiPlatform\Metadata\Resource\Factory\ConcernsResourceNameCollectionFactory;
124
use ApiPlatform\Metadata\Resource\Factory\LinkFactory;
125
use ApiPlatform\Metadata\Resource\Factory\LinkFactoryInterface;
126
use ApiPlatform\Metadata\Resource\Factory\ResourceMetadataCollectionFactoryInterface;
127
use ApiPlatform\Metadata\Resource\Factory\ResourceNameCollectionFactoryInterface;
128
use ApiPlatform\Metadata\ResourceAccessCheckerInterface;
129
use ApiPlatform\Metadata\ResourceClassResolver;
130
use ApiPlatform\Metadata\ResourceClassResolverInterface;
131
use ApiPlatform\Metadata\UrlGeneratorInterface;
132
use ApiPlatform\Metadata\Util\Inflector;
133
use ApiPlatform\OpenApi\Command\OpenApiCommand;
134
use ApiPlatform\OpenApi\Factory\OpenApiFactory;
135
use ApiPlatform\OpenApi\Factory\OpenApiFactoryInterface;
136
use ApiPlatform\OpenApi\Options;
137
use ApiPlatform\OpenApi\Serializer\OpenApiNormalizer;
138
use ApiPlatform\Serializer\ItemNormalizer;
139
use ApiPlatform\Serializer\JsonEncoder;
140
use ApiPlatform\Serializer\Mapping\Factory\ClassMetadataFactory as SerializerClassMetadataFactory;
141
use ApiPlatform\Serializer\Mapping\Loader\PropertyMetadataLoader;
142
use ApiPlatform\Serializer\SerializerContextBuilder;
143
use ApiPlatform\State\CallableProcessor;
144
use ApiPlatform\State\CallableProvider;
145
use ApiPlatform\State\ErrorProvider;
146
use ApiPlatform\State\Pagination\Pagination;
147
use ApiPlatform\State\Pagination\PaginationOptions;
148
use ApiPlatform\State\Processor\AddLinkHeaderProcessor;
149
use ApiPlatform\State\Processor\RespondProcessor;
150
use ApiPlatform\State\Processor\SerializeProcessor;
151
use ApiPlatform\State\Processor\WriteProcessor;
152
use ApiPlatform\State\ProcessorInterface;
153
use ApiPlatform\State\Provider\ContentNegotiationProvider;
154
use ApiPlatform\State\Provider\DeserializeProvider;
155
use ApiPlatform\State\Provider\ParameterProvider;
156
use ApiPlatform\State\Provider\ReadProvider;
157
use ApiPlatform\State\ProviderInterface;
158
use ApiPlatform\State\SerializerContextBuilderInterface;
159
use Illuminate\Config\Repository as ConfigRepository;
160
use Illuminate\Contracts\Foundation\Application;
161
use Illuminate\Routing\Router;
162
use Illuminate\Support\ServiceProvider;
163
use Negotiation\Negotiator;
164
use PHPStan\PhpDocParser\Parser\PhpDocParser;
165
use Psr\Log\LoggerInterface;
166
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
167
use Symfony\Component\PropertyInfo\Extractor\PhpStanExtractor;
168
use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor;
169
use Symfony\Component\PropertyInfo\PropertyInfoExtractor;
170
use Symfony\Component\PropertyInfo\PropertyInfoExtractorInterface;
171
use Symfony\Component\Routing\RequestContext;
172
use Symfony\Component\Serializer\Encoder\CsvEncoder;
173
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory;
174
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface;
175
use Symfony\Component\Serializer\Mapping\Loader\AttributeLoader;
176
use Symfony\Component\Serializer\Mapping\Loader\LoaderChain;
177
use Symfony\Component\Serializer\Mapping\Loader\LoaderInterface;
178
use Symfony\Component\Serializer\NameConverter\MetadataAwareNameConverter;
179
use Symfony\Component\Serializer\NameConverter\NameConverterInterface;
180
use Symfony\Component\Serializer\NameConverter\SnakeCaseToCamelCaseNameConverter;
181
use Symfony\Component\Serializer\Normalizer\ArrayDenormalizer;
182
use Symfony\Component\Serializer\Normalizer\BackedEnumNormalizer;
183
use Symfony\Component\Serializer\Normalizer\DateIntervalNormalizer;
184
use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer;
185
use Symfony\Component\Serializer\Normalizer\DateTimeZoneNormalizer;
186
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
187
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
188
use Symfony\Component\Serializer\Serializer;
189
use Symfony\Component\Serializer\SerializerInterface;
190
use Symfony\Component\WebLink\HttpHeaderSerializer;
191

192
class ApiPlatformProvider extends ServiceProvider
193
{
194
    /**
195
     * Register services.
196
     */
197
    public function register(): void
198
    {
199
        $this->mergeConfigFrom(__DIR__.'/config/api-platform.php', 'api-platform');
×
200

201
        $this->app->singleton(PropertyInfoExtractorInterface::class, function (Application $app) {
×
202
            $phpstanExtractor = class_exists(PhpDocParser::class) ? new PhpStanExtractor() : null;
×
203
            $reflectionExtractor = new ReflectionExtractor();
×
204
            $eloquentExtractor = new EloquentExtractor($app->make(ModelMetadata::class));
×
205

206
            return new PropertyInfoExtractor(
×
207
                [$reflectionExtractor],
×
208
                $phpstanExtractor ? [$phpstanExtractor, $reflectionExtractor] : [$reflectionExtractor],
×
209
                [],
×
210
                [$eloquentExtractor],
×
211
                [$reflectionExtractor]
×
212
            );
×
213
        });
×
214

215
        $this->app->singleton(ModelMetadata::class, function () {
×
216
            return new ModelMetadata();
×
217
        });
×
218

219
        $this->app->bind(LoaderInterface::class, AttributeLoader::class);
×
220
        $this->app->bind(ClassMetadataFactoryInterface::class, ClassMetadataFactory::class);
×
221
        $this->app->singleton(ClassMetadataFactory::class, function (Application $app) {
×
222
            /** @var ConfigRepository */
223
            $config = $app['config'];
×
224
            $nameConverter = $config->get('api-platform.name_converter', SnakeCaseToCamelCaseNameConverter::class);
×
225
            if ($nameConverter && class_exists($nameConverter)) {
×
226
                $nameConverter = new EloquentNameConverter($app->make($nameConverter));
×
227
            }
228

229
            return new ClassMetadataFactory(
×
230
                new LoaderChain([
×
231
                    new PropertyMetadataLoader(
×
232
                        $app->make(PropertyNameCollectionFactoryInterface::class),
×
233
                        $nameConverter
×
234
                    ),
×
235
                    new AttributeLoader(),
×
236
                    // new RelationMetadataLoader($app->make(ModelMetadata::class)),
×
237
                ])
×
238
            );
×
239
        });
×
240

241
        $this->app->singleton(SerializerClassMetadataFactory::class, function (Application $app) {
×
242
            return new SerializerClassMetadataFactory($app->make(ClassMetadataFactoryInterface::class));
×
243
        });
×
244

245
        $this->app->bind(PathSegmentNameGeneratorInterface::class, UnderscorePathSegmentNameGenerator::class);
×
246

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

254
            $logger = $app->make(LoggerInterface::class);
×
255

256
            foreach ($paths as $i => $path) {
×
257
                if (!file_exists($path)) {
×
258
                    $logger->warning(\sprintf('We skipped reading resources in "%s" as the path does not exist. Please check the configuration at "api-platform.resources".', $path));
×
259
                    unset($paths[$i]);
×
260
                }
261
            }
262

263
            return new ConcernsResourceNameCollectionFactory($paths, new AttributesResourceNameCollectionFactory($paths));
×
264
        });
×
265

266
        $this->app->bind(ResourceClassResolverInterface::class, ResourceClassResolver::class);
×
267
        $this->app->singleton(ResourceClassResolver::class, function (Application $app) {
×
268
            return new EloquentResourceClassResolver(new ResourceClassResolver($app->make(ResourceNameCollectionFactoryInterface::class)));
×
269
        });
×
270

271
        $this->app->singleton(PropertyMetadataFactoryInterface::class, function (Application $app) {
×
272
            /** @var ConfigRepository $config */
273
            $config = $app['config'];
×
274
            $nameConverter = $config->get('api-platform.name_converter', SnakeCaseToCamelCaseNameConverter::class);
×
275
            if ($nameConverter && class_exists($nameConverter)) {
×
276
                $nameConverter = new EloquentNameConverter($app->make($nameConverter));
×
277
            }
278

279
            return new CachePropertyMetadataFactory(
×
280
                new SchemaPropertyMetadataFactory(
×
281
                    $app->make(ResourceClassResolverInterface::class),
×
282
                    new SerializerPropertyMetadataFactory(
×
283
                        $app->make(SerializerClassMetadataFactory::class),
×
284
                        new PropertyInfoPropertyMetadataFactory(
×
285
                            $app->make(PropertyInfoExtractorInterface::class),
×
286
                            new AttributePropertyMetadataFactory(
×
287
                                new EloquentAttributePropertyMetadataFactory(
×
288
                                    new EloquentPropertyMetadataFactory(
×
289
                                        $app->make(ModelMetadata::class),
×
290
                                    ),
×
291
                                ),
×
292
                                $nameConverter
×
293
                            ),
×
294
                            $app->make(ResourceClassResolverInterface::class)
×
295
                        ),
×
296
                    )
×
297
                ),
×
298
                true === $config->get('app.debug') ? 'array' : $config->get('api-platform.cache', 'file')
×
299
            );
×
300
        });
×
301

302
        $this->app->singleton(PropertyNameCollectionFactoryInterface::class, function (Application $app) {
×
303
            /** @var ConfigRepository $config */
304
            $config = $app['config'];
×
305
            $nameConverter = $config->get('api-platform.name_converter', SnakeCaseToCamelCaseNameConverter::class);
×
306
            if ($nameConverter && class_exists($nameConverter)) {
×
307
                $nameConverter = new EloquentNameConverter($app->make($nameConverter));
×
308
            }
309

310
            return new CachePropertyNameCollectionMetadataFactory(
×
311
                new ClassLevelAttributePropertyNameCollectionFactory(
×
312
                    new ConcernsPropertyNameCollectionMetadataFactory(
×
313
                        new EloquentPropertyNameCollectionMetadataFactory(
×
314
                            $app->make(ModelMetadata::class),
×
315
                            new PropertyInfoPropertyNameCollectionFactory($app->make(PropertyInfoExtractorInterface::class)),
×
316
                            $app->make(ResourceClassResolverInterface::class)
×
317
                        )
×
318
                    ),
×
319
                    $nameConverter
×
320
                ),
×
321
                true === $config->get('app.debug') ? 'array' : $config->get('api-platform.cache', 'file')
×
322
            );
×
323
        });
×
324

325
        $this->app->singleton(LinkFactoryInterface::class, function (Application $app) {
×
326
            return new LinkFactory(
×
327
                $app->make(PropertyNameCollectionFactoryInterface::class),
×
328
                $app->make(PropertyMetadataFactoryInterface::class),
×
329
                $app->make(ResourceClassResolverInterface::class),
×
330
            );
×
331
        });
×
332

333
        $this->app->bind(PropertyAccessorInterface::class, function () {
×
334
            return new EloquentPropertyAccessor();
×
335
        });
×
336

337
        $this->app->bind(NameConverterInterface::class, function (Application $app) {
×
338
            $config = $app['config'];
×
339
            $nameConverter = $config->get('api-platform.name_converter', SnakeCaseToCamelCaseNameConverter::class);
×
340
            if ($nameConverter && class_exists($nameConverter)) {
×
341
                $nameConverter = new EloquentNameConverter($app->make($nameConverter));
×
342
            }
343

344
            $defaultContext = $config->get('api-platform.serializer', []);
×
345

346
            return new HydraPrefixNameConverter(new MetadataAwareNameConverter($app->make(ClassMetadataFactoryInterface::class), $nameConverter), $defaultContext);
×
347
        });
×
348

349
        $this->app->singleton(OperationMetadataFactory::class, function (Application $app) {
×
350
            return new OperationMetadataFactory($app->make(ResourceNameCollectionFactoryInterface::class), $app->make(ResourceMetadataCollectionFactoryInterface::class));
×
351
        });
×
352

353
        $this->app->bind(OperationMetadataFactoryInterface::class, OperationMetadataFactory::class);
×
354

355
        $this->app->singleton(ReadProvider::class, function (Application $app) {
×
356
            return new ReadProvider($app->make(CallableProvider::class));
×
357
        });
×
358

359
        $this->app->singleton(SwaggerUiProvider::class, function (Application $app) {
×
360
            /** @var ConfigRepository */
361
            $config = $app['config'];
×
362

363
            return new SwaggerUiProvider($app->make(ReadProvider::class), $app->make(OpenApiFactoryInterface::class), $config->get('api-platform.swagger_ui.enabled', false));
×
364
        });
×
365

366
        $this->app->singleton(DeserializeProvider::class, function (Application $app) {
×
367
            return new DeserializeProvider($app->make(SwaggerUiProvider::class), $app->make(SerializerInterface::class), $app->make(SerializerContextBuilderInterface::class));
×
368
        });
×
369

370
        $this->app->singleton(ValidateProvider::class, function (Application $app) {
×
371
            $config = $app['config'];
×
372
            $nameConverter = $config->get('api-platform.name_converter', SnakeCaseToCamelCaseNameConverter::class);
×
373
            if ($nameConverter && class_exists($nameConverter)) {
×
374
                $nameConverter = $app->make($nameConverter);
×
375
            }
376

377
            return new ValidateProvider($app->make(DeserializeProvider::class), $app, $app->make(ObjectNormalizer::class), $nameConverter);
×
378
        });
×
379

380
        if (class_exists(JsonApiProvider::class)) {
×
381
            $this->app->extend(DeserializeProvider::class, function (ProviderInterface $inner, Application $app) {
×
382
                return new JsonApiProvider($inner);
×
383
            });
×
384
        }
385

386
        $this->app->singleton(SortFilterParameterProvider::class, function (Application $app) {
×
387
            return new SortFilterParameterProvider();
×
388
        });
×
389

390
        $this->app->singleton(AccessCheckerProvider::class, function (Application $app) {
×
391
            return new AccessCheckerProvider($app->make(ParameterProvider::class), $app->make(ResourceAccessCheckerInterface::class));
×
392
        });
×
393

394
        $this->app->singleton(Negotiator::class, function (Application $app) {
×
395
            return new Negotiator();
×
396
        });
×
397
        $this->app->singleton(ContentNegotiationProvider::class, function (Application $app) {
×
398
            /** @var ConfigRepository */
399
            $config = $app['config'];
×
400

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

404
        $this->app->bind(ProviderInterface::class, ContentNegotiationProvider::class);
×
405

NEW
406
        $this->app->singleton(RespondProcessor::class, function (Application $app) {
×
NEW
407
            $decorated = new RespondProcessor();
×
NEW
408
            if (class_exists(AddHeadersProcessor::class)) {
×
409
                /** @var ConfigRepository */
NEW
410
                $config = $app['config']->get('api-platform.http_cache') ?? [];
×
411

NEW
412
                $decorated = new AddHeadersProcessor(
×
NEW
413
                    $decorated,
×
NEW
414
                    etag: $config['etag'] ?? false,
×
NEW
415
                    maxAge: $config['max_age'] ?? null,
×
NEW
416
                    sharedMaxAge: $config['shared_max_age'] ?? null,
×
NEW
417
                    vary: $config['vary'] ?? null,
×
NEW
418
                    public: $config['public'] ?? null,
×
NEW
419
                    staleWhileRevalidate: $config['stale_while_revalidate'] ?? null,
×
NEW
420
                    staleIfError: $config['stale_if_error'] ?? null
×
NEW
421
                );
×
422
            }
423

NEW
424
            return new AddLinkHeaderProcessor($decorated, new HttpHeaderSerializer());
×
UNCOV
425
        });
×
426

427
        $this->app->singleton(SerializeProcessor::class, function (Application $app) {
×
428
            return new SerializeProcessor($app->make(RespondProcessor::class), $app->make(Serializer::class), $app->make(SerializerContextBuilderInterface::class));
×
429
        });
×
430

431
        $this->app->singleton(WriteProcessor::class, function (Application $app) {
×
432
            return new WriteProcessor($app->make(SerializeProcessor::class), $app->make(CallableProcessor::class));
×
433
        });
×
434

435
        $this->app->singleton(SerializerContextBuilder::class, function (Application $app) {
×
436
            /** @var ConfigRepository */
437
            $config = $app['config'];
×
438

439
            return new SerializerContextBuilder($app->make(ResourceMetadataCollectionFactoryInterface::class), $config->get('app.debug'));
×
440
        });
×
441
        $this->app->bind(SerializerContextBuilderInterface::class, EloquentSerializerContextBuilder::class);
×
442
        $this->app->singleton(EloquentSerializerContextBuilder::class, function (Application $app) {
×
443
            /** @var ConfigRepository */
444
            $config = $app['config'];
×
445

446
            return new EloquentSerializerContextBuilder(
×
447
                $app->make(SerializerContextBuilder::class),
×
448
                $app->make(PropertyNameCollectionFactoryInterface::class),
×
449
                $config->get('api-platform.name_converter', SnakeCaseToCamelCaseNameConverter::class)
×
450
            );
×
451
        });
×
452

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

457
        $this->app->bind(ProcessorInterface::class, function (Application $app) {
×
458
            $config = $app['config'];
×
459
            if ($config->has('api-platform.formats.jsonld')) {
×
460
                return $app->make(HydraLinkProcessor::class);
×
461
            }
462

463
            return $app->make(WriteProcessor::class);
×
464
        });
×
465

466
        $this->app->singleton(ObjectNormalizer::class, function (Application $app) {
×
467
            $config = $app['config'];
×
468
            $defaultContext = $config->get('api-platform.serializer', []);
×
469

470
            return new ObjectNormalizer(defaultContext: $defaultContext);
×
471
        });
×
472

473
        $this->app->singleton(DateTimeNormalizer::class, function (Application $app) {
×
474
            $config = $app['config'];
×
475
            $defaultContext = $config->get('api-platform.serializer', []);
×
476

477
            return new DateTimeNormalizer(defaultContext: $defaultContext);
×
478
        });
×
479

480
        $this->app->singleton(DateTimeZoneNormalizer::class, function () {
×
481
            return new DateTimeZoneNormalizer();
×
482
        });
×
483

484
        $this->app->singleton(DateIntervalNormalizer::class, function (Application $app) {
×
485
            $config = $app['config'];
×
486
            $defaultContext = $config->get('api-platform.serializer', []);
×
487

488
            return new DateIntervalNormalizer(defaultContext: $defaultContext);
×
489
        });
×
490

491
        $this->app->singleton(JsonEncoder::class, function () {
×
492
            return new JsonEncoder('jsonld');
×
493
        });
×
494

495
        $this->app->bind(IriConverterInterface::class, IriConverter::class);
×
496
        $this->app->singleton(IriConverter::class, function (Application $app) {
×
497
            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));
×
498
        });
×
499

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

504
        $this->app->bind(IdentifiersExtractorInterface::class, IdentifiersExtractor::class);
×
505
        $this->app->singleton(IdentifiersExtractor::class, function (Application $app) {
×
506
            return new EloquentIdentifiersExtractor(
×
507
                new IdentifiersExtractor(
×
508
                    $app->make(ResourceMetadataCollectionFactoryInterface::class),
×
509
                    $app->make(ResourceClassResolverInterface::class),
×
510
                    $app->make(PropertyNameCollectionFactoryInterface::class),
×
511
                    $app->make(PropertyMetadataFactoryInterface::class),
×
512
                    $app->make(PropertyAccessorInterface::class)
×
513
                )
×
514
            );
×
515
        });
×
516

517
        $this->app->bind(UrlGeneratorInterface::class, UrlGeneratorRouter::class);
×
518
        $this->app->singleton(UrlGeneratorRouter::class, function (Application $app) {
×
519
            $request = $app->make('request');
×
520
            // https://github.com/laravel/framework/blob/2bfb70bca53e24227a6f921f39d84ba452efd8e0/src/Illuminate/Routing/CompiledRouteCollection.php#L112
521
            $trimmedRequest = $request->duplicate();
×
522
            $parts = explode('?', $request->server->get('REQUEST_URI'), 2);
×
523
            $trimmedRequest->server->set(
×
524
                'REQUEST_URI',
×
525
                rtrim($parts[0], '/').(isset($parts[1]) ? '?'.$parts[1] : '')
×
526
            );
×
527

528
            $urlGenerator = new UrlGeneratorRouter($app->make(Router::class));
×
529
            $urlGenerator->setContext((new RequestContext())->fromRequest($trimmedRequest));
×
530

531
            return $urlGenerator;
×
532
        });
×
533

534
        $this->app->bind(ContextBuilderInterface::class, JsonLdContextBuilder::class);
×
535
        $this->app->singleton(JsonLdContextBuilder::class, function (Application $app) {
×
536
            $config = $app['config'];
×
537
            $defaultContext = $config->get('api-platform.serializer', []);
×
538

539
            return new JsonLdContextBuilder(
×
540
                $app->make(ResourceNameCollectionFactoryInterface::class),
×
541
                $app->make(ResourceMetadataCollectionFactoryInterface::class),
×
542
                $app->make(PropertyNameCollectionFactoryInterface::class),
×
543
                $app->make(PropertyMetadataFactoryInterface::class),
×
544
                $app->make(UrlGeneratorInterface::class),
×
545
                $app->make(IriConverterInterface::class),
×
546
                $app->make(NameConverterInterface::class),
×
547
                $defaultContext
×
548
            );
×
549
        });
×
550

551
        $this->app->singleton(HydraEntrypointNormalizer::class, function (Application $app) {
×
552
            return new HydraEntrypointNormalizer($app->make(ResourceMetadataCollectionFactoryInterface::class), $app->make(IriConverterInterface::class), $app->make(UrlGeneratorInterface::class));
×
553
        });
×
554

555
        $this->app->singleton(ResourceAccessCheckerInterface::class, function () {
×
556
            return new ResourceAccessChecker();
×
557
        });
×
558

559
        $this->app->singleton(ItemNormalizer::class, function (Application $app) {
×
560
            /** @var ConfigRepository */
561
            $config = $app['config'];
×
562
            $defaultContext = $config->get('api-platform.serializer', []);
×
563

564
            return new ItemNormalizer(
×
565
                $app->make(PropertyNameCollectionFactoryInterface::class),
×
566
                $app->make(PropertyMetadataFactoryInterface::class),
×
567
                $app->make(IriConverterInterface::class),
×
568
                $app->make(ResourceClassResolverInterface::class),
×
569
                $app->make(PropertyAccessorInterface::class),
×
570
                $app->make(NameConverterInterface::class),
×
571
                $app->make(ClassMetadataFactoryInterface::class),
×
572
                $app->make(LoggerInterface::class),
×
573
                $app->make(ResourceMetadataCollectionFactoryInterface::class),
×
574
                $app->make(ResourceAccessCheckerInterface::class),
×
NEW
575
                $defaultContext,
×
NEW
576
                // $app->make(TagCollectorInterface::class)
×
577
            );
×
578
        });
×
579

580
        $this->app->bind(AnonymousContextBuilderInterface::class, JsonLdContextBuilder::class);
×
581

582
        $this->app->singleton(JsonLdObjectNormalizer::class, function (Application $app) {
×
583
            return new JsonLdObjectNormalizer(
×
584
                $app->make(ObjectNormalizer::class),
×
585
                $app->make(IriConverterInterface::class),
×
586
                $app->make(AnonymousContextBuilderInterface::class)
×
587
            );
×
588
        });
×
589

590
        $this->app->singleton(HalCollectionNormalizer::class, function (Application $app) {
×
591
            /** @var ConfigRepository */
592
            $config = $app['config'];
×
593

594
            return new HalCollectionNormalizer(
×
595
                $app->make(ResourceClassResolverInterface::class),
×
596
                $config->get('api-platform.pagination.page_parameter_name'),
×
597
                $app->make(ResourceMetadataCollectionFactoryInterface::class),
×
598
            );
×
599
        });
×
600

601
        $this->app->singleton(HalObjectNormalizer::class, function (Application $app) {
×
602
            return new HalObjectNormalizer(
×
603
                $app->make(ObjectNormalizer::class),
×
604
                $app->make(IriConverterInterface::class)
×
605
            );
×
606
        });
×
607

608
        $this->app->singleton(HalItemNormalizer::class, function (Application $app) {
×
609
            /** @var ConfigRepository */
610
            $config = $app['config'];
×
611
            $defaultContext = $config->get('api-platform.serializer', []);
×
612

613
            return new HalItemNormalizer(
×
614
                $app->make(PropertyNameCollectionFactoryInterface::class),
×
615
                $app->make(PropertyMetadataFactoryInterface::class),
×
616
                $app->make(IriConverterInterface::class),
×
617
                $app->make(ResourceClassResolverInterface::class),
×
618
                $app->make(PropertyAccessorInterface::class),
×
619
                $app->make(NameConverterInterface::class),
×
620
                $app->make(ClassMetadataFactoryInterface::class),
×
621
                $defaultContext,
×
622
                $app->make(ResourceMetadataCollectionFactoryInterface::class),
×
623
                $app->make(ResourceAccessCheckerInterface::class),
×
NEW
624
                // $app->make(TagCollectorInterface::class),
×
625
            );
×
626
        });
×
627

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

632
            return new Options(
×
633
                title: $config->get('api-platform.title', ''),
×
634
                description: $config->get('api-platform.description', ''),
×
635
                version: $config->get('api-platform.version', ''),
×
636
                oAuthEnabled: $config->get('api-platform.swagger_ui.oauth.enabled', false),
×
637
                oAuthType: $config->get('api-platform.swagger_ui.oauth.type', null),
×
638
                oAuthFlow: $config->get('api-platform.swagger_ui.oauth.flow', null),
×
639
                oAuthTokenUrl: $config->get('api-platform.swagger_ui.oauth.tokenUrl', null),
×
640
                oAuthAuthorizationUrl: $config->get('api-platform.swagger_ui.oauth.authorizationUrl', null),
×
641
                oAuthRefreshUrl: $config->get('api-platform.swagger_ui.oauth.refreshUrl', null),
×
642
                oAuthScopes: $config->get('api-platform.swagger_ui.oauth.scopes', []),
×
643
                apiKeys: $config->get('api-platform.swagger_ui.apiKeys', []),
×
644
                contactName: $config->get('api-platform.swagger_ui.contact.name', ''),
×
645
                contactUrl: $config->get('api-platform.swagger_ui.contact.url', ''),
×
646
                contactEmail: $config->get('api-platform.swagger_ui.contact.email', ''),
×
647
                licenseName: $config->get('api-platform.swagger_ui.license.name', ''),
×
648
                licenseUrl: $config->get('api-platform.swagger_ui.license.url', ''),
×
649
                persistAuthorization: $config->get('api-platform.swagger_ui.persist_authorization', false),
×
650
                httpAuth: $config->get('api-platform.swagger_ui.http_auth', []),
×
651
                tags: $config->get('api-platform.openapi.tags', []),
×
652
                errorResourceClass: Error::class,
×
653
                validationErrorResourceClass: ValidationError::class
×
654
            );
×
655
        });
×
656

657
        $this->app->singleton(SwaggerUiProcessor::class, function (Application $app) {
×
658
            /** @var ConfigRepository */
659
            $config = $app['config'];
×
660

661
            return new SwaggerUiProcessor(
×
662
                urlGenerator: $app->make(UrlGeneratorInterface::class),
×
663
                normalizer: $app->make(NormalizerInterface::class),
×
664
                openApiOptions: $app->make(Options::class),
×
665
                oauthClientId: $config->get('api-platform.swagger_ui.oauth.clientId'),
×
666
                oauthClientSecret: $config->get('api-platform.swagger_ui.oauth.clientSecret'),
×
667
                oauthPkce: $config->get('api-platform.swagger_ui.oauth.pkce', false),
×
668
            );
×
669
        });
×
670

671
        $this->app->singleton(DocumentationController::class, function (Application $app) {
×
672
            /** @var ConfigRepository */
673
            $config = $app['config'];
×
674

675
            return new DocumentationController($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'), $config->get('api-platform.swagger_ui.enabled', false));
×
676
        });
×
677

678
        $this->app->singleton(EntrypointController::class, function (Application $app) {
×
679
            /** @var ConfigRepository */
680
            $config = $app['config'];
×
681

682
            return new EntrypointController($app->make(ResourceNameCollectionFactoryInterface::class), $app->make(ProviderInterface::class), $app->make(ProcessorInterface::class), $config->get('api-platform.docs_formats'));
×
683
        });
×
684

685
        $this->app->singleton(Pagination::class, function (Application $app) {
×
686
            /** @var ConfigRepository */
687
            $config = $app['config'];
×
688

689
            return new Pagination($config->get('api-platform.pagination'), []);
×
690
        });
×
691

692
        $this->app->singleton(PaginationOptions::class, function (Application $app) {
×
693
            /** @var ConfigRepository */
694
            $config = $app['config'];
×
695
            $defaults = $config->get('api-platform.defaults');
×
696
            $pagination = $config->get('api-platform.pagination');
×
697

698
            return new PaginationOptions(
×
699
                $defaults['pagination_enabled'] ?? true,
×
700
                $pagination['page_parameter_name'] ?? 'page',
×
701
                $defaults['pagination_client_items_per_page'] ?? false,
×
702
                $pagination['items_per_page_parameter_name'] ?? 'itemsPerPage',
×
703
                $defaults['pagination_client_enabled'] ?? false,
×
704
                $pagination['enabled_parameter_name'] ?? 'pagination',
×
705
                $defaults['pagination_items_per_page'] ?? 30,
×
706
                $defaults['pagination_maximum_items_per_page'] ?? 30,
×
707
                $defaults['pagination_partial'] ?? false,
×
708
                $defaults['pagination_client_partial'] ?? false,
×
709
                $pagination['partial_parameter_name'] ?? 'partial',
×
710
            );
×
711
        });
×
712

713
        $this->app->bind(OpenApiFactoryInterface::class, OpenApiFactory::class);
×
714
        $this->app->singleton(OpenApiFactory::class, function (Application $app) {
×
715
            /** @var ConfigRepository */
716
            $config = $app['config'];
×
717

718
            return new OpenApiFactory(
×
719
                $app->make(ResourceNameCollectionFactoryInterface::class),
×
720
                $app->make(ResourceMetadataCollectionFactoryInterface::class),
×
721
                $app->make(PropertyNameCollectionFactoryInterface::class),
×
722
                $app->make(PropertyMetadataFactoryInterface::class),
×
723
                $app->make(SchemaFactoryInterface::class),
×
724
                null,
×
725
                $config->get('api-platform.formats'),
×
726
                $app->make(Options::class),
×
727
                $app->make(PaginationOptions::class),
×
728
                null,
×
729
                $config->get('api-platform.error_formats'),
×
730
                // ?RouterInterface $router = null
×
731
            );
×
732
        });
×
733

734
        $this->app->singleton(OpenApiCommand::class, function (Application $app) {
×
735
            return new OpenApiCommand($app->make(OpenApiFactory::class), $app->make(Serializer::class));
×
736
        });
×
737

738
        $this->app->bind(DefinitionNameFactoryInterface::class, DefinitionNameFactory::class);
×
739
        $this->app->singleton(DefinitionNameFactory::class, function (Application $app) {
×
740
            /** @var ConfigRepository */
741
            $config = $app['config'];
×
742

743
            return new DefinitionNameFactory($config->get('api-platform.formats'));
×
744
        });
×
745

746
        $this->app->singleton(SchemaFactory::class, function (Application $app) {
×
747
            /** @var ConfigRepository */
748
            $config = $app['config'];
×
749

750
            return new SchemaFactory(
×
751
                $app->make(ResourceMetadataCollectionFactoryInterface::class),
×
752
                $app->make(PropertyNameCollectionFactoryInterface::class),
×
753
                $app->make(PropertyMetadataFactoryInterface::class),
×
754
                $app->make(NameConverterInterface::class),
×
755
                $app->make(ResourceClassResolverInterface::class),
×
756
                $config->get('api-platform.formats'),
×
757
                $app->make(DefinitionNameFactoryInterface::class),
×
758
            );
×
759
        });
×
760
        $this->app->singleton(JsonApiSchemaFactory::class, function (Application $app) {
×
761
            return new JsonApiSchemaFactory(
×
762
                $app->make(SchemaFactory::class),
×
763
                $app->make(PropertyMetadataFactoryInterface::class),
×
764
                $app->make(ResourceClassResolverInterface::class),
×
765
                $app->make(ResourceMetadataCollectionFactoryInterface::class),
×
766
                $app->make(DefinitionNameFactoryInterface::class),
×
767
            );
×
768
        });
×
769
        $this->app->singleton(HydraSchemaFactory::class, function (Application $app) {
×
770
            $config = $app['config'];
×
771
            $defaultContext = $config->get('api-platform.serializer', []);
×
772

773
            return new HydraSchemaFactory(
×
774
                $app->make(JsonApiSchemaFactory::class),
×
775
                $defaultContext
×
776
            );
×
777
        });
×
778

779
        $this->app->bind(SchemaFactoryInterface::class, HydraSchemaFactory::class);
×
780

781
        $this->app->singleton(OpenApiNormalizer::class, function (Application $app) {
×
782
            return new OpenApiNormalizer($app->make(ObjectNormalizer::class));
×
783
        });
×
784

785
        $this->app->singleton(HydraDocumentationNormalizer::class, function (Application $app) {
×
786
            $config = $app['config'];
×
787
            $defaultContext = $config->get('api-platform.serializer', []);
×
788
            $entrypointEnabled = $config->get('api-platform.enable_entrypoint', true);
×
789

790
            return new HydraDocumentationNormalizer(
×
791
                $app->make(ResourceMetadataCollectionFactoryInterface::class),
×
792
                $app->make(PropertyNameCollectionFactoryInterface::class),
×
793
                $app->make(PropertyMetadataFactoryInterface::class),
×
794
                $app->make(ResourceClassResolverInterface::class),
×
795
                $app->make(UrlGeneratorInterface::class),
×
796
                $app->make(NameConverterInterface::class),
×
797
                $defaultContext,
×
798
                $entrypointEnabled
×
799
            );
×
800
        });
×
801

802
        $this->app->singleton(HydraPartialCollectionViewNormalizer::class, function (Application $app) {
×
803
            $config = $app['config'];
×
804
            $defaultContext = $config->get('api-platform.serializer', []);
×
805

806
            return new HydraPartialCollectionViewNormalizer(
×
807
                new HydraCollectionFiltersNormalizer(
×
808
                    new HydraCollectionNormalizer(
×
809
                        $app->make(ContextBuilderInterface::class),
×
810
                        $app->make(ResourceClassResolverInterface::class),
×
811
                        $app->make(IriConverterInterface::class),
×
812
                        $defaultContext
×
813
                    ),
×
814
                    $app->make(ResourceMetadataCollectionFactoryInterface::class),
×
815
                    $app->make(ResourceClassResolverInterface::class),
×
816
                    null, // filterLocator, we use only Parameters with Laravel and we don't need to call filters there
×
817
                    $defaultContext
×
818
                ),
×
819
                'page',
×
820
                'pagination',
×
821
                $app->make(ResourceMetadataCollectionFactoryInterface::class),
×
822
                $app->make(PropertyAccessorInterface::class),
×
823
                $config->get('api-platform.url_generation_strategy', UrlGeneratorInterface::ABS_PATH),
×
824
                $defaultContext,
×
825
            );
×
826
        });
×
827

828
        $this->app->singleton(ReservedAttributeNameConverter::class, function (Application $app) {
×
829
            return new ReservedAttributeNameConverter($app->make(NameConverterInterface::class));
×
830
        });
×
831

832
        if (interface_exists(FieldsBuilderEnumInterface::class)) {
×
833
            $this->registerGraphQl();
×
834
        }
835

836
        $this->app->singleton(JsonApiEntrypointNormalizer::class, function (Application $app) {
×
837
            return new JsonApiEntrypointNormalizer(
×
838
                $app->make(ResourceMetadataCollectionFactoryInterface::class),
×
839
                $app->make(IriConverterInterface::class),
×
840
                $app->make(UrlGeneratorInterface::class),
×
841
            );
×
842
        });
×
843

844
        $this->app->singleton(JsonApiCollectionNormalizer::class, function (Application $app) {
×
845
            /** @var ConfigRepository */
846
            $config = $app['config'];
×
847

848
            return new JsonApiCollectionNormalizer(
×
849
                $app->make(ResourceClassResolverInterface::class),
×
850
                $config->get('api-platform.pagination.page_parameter_name'),
×
851
                $app->make(ResourceMetadataCollectionFactoryInterface::class),
×
852
            );
×
853
        });
×
854

855
        $this->app->singleton(JsonApiItemNormalizer::class, function (Application $app) {
×
856
            $config = $app['config'];
×
857
            $defaultContext = $config->get('api-platform.serializer', []);
×
858

859
            return new JsonApiItemNormalizer(
×
860
                $app->make(PropertyNameCollectionFactoryInterface::class),
×
861
                $app->make(PropertyMetadataFactoryInterface::class),
×
862
                $app->make(IriConverterInterface::class),
×
863
                $app->make(ResourceClassResolverInterface::class),
×
864
                $app->make(PropertyAccessorInterface::class),
×
865
                $app->make(NameConverterInterface::class),
×
866
                $app->make(ClassMetadataFactoryInterface::class),
×
867
                $defaultContext,
×
868
                $app->make(ResourceMetadataCollectionFactoryInterface::class),
×
869
                $app->make(ResourceAccessCheckerInterface::class),
×
870
                // $app->make(TagCollectorInterface::class),
×
871
            );
×
872
        });
×
873

874
        $this->app->singleton(JsonApiErrorNormalizer::class, function (Application $app) {
×
875
            return new JsonApiErrorNormalizer(
×
876
                $app->make(JsonApiItemNormalizer::class),
×
877
            );
×
878
        });
×
879

880
        $this->app->singleton(JsonApiObjectNormalizer::class, function (Application $app) {
×
881
            return new JsonApiObjectNormalizer(
×
882
                $app->make(ObjectNormalizer::class),
×
883
                $app->make(IriConverterInterface::class),
×
884
                $app->make(ResourceClassResolverInterface::class),
×
885
                $app->make(ResourceMetadataCollectionFactoryInterface::class),
×
886
            );
×
887
        });
×
888

889
        $this->app->singleton('api_platform_normalizer_list', function (Application $app) {
×
890
            $list = new \SplPriorityQueue();
×
891
            $list->insert($app->make(HydraEntrypointNormalizer::class), -800);
×
892
            $list->insert($app->make(HydraPartialCollectionViewNormalizer::class), -800);
×
893
            $list->insert($app->make(HalCollectionNormalizer::class), -800);
×
894
            $list->insert($app->make(HalEntrypointNormalizer::class), -985);
×
895
            $list->insert($app->make(HalObjectNormalizer::class), -995);
×
896
            $list->insert($app->make(HalItemNormalizer::class), -890);
×
897
            $list->insert($app->make(JsonLdItemNormalizer::class), -890);
×
898
            $list->insert($app->make(JsonLdObjectNormalizer::class), -995);
×
899
            $list->insert($app->make(ArrayDenormalizer::class), -990);
×
900
            $list->insert($app->make(DateTimeZoneNormalizer::class), -915);
×
901
            $list->insert($app->make(DateIntervalNormalizer::class), -915);
×
902
            $list->insert($app->make(DateTimeNormalizer::class), -910);
×
903
            $list->insert($app->make(BackedEnumNormalizer::class), -910);
×
904
            $list->insert($app->make(ObjectNormalizer::class), -1000);
×
905
            $list->insert($app->make(ItemNormalizer::class), -895);
×
906
            $list->insert($app->make(OpenApiNormalizer::class), -780);
×
907
            $list->insert($app->make(HydraDocumentationNormalizer::class), -790);
×
908

909
            $list->insert($app->make(JsonApiEntrypointNormalizer::class), -800);
×
910
            $list->insert($app->make(JsonApiCollectionNormalizer::class), -985);
×
911
            $list->insert($app->make(JsonApiItemNormalizer::class), -890);
×
912
            $list->insert($app->make(JsonApiErrorNormalizer::class), -790);
×
913
            $list->insert($app->make(JsonApiObjectNormalizer::class), -995);
×
914

915
            if (interface_exists(FieldsBuilderEnumInterface::class)) {
×
916
                $list->insert($app->make(GraphQlItemNormalizer::class), -890);
×
917
                $list->insert($app->make(GraphQlObjectNormalizer::class), -995);
×
918
                $list->insert($app->make(GraphQlErrorNormalizer::class), -790);
×
919
                $list->insert($app->make(GraphQlValidationExceptionNormalizer::class), -780);
×
920
                $list->insert($app->make(GraphQlHttpExceptionNormalizer::class), -780);
×
921
                $list->insert($app->make(GraphQlRuntimeExceptionNormalizer::class), -780);
×
922
            }
923

924
            return $list;
×
925
        });
×
926

927
        $this->app->bind(SerializerInterface::class, Serializer::class);
×
928
        $this->app->bind(NormalizerInterface::class, Serializer::class);
×
929
        $this->app->singleton(Serializer::class, function (Application $app) {
×
930
            // TODO: unused + implement hal/jsonapi ?
931
            // $list->insert($dataUriNormalizer, -920);
932
            // $list->insert($unwrappingDenormalizer, 1000);
933
            // $list->insert($jsonserializableNormalizer, -900);
934
            // $list->insert($uuidDenormalizer, -895); //Todo ramsey uuid support ?
935

936
            return new Serializer(
×
937
                iterator_to_array($app->make('api_platform_normalizer_list')),
×
938
                [
×
939
                    new JsonEncoder('json'),
×
940
                    $app->make(JsonEncoder::class),
×
941
                    new JsonEncoder('jsonopenapi'),
×
942
                    new JsonEncoder('jsonapi'),
×
943
                    new JsonEncoder('jsonhal'),
×
944
                    new CsvEncoder(),
×
945
                ]
×
946
            );
×
947
        });
×
948

949
        $this->app->singleton(JsonLdItemNormalizer::class, function (Application $app) {
×
950
            $config = $app['config'];
×
951
            $defaultContext = $config->get('api-platform.serializer', []);
×
952

953
            return new JsonLdItemNormalizer(
×
954
                $app->make(ResourceMetadataCollectionFactoryInterface::class),
×
955
                $app->make(PropertyNameCollectionFactoryInterface::class),
×
956
                $app->make(PropertyMetadataFactoryInterface::class),
×
957
                $app->make(IriConverterInterface::class),
×
958
                $app->make(ResourceClassResolverInterface::class),
×
959
                $app->make(ContextBuilderInterface::class),
×
960
                $app->make(PropertyAccessorInterface::class),
×
961
                $app->make(NameConverterInterface::class),
×
962
                $app->make(ClassMetadataFactoryInterface::class),
×
963
                $defaultContext,
×
NEW
964
                $app->make(ResourceAccessCheckerInterface::class),
×
NEW
965
                // $app->make(TagCollectorInterface::class)
×
966
            );
×
967
        });
×
968

969
        $this->app->singleton(InflectorInterface::class, function (Application $app) {
×
970
            return new Inflector();
×
971
        });
×
972

973
        if ($this->app->runningInConsole()) {
×
974
            $this->commands([
×
975
                Console\InstallCommand::class,
×
976
                Console\Maker\MakeStateProcessorCommand::class,
×
977
                Console\Maker\MakeStateProviderCommand::class,
×
978
                OpenApiCommand::class,
×
979
            ]);
×
980
        }
981
    }
982

983
    private function registerGraphQl(): void
984
    {
985
        $this->app->singleton(GraphQlItemNormalizer::class, function (Application $app) {
×
986
            return new GraphQlItemNormalizer(
×
987
                $app->make(PropertyNameCollectionFactoryInterface::class),
×
988
                $app->make(PropertyMetadataFactoryInterface::class),
×
989
                $app->make(IriConverterInterface::class),
×
990
                $app->make(IdentifiersExtractorInterface::class),
×
991
                $app->make(ResourceClassResolverInterface::class),
×
992
                $app->make(PropertyAccessorInterface::class),
×
993
                $app->make(NameConverterInterface::class),
×
994
                $app->make(SerializerClassMetadataFactory::class),
×
995
                null,
×
996
                $app->make(ResourceMetadataCollectionFactoryInterface::class),
×
997
                $app->make(ResourceAccessCheckerInterface::class)
×
998
            );
×
999
        });
×
1000

1001
        $this->app->singleton(GraphQlObjectNormalizer::class, function (Application $app) {
×
1002
            return new GraphQlObjectNormalizer(
×
1003
                $app->make(ObjectNormalizer::class),
×
1004
                $app->make(IriConverterInterface::class),
×
1005
                $app->make(IdentifiersExtractorInterface::class),
×
1006
            );
×
1007
        });
×
1008

1009
        $this->app->singleton(GraphQlErrorNormalizer::class, function () {
×
1010
            return new GraphQlErrorNormalizer();
×
1011
        });
×
1012

1013
        $this->app->singleton(GraphQlValidationExceptionNormalizer::class, function (Application $app) {
×
1014
            /** @var ConfigRepository */
1015
            $config = $app['config'];
×
1016

1017
            return new GraphQlValidationExceptionNormalizer($config->get('api-platform.exception_to_status'));
×
1018
        });
×
1019

1020
        $this->app->singleton(GraphQlHttpExceptionNormalizer::class, function () {
×
1021
            return new GraphQlHttpExceptionNormalizer();
×
1022
        });
×
1023

1024
        $this->app->singleton(GraphQlRuntimeExceptionNormalizer::class, function () {
×
1025
            return new GraphQlHttpExceptionNormalizer();
×
1026
        });
×
1027

1028
        $this->app->singleton('api_platform.graphql.type_locator', function (Application $app) {
×
1029
            $tagged = iterator_to_array($app->tagged('api_platform.graphql.type'));
×
1030
            $services = [];
×
1031
            foreach ($tagged as $service) {
×
1032
                $services[$service->name] = $service;
×
1033
            }
1034

1035
            return new ServiceLocator($services);
×
1036
        });
×
1037

1038
        $this->app->singleton(TypesFactoryInterface::class, function (Application $app) {
×
1039
            $tagged = iterator_to_array($app->tagged('api_platform.graphql.type'));
×
1040

1041
            return new TypesFactory($app->make('api_platform.graphql.type_locator'), array_column($tagged, 'name'));
×
1042
        });
×
1043

1044
        $this->app->singleton(TypesContainerInterface::class, function () {
×
1045
            return new TypesContainer();
×
1046
        });
×
1047

1048
        $this->app->singleton(ResourceFieldResolver::class, function (Application $app) {
×
1049
            return new ResourceFieldResolver($app->make(IriConverterInterface::class));
×
1050
        });
×
1051

1052
        $this->app->singleton(ContextAwareTypeBuilderInterface::class, function (Application $app) {
×
1053
            return new TypeBuilder(
×
1054
                $app->make(TypesContainerInterface::class),
×
1055
                $app->make(ResourceFieldResolver::class),
×
1056
                null,
×
1057
                $app->make(Pagination::class)
×
1058
            );
×
1059
        });
×
1060

1061
        $this->app->singleton(TypeConverterInterface::class, function (Application $app) {
×
1062
            return new TypeConverter(
×
1063
                $app->make(ContextAwareTypeBuilderInterface::class),
×
1064
                $app->make(TypesContainerInterface::class),
×
1065
                $app->make(ResourceMetadataCollectionFactoryInterface::class),
×
1066
                $app->make(PropertyMetadataFactoryInterface::class),
×
1067
            );
×
1068
        });
×
1069

1070
        $this->app->singleton(GraphQlSerializerContextBuilder::class, function (Application $app) {
×
1071
            return new GraphQlSerializerContextBuilder($app->make(NameConverterInterface::class));
×
1072
        });
×
1073

1074
        $this->app->singleton(GraphQlReadProvider::class, function (Application $app) {
×
1075
            /** @var ConfigRepository */
1076
            $config = $app['config'];
×
1077

1078
            return new GraphQlReadProvider(
×
1079
                $this->app->make(CallableProvider::class),
×
1080
                $app->make(IriConverterInterface::class),
×
1081
                $app->make(GraphQlSerializerContextBuilder::class),
×
1082
                $config->get('api-platform.graphql.nesting_separator') ?? '__'
×
1083
            );
×
1084
        });
×
1085
        $this->app->alias(GraphQlReadProvider::class, 'api_platform.graphql.state_provider.read');
×
1086

1087
        $this->app->singleton(ErrorProvider::class, function (Application $app) {
×
1088
            /** @var ConfigRepository */
1089
            $config = $app['config'];
×
1090

1091
            return new ErrorProvider(
×
1092
                $config->get('app.debug'),
×
1093
                $app->make(ResourceClassResolver::class),
×
1094
                $app->make(ResourceMetadataCollectionFactoryInterface::class),
×
1095
            );
×
1096
        });
×
1097

1098
        $this->app->singleton(ResolverProvider::class, function (Application $app) {
×
1099
            $resolvers = iterator_to_array($app->tagged('api_platform.graphql.resolver'));
×
1100
            $taggedItemResolvers = iterator_to_array($app->tagged(QueryItemResolverInterface::class));
×
1101
            $taggedCollectionResolvers = iterator_to_array($app->tagged(QueryCollectionResolverInterface::class));
×
1102

1103
            return new ResolverProvider(
×
1104
                $app->make(GraphQlReadProvider::class),
×
1105
                new ServiceLocator([...$resolvers, ...$taggedItemResolvers, ...$taggedCollectionResolvers]),
×
1106
            );
×
1107
        });
×
1108

1109
        $this->app->alias(ResolverProvider::class, 'api_platform.graphql.state_provider.resolver');
×
1110

1111
        $this->app->singleton(GraphQlDenormalizeProvider::class, function (Application $app) {
×
1112
            return new GraphQlDenormalizeProvider(
×
1113
                $this->app->make(ResolverProvider::class),
×
1114
                $app->make(SerializerInterface::class),
×
1115
                $app->make(GraphQlSerializerContextBuilder::class)
×
1116
            );
×
1117
        });
×
1118

1119
        $this->app->alias(GraphQlDenormalizeProvider::class, 'api_platform.graphql.state_provider.denormalize');
×
1120

1121
        $this->app->singleton('api_platform.graphql.state_provider.access_checker', function (Application $app) {
×
1122
            return new AccessCheckerProvider($app->make('api_platform.graphql.state_provider.parameter'), $app->make(ResourceAccessCheckerInterface::class));
×
1123
        });
×
1124

1125
        $this->app->singleton(NormalizeProcessor::class, function (Application $app) {
×
1126
            return new NormalizeProcessor(
×
1127
                $app->make(SerializerInterface::class),
×
1128
                $app->make(GraphQlSerializerContextBuilder::class),
×
1129
                $app->make(Pagination::class)
×
1130
            );
×
1131
        });
×
1132
        $this->app->alias(NormalizeProcessor::class, 'api_platform.graphql.state_processor.normalize');
×
1133

1134
        $this->app->singleton('api_platform.graphql.state_processor', function (Application $app) {
×
1135
            return new WriteProcessor(
×
1136
                $app->make('api_platform.graphql.state_processor.normalize'),
×
1137
                $app->make(CallableProcessor::class),
×
1138
            );
×
1139
        });
×
1140

1141
        $this->app->singleton(ResolverFactoryInterface::class, function (Application $app) {
×
1142
            return new ResolverFactory(
×
1143
                $app->make('api_platform.graphql.state_provider.access_checker'),
×
1144
                $app->make('api_platform.graphql.state_processor'),
×
1145
                $app->make('api_platform.graphql.runtime_operation_metadata_factory'),
×
1146
            );
×
1147
        });
×
1148

1149
        $this->app->singleton('api_platform.graphql.runtime_operation_metadata_factory', function (Application $app) {
×
1150
            return new RuntimeOperationMetadataFactory(
×
1151
                $app->make(ResourceMetadataCollectionFactoryInterface::class),
×
1152
                $app->make(UrlGeneratorRouter::class)
×
1153
            );
×
1154
        });
×
1155

1156
        $this->app->singleton(SchemaBuilderInterface::class, function (Application $app) {
×
1157
            return new SchemaBuilder($app->make(ResourceNameCollectionFactoryInterface::class), $app->make(ResourceMetadataCollectionFactoryInterface::class), $app->make(TypesFactoryInterface::class), $app->make(TypesContainerInterface::class), $app->make(FieldsBuilderEnumInterface::class));
×
1158
        });
×
1159

1160
        $this->app->singleton(ErrorHandlerInterface::class, function () {
×
1161
            return new GraphQlErrorHandler();
×
1162
        });
×
1163

1164
        $this->app->singleton(ExecutorInterface::class, function (Application $app) {
×
1165
            /** @var ConfigRepository */
1166
            $config = $app['config'];
×
1167

1168
            return new Executor($config->get('api-platform.graphql.introspection.enabled') ?? false, $config->get('api-platform.graphql.max_query_complexity') ?? 500, $config->get('api-platform.graphql.max_query_depth') ?? 200);
×
1169
        });
×
1170

1171
        $this->app->singleton(GraphiQlController::class, function (Application $app) {
×
1172
            /** @var ConfigRepository */
1173
            $config = $app['config'];
×
1174
            $prefix = $config->get('api-platform.defaults.route_prefix') ?? '';
×
1175

1176
            return new GraphiQlController($prefix);
×
1177
        });
×
1178

1179
        $this->app->singleton(GraphQlEntrypointController::class, function (Application $app) {
×
1180
            /** @var ConfigRepository */
1181
            $config = $app['config'];
×
1182

1183
            return new GraphQlEntrypointController(
×
1184
                $app->make(SchemaBuilderInterface::class),
×
1185
                $app->make(ExecutorInterface::class),
×
1186
                $app->make(GraphiQlController::class),
×
1187
                $app->make(SerializerInterface::class),
×
1188
                $app->make(ErrorHandlerInterface::class),
×
1189
                debug: $config->get('app.debug'),
×
1190
                negotiator: $app->make(Negotiator::class),
×
1191
                formats: $config->get('api-platform.formats')
×
1192
            );
×
1193
        });
×
1194
    }
1195

1196
    /**
1197
     * Bootstrap services.
1198
     */
1199
    public function boot(): void
1200
    {
1201
        if ($this->app->runningInConsole()) {
×
1202
            $this->publishes([
×
1203
                __DIR__.'/config/api-platform.php' => $this->app->configPath('api-platform.php'),
×
1204
            ], 'api-platform-config');
×
1205

1206
            $this->publishes([
×
1207
                __DIR__.'/public' => $this->app->publicPath('vendor/api-platform'),
×
1208
            ], ['api-platform-assets', 'public']);
×
1209
        }
1210

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

1213
        $config = $this->app['config'];
×
1214

1215
        if ($config->get('api-platform.graphql.enabled')) {
×
1216
            $fieldsBuilder = $this->app->make(FieldsBuilderEnumInterface::class);
×
1217
            $typeBuilder = $this->app->make(ContextAwareTypeBuilderInterface::class);
×
1218
            $typeBuilder->setFieldsBuilderLocator(new ServiceLocator(['api_platform.graphql.fields_builder' => $fieldsBuilder]));
×
1219
        }
1220

1221
        $this->loadRoutesFrom(__DIR__.'/routes/api.php');
×
1222
    }
1223
}
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

© 2026 Coveralls, Inc