Completed
Push — master ( ac8ec4...1a57ac )
by Kévin
04:37 queued 11s
created

src/Metadata/Extractor/AbstractExtractor.php (1 issue)

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\Metadata\Extractor;
15
16
use Psr\Container\ContainerInterface;
17
use Symfony\Component\DependencyInjection\ContainerInterface as SymfonyContainerInterface;
18
19
/**
20
 * Base file extractor.
21
 *
22
 * @author Kévin Dunglas <[email protected]>
23
 */
24
abstract class AbstractExtractor implements ExtractorInterface
25
{
26
    protected $paths;
27
    protected $resources;
28
    private $container;
29
    private $collectedParameters = [];
30
31
    /**
32
     * @param string[] $paths
33
     */
34
    public function __construct(array $paths, ContainerInterface $container = null)
35
    {
36
        $this->paths = $paths;
37
        $this->container = $container;
38
    }
39
40
    /**
41
     * {@inheritdoc}
42
     */
43
    public function getResources(): array
44
    {
45
        if (null !== $this->resources) {
46
            return $this->resources;
47
        }
48
49
        $this->resources = [];
50
        foreach ($this->paths as $path) {
51
            $this->extractPath($path);
52
        }
53
54
        return $this->resources;
55
    }
56
57
    /**
58
     * Extracts metadata from a given path.
59
     */
60
    abstract protected function extractPath(string $path);
61
62
    /**
63
     * Recursively replaces placeholders with the service container parameters.
64
     *
65
     * @see https://github.com/symfony/symfony/blob/6fec32c/src/Symfony/Bundle/FrameworkBundle/Routing/Router.php
66
     *
67
     * @copyright (c) Fabien Potencier <[email protected]>
68
     *
69
     * @param mixed $value The source which might contain "%placeholders%"
70
     *
71
     * @throws \RuntimeException When a container value is not a string or a numeric value
72
     *
73
     * @return mixed The source with the placeholders replaced by the container
74
     *               parameters. Arrays are resolved recursively.
75
     */
76
    protected function resolve($value)
77
    {
78
        if (null === $this->container) {
79
            return $value;
80
        }
81
82
        if (\is_array($value)) {
83
            foreach ($value as $key => $val) {
84
                $value[$key] = $this->resolve($val);
85
            }
86
87
            return $value;
88
        }
89
90
        if (!\is_string($value)) {
91
            return $value;
92
        }
93
94
        $escapedValue = preg_replace_callback('/%%|%([^%\s]++)%/', function ($match) use ($value) {
95
            $parameter = $match[1];
96
97
            // skip %%
98
            if (!isset($parameter)) {
99
                return '%%';
100
            }
101
102
            if (preg_match('/^env\(\w+\)$/', $parameter)) {
103
                throw new \RuntimeException(sprintf('Using "%%%s%%" is not allowed in routing configuration.', $parameter));
104
            }
105
106
            if (\array_key_exists($parameter, $this->collectedParameters)) {
107
                return $this->collectedParameters[$parameter];
108
            }
109
110
            if ($this->container instanceof SymfonyContainerInterface) {
111
                $resolved = $this->container->getParameter($parameter);
112
            } else {
113
                $resolved = $this->container->get($parameter);
0 ignored issues
show
The method get() does not exist on null. ( Ignorable by Annotation )

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

113
                /** @scrutinizer ignore-call */ 
114
                $resolved = $this->container->get($parameter);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
114
            }
115
116
            if (\is_string($resolved) || is_numeric($resolved)) {
117
                $this->collectedParameters[$parameter] = $resolved;
118
119
                return (string) $resolved;
120
            }
121
122
            throw new\ RuntimeException(sprintf('The container parameter "%s", used in the resource configuration value "%s", must be a string or numeric, but it is of type %s.', $parameter, $value, \gettype($resolved)));
123
        }, $value);
124
125
        return str_replace('%%', '%', $escapedValue);
126
    }
127
}
128