• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

api-platform / core / 15629538569

13 Jun 2025 07:58AM UTC coverage: 21.874% (-0.002%) from 21.876%
15629538569

Pull #7207

github

web-flow
Merge 3fb5fafc9 into cff61eab8
Pull Request #7207: feat(metadata) customize resource & operations

16 of 92 new or added lines in 9 files covered. (17.39%)

37 existing lines in 2 files now uncovered.

11410 of 52163 relevant lines covered (21.87%)

20.98 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

40.63
/src/Metadata/Extractor/AbstractPropertyExtractor.php
1
<?php
2

3
/*
4
 * This file is part of the API Platform project.
5
 *
6
 * (c) Kévin Dunglas <dunglas@gmail.com>
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\Extractor;
15

16
use Psr\Container\ContainerInterface;
17
use Symfony\Component\DependencyInjection\ContainerInterface as SymfonyContainerInterface;
18

19
/**
20
 * Base file extractor.
21
 *
22
 * @author Vincent Chalamon <vincentchalamon@gmail.com>
23
 */
24
abstract class AbstractPropertyExtractor implements PropertyExtractorInterface
25
{
26
    protected ?array $properties = null;
27
    private array $collectedParameters = [];
28

29
    /**
30
     * @param string[] $paths
31
     */
32
    public function __construct(protected array $paths, private readonly ?ContainerInterface $container = null)
33
    {
34
    }
562✔
35

36
    /**
37
     * {@inheritdoc}
38
     */
39
    public function getProperties(): array
40
    {
41
        if (null !== $this->properties) {
164✔
42
            return $this->properties;
156✔
43
        }
44

45
        $this->properties = [];
164✔
46
        foreach ($this->paths as $path) {
164✔
47
            $this->extractPath($path);
164✔
48
        }
49

50
        return $this->properties;
164✔
51
    }
52

53
    /**
54
     * Extracts metadata from a given path.
55
     */
56
    abstract protected function extractPath(string $path): void;
57

58
    /**
59
     * Recursively replaces placeholders with the service container parameters.
60
     *
61
     * @see https://github.com/symfony/symfony/blob/6fec32c/src/Symfony/Bundle/FrameworkBundle/Routing/Router.php
62
     *
63
     * @copyright (c) Fabien Potencier <fabien@symfony.com>
64
     *
65
     * @param mixed $value The source which might contain "%placeholders%"
66
     *
67
     * @throws \RuntimeException When a container value is not a string or a numeric value
68
     *
69
     * @return mixed The source with the placeholders replaced by the container
70
     *               parameters. Arrays are resolved recursively.
71
     */
72
    protected function resolve(mixed $value): mixed
73
    {
74
        if (null === $this->container) {
164✔
UNCOV
75
            return $value;
×
76
        }
77

78
        if (\is_array($value)) {
164✔
UNCOV
79
            foreach ($value as $key => $val) {
×
UNCOV
80
                $value[$key] = $this->resolve($val);
×
81
            }
82

UNCOV
83
            return $value;
×
84
        }
85

86
        if (!\is_string($value)) {
164✔
UNCOV
87
            return $value;
×
88
        }
89

90
        $escapedValue = preg_replace_callback('/%%|%([^%\s]++)%/', function ($match) use ($value) {
164✔
UNCOV
91
            $parameter = $match[1] ?? null;
×
92

93
            // skip %%
UNCOV
94
            if (!isset($parameter)) {
×
UNCOV
95
                return '%%';
×
96
            }
97

UNCOV
98
            if (preg_match('/^env\(\w+\)$/', $parameter)) {
×
UNCOV
99
                throw new \RuntimeException(\sprintf('Using "%%%s%%" is not allowed in routing configuration.', $parameter));
×
100
            }
101

UNCOV
102
            if (\array_key_exists($parameter, $this->collectedParameters)) {
×
UNCOV
103
                return $this->collectedParameters[$parameter];
×
104
            }
105

UNCOV
106
            if ($this->container instanceof SymfonyContainerInterface) {
×
UNCOV
107
                $resolved = $this->container->getParameter($parameter);
×
108
            } else {
UNCOV
109
                $resolved = $this->container->get($parameter);
×
110
            }
111

UNCOV
112
            if (\is_string($resolved) || is_numeric($resolved)) {
×
UNCOV
113
                $this->collectedParameters[$parameter] = $resolved;
×
114

UNCOV
115
                return (string) $resolved;
×
116
            }
117

UNCOV
118
            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)));
×
119
        }, $value);
164✔
120

121
        return str_replace('%%', '%', $escapedValue);
164✔
122
    }
123
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc