Skip to content

Commit 15dcaa4

Browse files
committed
feat(metadata) Customize Resource & operations
1 parent cb0dd58 commit 15dcaa4

File tree

8 files changed

+175
-0
lines changed

8 files changed

+175
-0
lines changed

src/Metadata/AsResourceMutator.php

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the API Platform project.
5+
*
6+
* (c) Kévin Dunglas <[email protected]>
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\Metadata;
15+
16+
#[\Attribute(\Attribute::TARGET_CLASS)]
17+
final class AsResourceMutator
18+
{
19+
/**
20+
* @param class-string $resourceClass
21+
*/
22+
public function __construct(
23+
public readonly string $resourceClass,
24+
) {
25+
}
26+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the API Platform project.
5+
*
6+
* (c) Kévin Dunglas <[email protected]>
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\Metadata\Mutator;
15+
16+
use Psr\Container\ContainerInterface;
17+
18+
final class ResourceMutatorCollection implements ContainerInterface
19+
{
20+
private array $mutators;
21+
22+
public function addMutator(string $resourceClass, object $mutator): void
23+
{
24+
$this->mutators[$resourceClass][] = $mutator;
25+
}
26+
27+
public function get(string $id): array
28+
{
29+
return $this->mutators[$id] ?? [];
30+
}
31+
32+
public function has(string $id): bool
33+
{
34+
return isset($this->mutators[$id]);
35+
}
36+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the API Platform project.
5+
*
6+
* (c) Kévin Dunglas <[email protected]>
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\Metadata\Resource\Factory;
15+
16+
use ApiPlatform\Metadata\Resource\ResourceMetadataCollection;
17+
use Psr\Container\ContainerInterface;
18+
19+
final class CustomResourceMetadataCollectionFactory implements ResourceMetadataCollectionFactoryInterface
20+
{
21+
public function __construct(
22+
private readonly ContainerInterface $resourceMutators,
23+
private readonly ?ResourceMetadataCollectionFactoryInterface $decorated = null,
24+
) {
25+
}
26+
27+
public function create(string $resourceClass): ResourceMetadataCollection
28+
{
29+
$resourceMetadataCollection = new ResourceMetadataCollection($resourceClass);
30+
if ($this->decorated) {
31+
$resourceMetadataCollection = $this->decorated->create($resourceClass);
32+
}
33+
34+
$newMetadataCollection = new ResourceMetadataCollection($resourceClass);
35+
36+
foreach ($resourceMetadataCollection as $resource) {
37+
foreach ($this->resourceMutators->get($resourceClass) as $mutators) {
38+
$resource = $mutators($resource);
39+
}
40+
41+
$newMetadataCollection[] = $resource;
42+
}
43+
44+
return $newMetadataCollection;
45+
}
46+
}

src/Symfony/Bundle/ApiPlatformBundle.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
use ApiPlatform\Symfony\Bundle\DependencyInjection\Compiler\GraphQlResolverPass;
2525
use ApiPlatform\Symfony\Bundle\DependencyInjection\Compiler\GraphQlTypePass;
2626
use ApiPlatform\Symfony\Bundle\DependencyInjection\Compiler\MetadataAwareNameConverterPass;
27+
use ApiPlatform\Symfony\Bundle\DependencyInjection\Compiler\MutatorPass;
2728
use ApiPlatform\Symfony\Bundle\DependencyInjection\Compiler\SerializerMappingLoaderPass;
2829
use ApiPlatform\Symfony\Bundle\DependencyInjection\Compiler\TestClientPass;
2930
use ApiPlatform\Symfony\Bundle\DependencyInjection\Compiler\TestMercureHubPass;
@@ -62,5 +63,6 @@ public function build(ContainerBuilder $container): void
6263
$container->addCompilerPass(new TestMercureHubPass());
6364
$container->addCompilerPass(new AuthenticatorManagerPass());
6465
$container->addCompilerPass(new SerializerMappingLoaderPass());
66+
$container->addCompilerPass(new MutatorPass());
6567
}
6668
}

