Issues (332)

Compiler/AnnotationFilterPass.php (2 issues)

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\Core\Bridge\Symfony\Bundle\DependencyInjection\Compiler;
15
16
use ApiPlatform\Core\Annotation\ApiFilter;
17
use ApiPlatform\Core\Util\AnnotationFilterExtractorTrait;
18
use ApiPlatform\Core\Util\ReflectionClassRecursiveIterator;
19
use Doctrine\Common\Annotations\Reader;
20
use Symfony\Component\DependencyInjection\ChildDefinition;
21
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
22
use Symfony\Component\DependencyInjection\ContainerBuilder;
23
use Symfony\Component\DependencyInjection\Definition;
24
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
25
26
/**
27
 * Registers filter services from {@see ApiFilter} annotations.
28
 *
29
 * @internal
30
 *
31
 * @author Antoine Bluchet <[email protected]>
32
 */
33
final class AnnotationFilterPass implements CompilerPassInterface
34
{
35
    use AnnotationFilterExtractorTrait;
36
37
    private const TAG_FILTER_NAME = 'api_platform.filter';
38
39
    /**
40
     * @var Reader|null
41
     */
42
    private $reader;
43
44
    /**
45
     * {@inheritdoc}
46
     */
47
    public function process(ContainerBuilder $container): void
48
    {
49
        $resourceClassDirectories = $container->getParameter('api_platform.resource_class_directories');
50
51
        foreach (ReflectionClassRecursiveIterator::getReflectionClassesFromDirectories($resourceClassDirectories) as $className => $reflectionClass) {
52
            $this->createFilterDefinitions($reflectionClass, $container);
53
        }
54
    }
55
56
    /**
57
     * @throws InvalidArgumentException
58
     */
59
    private function createFilterDefinitions(\ReflectionClass $resourceReflectionClass, ContainerBuilder $container): void
60
    {
61
        $this->reader ?? $this->reader = $container->get('annotation_reader');
62
63
        foreach ($this->readFilterAnnotations($resourceReflectionClass, $this->reader) as $id => [$arguments, $filterClass]) {
0 ignored issues
show
It seems like $this->reader can also be of type null; however, parameter $reader of ApiPlatform\Core\Bridge\...readFilterAnnotations() does only seem to accept Doctrine\Common\Annotations\Reader, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

63
        foreach ($this->readFilterAnnotations($resourceReflectionClass, /** @scrutinizer ignore-type */ $this->reader) as $id => [$arguments, $filterClass]) {
Loading history...
64
            if ($container->has($id)) {
65
                continue;
66
            }
67
68
            if (null === $filterReflectionClass = $container->getReflectionClass($filterClass, false)) {
69
                throw new InvalidArgumentException(sprintf('Class "%s" used for service "%s" cannot be found.', $filterClass, $id));
70
            }
71
72
            if ($container->has($filterClass) && ($parentDefinition = $container->findDefinition($filterClass))->isAbstract()) {
73
                $definition = new ChildDefinition($parentDefinition->getClass());
0 ignored issues
show
It seems like $parentDefinition->getClass() can also be of type null; however, parameter $parent of Symfony\Component\Depend...finition::__construct() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

73
                $definition = new ChildDefinition(/** @scrutinizer ignore-type */ $parentDefinition->getClass());
Loading history...
74
            } else {
75
                $definition = new Definition($filterReflectionClass->getName());
76
                $definition->setAutoconfigured(true);
77
            }
78
79
            $definition->addTag(self::TAG_FILTER_NAME);
80
            $definition->setAutowired(true);
81
82
            $parameterNames = [];
83
            if (null !== $constructorReflectionMethod = $filterReflectionClass->getConstructor()) {
84
                foreach ($constructorReflectionMethod->getParameters() as $reflectionParameter) {
85
                    $parameterNames[$reflectionParameter->name] = true;
86
                }
87
            }
88
89
            foreach ($arguments as $key => $value) {
90
                if (!isset($parameterNames[$key])) {
91
                    throw new InvalidArgumentException(sprintf('Class "%s" does not have argument "$%s".', $filterClass, $key));
92
                }
93
94
                $definition->setArgument("$$key", $value);
95
            }
96
97
            $container->setDefinition($id, $definition);
98
        }
99
    }
100
}
101