Skip to content

Commit 8f19fa5

Browse files
committed
Alternative fix to #2643: allow autowiring of filter classes
1 parent 66ee1ba commit 8f19fa5

File tree

9 files changed

+86
-35
lines changed

9 files changed

+86
-35
lines changed

src/Bridge/Doctrine/Orm/Filter/AbstractFilter.php

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,7 @@ abstract class AbstractFilter implements FilterInterface
4242
protected $logger;
4343
protected $properties;
4444

45-
/**
46-
* @param RequestStack|null $requestStack No prefix to prevent autowiring of this deprecated property
47-
*/
48-
public function __construct(ManagerRegistry $managerRegistry, $requestStack = null, LoggerInterface $logger = null, array $properties = null)
45+
public function __construct(ManagerRegistry $managerRegistry, ?RequestStack $requestStack = null, LoggerInterface $logger = null, array $properties = null)
4946
{
5047
if (null !== $requestStack) {
5148
@trigger_error(sprintf('Passing an instance of "%s" is deprecated since 2.2. Use "filters" context key instead.', RequestStack::class), E_USER_DEPRECATED);

src/Bridge/Doctrine/Orm/Filter/OrderFilter.php

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,7 @@ class OrderFilter extends AbstractContextAwareFilter implements OrderFilterInter
4040
{
4141
use OrderFilterTrait;
4242

43-
/**
44-
* @param RequestStack|null $requestStack No prefix to prevent autowiring of this deprecated property
45-
*/
46-
public function __construct(ManagerRegistry $managerRegistry, $requestStack = null, string $orderParameterName = 'order', LoggerInterface $logger = null, array $properties = null)
43+
public function __construct(ManagerRegistry $managerRegistry, ?RequestStack $requestStack = null, string $orderParameterName = 'order', LoggerInterface $logger = null, array $properties = null)
4744
{
4845
if (null !== $properties) {
4946
$properties = array_map(function ($propertyOptions) {

src/Bridge/Doctrine/Orm/Filter/SearchFilter.php

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,7 @@ class SearchFilter extends AbstractContextAwareFilter implements SearchFilterInt
3838

3939
public const DOCTRINE_INTEGER_TYPE = DBALType::INTEGER;
4040

41-
/**
42-
* @param RequestStack|null $requestStack No prefix to prevent autowiring of this deprecated property
43-
*/
44-
public function __construct(ManagerRegistry $managerRegistry, $requestStack = null, IriConverterInterface $iriConverter, PropertyAccessorInterface $propertyAccessor = null, LoggerInterface $logger = null, array $properties = null)
41+
public function __construct(ManagerRegistry $managerRegistry, ?RequestStack $requestStack, IriConverterInterface $iriConverter, PropertyAccessorInterface $propertyAccessor = null, LoggerInterface $logger = null, array $properties = null)
4542
{
4643
parent::__construct($managerRegistry, $requestStack, $logger, $properties);
4744

src/Bridge/Symfony/Bundle/ApiPlatformBundle.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
use ApiPlatform\Core\Bridge\Symfony\Bundle\DependencyInjection\Compiler\ElasticsearchClientPass;
1919
use ApiPlatform\Core\Bridge\Symfony\Bundle\DependencyInjection\Compiler\FilterPass;
2020
use ApiPlatform\Core\Bridge\Symfony\Bundle\DependencyInjection\Compiler\MetadataAwareNameConverterPass;
21+
use Symfony\Component\DependencyInjection\Compiler\PassConfig;
2122
use Symfony\Component\DependencyInjection\ContainerBuilder;
2223
use Symfony\Component\HttpKernel\Bundle\Bundle;
2324

@@ -36,7 +37,7 @@ public function build(ContainerBuilder $container)
3637
parent::build($container);
3738

3839
$container->addCompilerPass(new DataProviderPass());
39-
$container->addCompilerPass(new AnnotationFilterPass());
40+
$container->addCompilerPass(new AnnotationFilterPass(), PassConfig::TYPE_BEFORE_OPTIMIZATION, 101);
4041
$container->addCompilerPass(new FilterPass());
4142
$container->addCompilerPass(new ElasticsearchClientPass());
4243
$container->addCompilerPass(new MetadataAwareNameConverterPass());

src/Bridge/Symfony/Bundle/DependencyInjection/ApiPlatformExtension.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,12 @@
1616
use ApiPlatform\Core\Api\FilterInterface;
1717
use ApiPlatform\Core\Bridge\Doctrine\MongoDbOdm\Extension\AggregationCollectionExtensionInterface;
1818
use ApiPlatform\Core\Bridge\Doctrine\MongoDbOdm\Extension\AggregationItemExtensionInterface;
19+
use ApiPlatform\Core\Bridge\Doctrine\MongoDbOdm\Filter\AbstractFilter as DoctrineMongoDbOdmAbstractFilter;
1920
use ApiPlatform\Core\Bridge\Doctrine\Orm\Extension\EagerLoadingExtension;
2021
use ApiPlatform\Core\Bridge\Doctrine\Orm\Extension\FilterEagerLoadingExtension;
2122
use ApiPlatform\Core\Bridge\Doctrine\Orm\Extension\QueryCollectionExtensionInterface as DoctrineQueryCollectionExtensionInterface;
2223
use ApiPlatform\Core\Bridge\Doctrine\Orm\Extension\QueryItemExtensionInterface;
24+
use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\AbstractContextAwareFilter as DoctrineOrmAbstractFilter;
2325
use ApiPlatform\Core\Bridge\Elasticsearch\DataProvider\Extension\RequestBodySearchCollectionExtensionInterface;
2426
use ApiPlatform\Core\DataPersister\DataPersisterInterface;
2527
use ApiPlatform\Core\DataProvider\CollectionDataProviderInterface;
@@ -39,6 +41,7 @@
3941
use Symfony\Component\DependencyInjection\ContainerBuilder;
4042
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
4143
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
44+
use Symfony\Component\DependencyInjection\Reference;
4245
use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
4346
use Symfony\Component\Finder\Finder;
4447
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
@@ -475,6 +478,8 @@ private function registerDoctrineConfiguration(ContainerBuilder $container, arra
475478
->addTag('api_platform.doctrine.orm.query_extension.item');
476479
$container->registerForAutoconfiguration(DoctrineQueryCollectionExtensionInterface::class)
477480
->addTag('api_platform.doctrine.orm.query_extension.collection');
481+
$container->registerForAutoconfiguration(DoctrineOrmAbstractFilter::class)
482+
->setBindings(['$requestStack' => null]);
478483

479484
$loader->load('doctrine_orm.xml');
480485

@@ -501,6 +506,8 @@ private function registerDoctrineMongoDbOdmConfiguration(ContainerBuilder $conta
501506
->addTag('api_platform.doctrine.mongodb.aggregation_extension.item');
502507
$container->registerForAutoconfiguration(AggregationCollectionExtensionInterface::class)
503508
->addTag('api_platform.doctrine.mongodb.aggregation_extension.collection');
509+
$container->registerForAutoconfiguration(DoctrineMongoDbOdmAbstractFilter::class)
510+
->setBindings(['$managerRegistry' => new Reference('doctrine_mongodb')]);
504511

505512
$loader->load('doctrine_mongodb_odm.xml');
506513
}

src/Bridge/Symfony/Bundle/DependencyInjection/Compiler/AnnotationFilterPass.php

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,14 @@
1313

1414
namespace ApiPlatform\Core\Bridge\Symfony\Bundle\DependencyInjection\Compiler;
1515

16-
use ApiPlatform\Core\Bridge\Doctrine\MongoDbOdm\Filter\FilterInterface as MongoDbOdmFilterInterface;
16+
use ApiPlatform\Core\Exception\InvalidArgumentException;
1717
use ApiPlatform\Core\Util\AnnotationFilterExtractorTrait;
1818
use ApiPlatform\Core\Util\ReflectionClassRecursiveIterator;
1919
use Doctrine\Common\Annotations\Reader;
2020
use Symfony\Component\DependencyInjection\ChildDefinition;
2121
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
2222
use Symfony\Component\DependencyInjection\ContainerBuilder;
2323
use Symfony\Component\DependencyInjection\Definition;
24-
use Symfony\Component\DependencyInjection\Reference;
2524

2625
/**
2726
* Injects filters.
@@ -34,43 +33,45 @@ final class AnnotationFilterPass implements CompilerPassInterface
3433
{
3534
use AnnotationFilterExtractorTrait;
3635

37-
public const TAG_FILTER_NAME = 'api_platform.filter';
36+
private const TAG_FILTER_NAME = 'api_platform.filter';
37+
38+
/**
39+
* @var Reader|null
40+
*/
41+
private $reader;
3842

3943
/**
4044
* {@inheritdoc}
4145
*/
4246
public function process(ContainerBuilder $container)
4347
{
4448
$resourceClassDirectories = $container->getParameter('api_platform.resource_class_directories');
45-
/**
46-
* @var Reader
47-
*/
48-
$reader = $container->get('annotation_reader');
4949

5050
foreach (ReflectionClassRecursiveIterator::getReflectionClassesFromDirectories($resourceClassDirectories) as $className => $reflectionClass) {
51-
$this->createFilterDefinitions($reflectionClass, $reader, $container);
51+
$this->createFilterDefinitions($reflectionClass, $container);
5252
}
5353
}
5454

55-
private function createFilterDefinitions(\ReflectionClass $reflectionClass, Reader $reader, ContainerBuilder $container): void
55+
private function createFilterDefinitions(\ReflectionClass $reflectionClass, ContainerBuilder $container): void
5656
{
57+
$reader = $this->reader ?? $this->reader = $container->get('annotation_reader');
58+
5759
foreach ($this->readFilterAnnotations($reflectionClass, $reader) as $id => [$arguments, $filterClass]) {
58-
if ($container->hasDefinition($id)) {
60+
if ($container->has($id)) {
5961
continue;
6062
}
6163

62-
if ($container->has($filterClass) && $container->findDefinition($filterClass)->isAbstract()) {
63-
$definition = new ChildDefinition($filterClass);
64+
if ($container->has($filterClass) && ($definition = $container->findDefinition($filterClass))->isAbstract()) {
65+
$definition = new ChildDefinition($definition->getClass());
66+
} elseif ($reflectionClass = $container->getReflectionClass($filterClass, false)) {
67+
$definition = new Definition($reflectionClass->getName());
68+
$definition->setAutoconfigured(true);
6469
} else {
65-
$definition = new Definition();
66-
$definition->setClass($filterClass);
70+
throw new InvalidArgumentException(sprintf('Class "%s" used for service "%s" cannot be found.', $filterClass, $id));
6771
}
6872

6973
$definition->addTag(self::TAG_FILTER_NAME);
7074
$definition->setAutowired(true);
71-
if (is_a($filterClass, MongoDbOdmFilterInterface::class, true)) {
72-
$definition->setArgument('$managerRegistry', new Reference('doctrine_mongodb'));
73-
}
7475

7576
foreach ($arguments as $key => $value) {
7677
$definition->setArgument("$$key", $value);

tests/Bridge/Symfony/Bundle/ApiPlatformBundleTest.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
use ApiPlatform\Core\Bridge\Symfony\Bundle\DependencyInjection\Compiler\MetadataAwareNameConverterPass;
2222
use PHPUnit\Framework\TestCase;
2323
use Prophecy\Argument;
24+
use Symfony\Component\DependencyInjection\Compiler\PassConfig;
2425
use Symfony\Component\DependencyInjection\ContainerBuilder;
2526

2627
/**
@@ -32,7 +33,7 @@ public function testBuild()
3233
{
3334
$containerProphecy = $this->prophesize(ContainerBuilder::class);
3435
$containerProphecy->addCompilerPass(Argument::type(DataProviderPass::class))->shouldBeCalled();
35-
$containerProphecy->addCompilerPass(Argument::type(AnnotationFilterPass::class))->shouldBeCalled();
36+
$containerProphecy->addCompilerPass(Argument::type(AnnotationFilterPass::class), PassConfig::TYPE_BEFORE_OPTIMIZATION, 101)->shouldBeCalled();
3637
$containerProphecy->addCompilerPass(Argument::type(FilterPass::class))->shouldBeCalled();
3738
$containerProphecy->addCompilerPass(Argument::type(ElasticsearchClientPass::class))->shouldBeCalled();
3839
$containerProphecy->addCompilerPass(Argument::type(MetadataAwareNameConverterPass::class))->shouldBeCalled();

tests/Bridge/Symfony/Bundle/DependencyInjection/ApiPlatformExtensionTest.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
use ApiPlatform\Core\Bridge\Doctrine\MongoDbOdm\Extension\FilterExtension as MongoDbOdmFilterExtension;
2323
use ApiPlatform\Core\Bridge\Doctrine\MongoDbOdm\Extension\OrderExtension as MongoDbOdmOrderExtension;
2424
use ApiPlatform\Core\Bridge\Doctrine\MongoDbOdm\Extension\PaginationExtension as MongoDbOdmPaginationExtension;
25+
use ApiPlatform\Core\Bridge\Doctrine\MongoDbOdm\Filter\AbstractFilter as DoctrineMongoDbOdmAbstractFilter;
2526
use ApiPlatform\Core\Bridge\Doctrine\MongoDbOdm\Filter\BooleanFilter as MongoDbOdmBooleanFilter;
2627
use ApiPlatform\Core\Bridge\Doctrine\MongoDbOdm\Filter\DateFilter as MongoDbOdmDateFilter;
2728
use ApiPlatform\Core\Bridge\Doctrine\MongoDbOdm\Filter\ExistsFilter as MongoDbOdmExistsFilter;
@@ -36,6 +37,7 @@
3637
use ApiPlatform\Core\Bridge\Doctrine\Orm\Extension\PaginationExtension;
3738
use ApiPlatform\Core\Bridge\Doctrine\Orm\Extension\QueryCollectionExtensionInterface;
3839
use ApiPlatform\Core\Bridge\Doctrine\Orm\Extension\QueryItemExtensionInterface;
40+
use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\AbstractContextAwareFilter as DoctrineOrmAbstractFilter;
3941
use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\BooleanFilter;
4042
use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\DateFilter;
4143
use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\ExistsFilter;
@@ -87,6 +89,7 @@
8789
use Symfony\Component\DependencyInjection\Extension\ExtensionInterface;
8890
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
8991
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
92+
use Symfony\Component\DependencyInjection\Reference;
9093
use Symfony\Component\HttpFoundation\Response;
9194
use Symfony\Component\Serializer\Exception\ExceptionInterface;
9295

@@ -480,6 +483,8 @@ public function testDisableDoctrine()
480483
$this->childDefinitionProphecy->addTag('api_platform.doctrine.orm.query_extension.item')->shouldNotBeCalled();
481484
$containerBuilderProphecy->registerForAutoconfiguration(QueryCollectionExtensionInterface::class)->shouldNotBeCalled();
482485
$this->childDefinitionProphecy->addTag('api_platform.doctrine.orm.query_extension.collection')->shouldNotBeCalled();
486+
$containerBuilderProphecy->registerForAutoconfiguration(DoctrineOrmAbstractFilter::class)->shouldNotBeCalled();
487+
$this->childDefinitionProphecy->setBindings(['$requestStack' => null])->shouldNotBeCalled();
483488
$containerBuilderProphecy->setDefinition('api_platform.doctrine.listener.http_cache.purge', Argument::type(Definition::class))->shouldNotBeCalled();
484489
$containerBuilderProphecy->setDefinition('api_platform.doctrine.orm.boolean_filter', Argument::type(Definition::class))->shouldNotBeCalled();
485490
$containerBuilderProphecy->setDefinition('api_platform.doctrine.orm.collection_data_provider', Argument::type(Definition::class))->shouldNotBeCalled();
@@ -526,6 +531,8 @@ public function testDisableDoctrineMongoDbOdm()
526531
$this->childDefinitionProphecy->addTag('api_platform.doctrine.mongodb.aggregation_extension.item')->shouldNotBeCalled();
527532
$containerBuilderProphecy->registerForAutoconfiguration(AggregationCollectionExtensionInterface::class)->shouldNotBeCalled();
528533
$this->childDefinitionProphecy->addTag('api_platform.doctrine.mongodb.aggregation_extension.collection')->shouldNotBeCalled();
534+
$containerBuilderProphecy->registerForAutoconfiguration(DoctrineMongoDbOdmAbstractFilter::class)->shouldNotBeCalled();
535+
$this->childDefinitionProphecy->setBindings(Argument::allOf(Argument::withEntry('$managerRegistry', Argument::type(Reference::class))))->shouldNotBeCalled();
529536
$containerBuilderProphecy->setDefinition('api_platform.doctrine_mongodb.odm.aggregation_extension.filter', Argument::type(Definition::class))->shouldNotBeCalled();
530537
$containerBuilderProphecy->setDefinition('api_platform.doctrine_mongodb.odm.aggregation_extension.order', Argument::type(Definition::class))->shouldNotBeCalled();
531538
$containerBuilderProphecy->setDefinition('api_platform.doctrine_mongodb.odm.aggregation_extension.pagination', Argument::type(Definition::class))->shouldNotBeCalled();
@@ -907,6 +914,10 @@ private function getBaseContainerBuilderProphecy()
907914
->willReturn($this->childDefinitionProphecy)->shouldBeCalledTimes(1);
908915
$this->childDefinitionProphecy->addTag('api_platform.doctrine.orm.query_extension.collection')->shouldBeCalledTimes(1);
909916

917+
$containerBuilderProphecy->registerForAutoconfiguration(DoctrineOrmAbstractFilter::class)
918+
->willReturn($this->childDefinitionProphecy)->shouldBeCalledTimes(1);
919+
$this->childDefinitionProphecy->setBindings(['$requestStack' => null])->shouldBeCalledTimes(1);
920+
910921
$containerBuilderProphecy->registerForAutoconfiguration(AggregationItemExtensionInterface::class)
911922
->willReturn($this->childDefinitionProphecy)->shouldBeCalledTimes(1);
912923
$this->childDefinitionProphecy->addTag('api_platform.doctrine.mongodb.aggregation_extension.item')->shouldBeCalledTimes(1);
@@ -915,6 +926,10 @@ private function getBaseContainerBuilderProphecy()
915926
->willReturn($this->childDefinitionProphecy)->shouldBeCalledTimes(1);
916927
$this->childDefinitionProphecy->addTag('api_platform.doctrine.mongodb.aggregation_extension.collection')->shouldBeCalledTimes(1);
917928

929+
$containerBuilderProphecy->registerForAutoconfiguration(DoctrineMongoDbOdmAbstractFilter::class)
930+
->willReturn($this->childDefinitionProphecy)->shouldBeCalledTimes(1);
931+
$this->childDefinitionProphecy->setBindings(Argument::allOf(Argument::withEntry('$managerRegistry', Argument::type(Reference::class))))->shouldBeCalledTimes(1);
932+
918933
$containerBuilderProphecy->registerForAutoconfiguration(DataTransformerInterface::class)
919934
->willReturn($this->childDefinitionProphecy)->shouldBeCalledTimes(1);
920935
$this->childDefinitionProphecy->addTag('api_platform.data_transformer')->shouldBeCalledTimes(1);

0 commit comments

Comments
 (0)