src/Symfony/Bundle/DependencyInjection/ApiPlatformExtension.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
use ApiPlatform\GraphQl\Resolver\QueryItemResolverInterface;
3232
use ApiPlatform\GraphQl\Type\Definition\TypeInterface as GraphQlTypeInterface;
3333
use ApiPlatform\Metadata\ApiResource;
34+
use ApiPlatform\Metadata\AsResourceMutator;
3435
use ApiPlatform\Metadata\FilterInterface;
3536
use ApiPlatform\Metadata\UriVariableTransformerInterface;
3637
use ApiPlatform\Metadata\UrlGeneratorInterface;
@@ -184,6 +185,13 @@ public function load(array $configs, ContainerBuilder $container): void
184185
->addTag('api_platform.resource')
185186
->addTag('container.excluded', ['source' => 'by #[ApiResource] attribute']);
186187
});
188+
$container->registerAttributeForAutoconfiguration(AsResourceMutator::class,
189+
static function (ChildDefinition $definition, AsResourceMutator $attribute): void {
190+
$definition->addTag('api_platform.resource_mutator', [
191+
'resourceClass' => $attribute->resourceClass,
192+
]);
193+
},
194+
);
187195

188196
if (!$container->has('api_platform.state.item_provider')) {
189197
$container->setAlias('api_platform.state.item_provider', 'api_platform.state_provider.object');
@@ -341,6 +349,7 @@ private function registerMetadataConfiguration(ContainerBuilder $container, arra
341349
$loader->load('metadata/property.xml');
342350
$loader->load('metadata/resource.xml');
343351
$loader->load('metadata/operation.xml');
352+
$loader->load('metadata/mutator.xml');
344353

345354
$container->getDefinition('api_platform.metadata.resource_extractor.xml')->replaceArgument(0, $xmlResources);
346355
$container->getDefinition('api_platform.metadata.property_extractor.xml')->replaceArgument(0, $xmlResources);
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the API Platform project.
5+
*
6+
* (c) Kévin Dunglas <[email protected]>
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\Symfony\Bundle\DependencyInjection\Compiler;
15+
16+
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
17+
use Symfony\Component\DependencyInjection\ContainerBuilder;
18+
use Symfony\Component\DependencyInjection\Reference;
19+
20+
class MutatorPass implements CompilerPassInterface
21+
{
22+
public function process(ContainerBuilder $container): void
23+
{
24+
if (!$container->hasDefinition('api_platform.metadata.mutator_collection.resource')) {
25+
return;
26+
}
27+
28+
$definition = $container->getDefinition('api_platform.metadata.mutator_collection.resource');
29+
30+
$mutators = $container->findTaggedServiceIds('api_platform.resource_mutator');
31+
32+
foreach ($mutators as $id => $tags) {
33+
foreach ($tags as $tag) {
34+
$definition->addMethodCall('addMutator', [
35+
$tag['resourceClass'],
36+
new Reference($id),
37+
]);
38+
}
39+
}
40+
}
41+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?xml version="1.0" ?>
2+
3+
<container xmlns="http://symfony.com/schema/dic/services"
4+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5+
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
6+
7+
<services>
8+
<service id="api_platform.metadata.mutator_collection.resource" class="ApiPlatform\Metadata\Mutator\ResourceMutatorCollection" public="false" />
9+
</services>
10+
</container>

src/Symfony/Bundle/Resources/config/metadata/resource.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,11 @@
3030
<argument type="service" id="service_container" on-invalid="null" />
3131
</service>
3232

33+
<service id="api_platform.metadata.resource.metadata_collection_factory.custom" class="ApiPlatform\Metadata\Resource\Factory\CustomResourceMetadataCollectionFactory" decorates="api_platform.metadata.resource.metadata_collection_factory" decoration-priority="800" public="false" >
34+
<argument type="service" id="api_platform.metadata.mutator_collection.resource" />
35+
<argument type="service" id="api_platform.metadata.resource.metadata_collection_factory.custom.inner" />
36+
</service>
37+
3338
<service id="api_platform.metadata.resource.metadata_collection_factory.concerns" class="ApiPlatform\Metadata\Resource\Factory\ConcernsResourceMetadataCollectionFactory" decorates="api_platform.metadata.resource.metadata_collection_factory" decoration-priority="800" public="false">
3439
<argument type="service" id="api_platform.metadata.resource.metadata_collection_factory.concerns.inner" />
3540
</service>

0 commit comments

Comments
 (0)