Skip to content

Commit ee54704

Browse files
feat(metadata) Customize Resource & operations (#1055)
| Q | A | --------------- | ----- | Bug fix? | no | New feature? | yes | BC breaks? | no | Deprecations? | no | Related tickets | | License | MIT It's the same feature as [this APIP one](api-platform/core#7213). We need this feature for [this issue](Sylius/Sylius#18212).
2 parents 6197587 + a81d31b commit ee54704

22 files changed

+638
-6
lines changed

phpstan.neon

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ parameters:
4444
# return type mixed of method ParameterBag::get()"
4545
- 'src/Bundle/Controller/Parameters.php'
4646

47+
# ResourceMetadata will need to use the generic T
48+
- 'src/Component/src/Metadata/ResourceMetadata.php'
49+
4750
ignoreErrors:
4851
# Optional MongoDB ODM support - requires doctrine/mongodb-odm-bundle package
4952
# These classes are only loaded when MongoDB driver is configured and the bundle is installed
@@ -94,6 +97,9 @@ parameters:
9497
# See: src/Bundle/DependencyInjection/Configuration.php:30-37
9598
- '/Call to an undefined method Symfony\\Component\\Config\\Definition\\Builder\\NodeParentInterface::(end|variableNode|scalarNode)\(\)/'
9699

100+
# Symfony Dependency Injection Component can use ReflectionClass type as second argument instead of Reflector one.
101+
- '/Parameter #2 \$configurator of method Symfony\\Component\\DependencyInjection\\ContainerBuilder::registerAttributeForAutoconfiguration\(\)/'
102+
97103
# Backward compatibility for Symfony DependencyInjection Alias::setDeprecated()
98104
# Method signature changed between Symfony versions:
99105
# - Symfony < 5.1: setDeprecated($status, $message)

psalm.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
<referencedFunction name="Doctrine\Persistence\ObjectManager::getClassMetadata" />
4040
<referencedFunction name="ReflectionClass::getAttributes" />
4141
<file name="src/Bundle/Form/DataTransformer/CollectionToStringTransformer.php" />
42+
<file name="src/Bundle/DependencyInjection/SyliusResourceExtension.php" />
4243
<file name="src/Component/src/Doctrine/Persistence/InMemoryRepository.php" />
4344
<file name="src/Component/src/Symfony/Request/State/Provider.php" />
4445
</errorLevel>
@@ -153,6 +154,12 @@
153154
</errorLevel>
154155
</MissingClassConstType>
155156

157+
<MissingConstructor>
158+
<errorLevel type="suppress">
159+
<file name="src/Component/src/Metadata/Mutator/ResourceMutatorCollection.php" />
160+
</errorLevel>
161+
</MissingConstructor>
162+
156163
<MissingParamType>
157164
<errorLevel type="suppress">
158165
<file name="src/Bundle/Routing/ResourceLoader.php" />

src/Bundle/DependencyInjection/SyliusResourceExtension.php

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,13 @@
2323
use Sylius\Component\Resource\Factory\FactoryInterface as LegacyFactoryInterface;
2424
use Sylius\Resource\Factory\Factory;
2525
use Sylius\Resource\Factory\FactoryInterface;
26+
use Sylius\Resource\Metadata\AsOperationMutator;
2627
use Sylius\Resource\Metadata\AsResource;
28+
use Sylius\Resource\Metadata\AsResourceMutator;
2729
use Sylius\Resource\Metadata\Metadata;
30+
use Sylius\Resource\Metadata\OperationMutatorInterface;
2831
use Sylius\Resource\Metadata\ResourceMetadata;
32+
use Sylius\Resource\Metadata\ResourceMutatorInterface;
2933
use Sylius\Resource\Reflection\ClassReflection;
3034
use Sylius\Resource\State\ProcessorInterface;
3135
use Sylius\Resource\State\ProviderInterface;
@@ -34,6 +38,7 @@
3438
use Symfony\Component\Config\FileLocator;
3539
use Symfony\Component\Config\Loader\LoaderInterface;
3640
use Symfony\Component\Config\Resource\DirectoryResource;
41+
use Symfony\Component\DependencyInjection\ChildDefinition;
3742
use Symfony\Component\DependencyInjection\ContainerBuilder;
3843
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
3944
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
@@ -76,6 +81,32 @@ public function load(array $configs, ContainerBuilder $container): void
7681
$this->loadPersistence($config['drivers'], $config['resources'], $loader, $container);
7782
$this->loadResources($config['resources'], $container);
7883

84+
$container->registerAttributeForAutoconfiguration(
85+
AsResourceMutator::class,
86+
static function (ChildDefinition $definition, AsResourceMutator $attribute, \ReflectionClass $reflector): void {
87+
if (!is_a($reflector->name, ResourceMutatorInterface::class, true)) {
88+
throw new RuntimeException(\sprintf('Resource mutator "%s" should implement %s', $reflector->name, ResourceMutatorInterface::class));
89+
}
90+
91+
$definition->addTag('sylius.resource_mutator', [
92+
'resourceClass' => $attribute->resourceClass,
93+
]);
94+
},
95+
);
96+
97+
$container->registerAttributeForAutoconfiguration(
98+
AsOperationMutator::class,
99+
static function (ChildDefinition $definition, AsOperationMutator $attribute, \ReflectionClass $reflector): void {
100+
if (!is_a($reflector->name, OperationMutatorInterface::class, true)) {
101+
throw new RuntimeException(\sprintf('Operation mutator "%s" should implement %s', $reflector->name, OperationMutatorInterface::class));
102+
}
103+
104+
$definition->addTag('sylius.operation_mutator', [
105+
'operationName' => $attribute->operationName,
106+
]);
107+
},
108+
);
109+
79110
$container->registerForAutoconfiguration(ProviderInterface::class)
80111
->addTag('sylius.state_provider')
81112
;

src/Bundle/Resources/config/services/metadata/extractor.xml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,16 @@
1+
<?xml version="1.0" ?>
2+
3+
<!--
4+
5+
This file is part of the Sylius package.
6+
7+
(c) Sylius Sp. z o.o.
8+
9+
For the full copyright and license information, please view the LICENSE
10+
file that was distributed with this source code.
11+
12+
-->
13+
114
<container xmlns="http://symfony.com/schema/dic/services" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
215
<services>
316
<service id="sylius.metadata.resource_extractor.php_file" class="Sylius\Resource\Metadata\Extractor\PhpFileResourceExtractor" public="false">
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?xml version="1.0" ?>
2+
3+
<!--
4+
5+
This file is part of the Sylius package.
6+
7+
(c) Sylius Sp. z o.o.
8+
9+
For the full copyright and license information, please view the LICENSE
10+
file that was distributed with this source code.
11+
12+
-->
13+
14+
<container xmlns="http://symfony.com/schema/dic/services"
15+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
16+
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
17+
18+
<services>
19+
<service id="sylius.metadata.mutator_collection.resource" class="Sylius\Resource\Metadata\Mutator\ResourceMutatorCollection" public="false" />
20+
21+
<service id="sylius.metadata.mutator_collection.operation" class="Sylius\Resource\Metadata\Mutator\OperationMutatorCollection" public="false" />
22+
</services>
23+
</container>

src/Bundle/Resources/config/services/metadata/resource_metadata_collection.xml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,15 @@
3636
<argument type="service" id=".inner" />
3737
</service>
3838

39+
<service id="sylius.metadata.resource.metadata_collection_factory.mutator"
40+
class="Sylius\Resource\Metadata\Resource\Factory\MutatorResourceMetadataCollectionFactory"
41+
decorates="sylius.resource_metadata_collection.factory"
42+
decoration-priority="400">
43+
<argument type="service" id="sylius.metadata.mutator_collection.resource" />
44+
<argument type="service" id="sylius.metadata.mutator_collection.operation" />
45+
<argument type="service" id=".inner" />
46+
</service>
47+
3948
<service id="sylius.resource_metadata_collection.factory.state_machine"
4049
class="Sylius\Resource\Metadata\Resource\Factory\StateMachineResourceMetadataCollectionFactory"
4150
decorates="sylius.resource_metadata_collection.factory"

src/Bundle/SyliusResourceBundle.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
use Sylius\Bundle\ResourceBundle\DependencyInjection\PagerfantaExtension;
3232
use Sylius\Resource\Symfony\DependencyInjection\Compiler\DisableMetadataCachePass;
3333
use Sylius\Resource\Symfony\DependencyInjection\Compiler\FallbackToKernelDefaultLocalePass;
34+
use Sylius\Resource\Symfony\DependencyInjection\Compiler\MetadataMutatorPass;
3435
use Symfony\Component\DependencyInjection\Compiler\PassConfig;
3536
use Symfony\Component\DependencyInjection\ContainerBuilder;
3637
use Symfony\Component\HttpKernel\Bundle\Bundle;
@@ -54,6 +55,7 @@ public function build(ContainerBuilder $container): void
5455
$container->addCompilerPass(new FallbackToKernelDefaultLocalePass());
5556
$container->addCompilerPass(new DoctrineContainerRepositoryFactoryPass());
5657
$container->addCompilerPass(new DoctrineTargetEntitiesResolverPass(new TargetEntitiesResolver()), PassConfig::TYPE_BEFORE_OPTIMIZATION, 1);
58+
$container->addCompilerPass(new MetadataMutatorPass());
5759
$container->addCompilerPass(new RegisterFormBuilderPass());
5860
$container->addCompilerPass(new RegisterFqcnControllersPass());
5961
$container->addCompilerPass(new RegisterResourceRepositoryPass());
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Sylius package.
5+
*
6+
* (c) Sylius Sp. z o.o.
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 Sylius\Resource\Metadata;
15+
16+
#[\Attribute(\Attribute::TARGET_CLASS)]
17+
class AsOperationMutator
18+
{
19+
public function __construct(
20+
public readonly string $operationName,
21+
) {
22+
}
23+
}
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 Sylius package.
5+
*
6+
* (c) Sylius Sp. z o.o.
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 Sylius\Resource\Metadata;
15+
16+
#[\Attribute(\Attribute::TARGET_CLASS)]
17+
class AsResourceMutator
18+
{
19+
/**
20+
* @param class-string $resourceClass
21+
*/
22+
public function __construct(
23+
public readonly string $resourceClass,
24+
) {
25+
}
26+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Sylius package.
5+
*
6+
* (c) Sylius Sp. z o.o.
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 Sylius\Resource\Metadata\Mutator;
15+
16+
use Sylius\Resource\Metadata\OperationMutatorInterface;
17+
18+
/**
19+
* @internal
20+
*/
21+
final class OperationMutatorCollection implements OperationMutatorCollectionInterface
22+
{
23+
/** @var array<string, list<OperationMutatorInterface>> */
24+
private array $mutators = [];
25+
26+
/**
27+
* Adds a mutator to the container for a given operation name.
28+
*/
29+
public function add(string $operationName, OperationMutatorInterface $mutator): void
30+
{
31+
$this->mutators[$operationName][] = $mutator;
32+
}
33+
34+
public function get(string $id): array
35+
{
36+
return $this->mutators[$id] ?? [];
37+
}
38+
39+
public function has(string $id): bool
40+
{
41+
return isset($this->mutators[$id]);
42+
}
43+
}

0 commit comments

Comments
 (0)