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

api-platform / core / 16050929464

03 Jul 2025 12:51PM UTC coverage: 22.065% (+0.2%) from 21.821%
16050929464

push

github

soyuka
chore: todo improvement

11516 of 52192 relevant lines covered (22.06%)

22.08 hits per line

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

96.83
/src/State/Provider/ParameterProvider.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\State\Provider;
15

16
use ApiPlatform\Metadata\HttpOperation;
17
use ApiPlatform\Metadata\Operation;
18
use ApiPlatform\Metadata\Parameter;
19
use ApiPlatform\State\Exception\ParameterNotSupportedException;
20
use ApiPlatform\State\Exception\ProviderNotFoundException;
21
use ApiPlatform\State\ParameterNotFound;
22
use ApiPlatform\State\ParameterProvider\ReadLinkParameterProvider;
23
use ApiPlatform\State\ProviderInterface;
24
use ApiPlatform\State\Util\ParameterParserTrait;
25
use ApiPlatform\State\Util\RequestParser;
26
use Psr\Container\ContainerInterface;
27

28
/**
29
 * Loops over parameters to:
30
 *   - compute its values set as extra properties from the Parameter object (`_api_values`)
31
 *   - call the Parameter::provider if any and updates the Operation
32
 *
33
 * @experimental
34
 */
35
final class ParameterProvider implements ProviderInterface
36
{
37
    use ParameterParserTrait;
38

39
    public function __construct(private readonly ?ProviderInterface $decorated = null, private readonly ?ContainerInterface $locator = null)
40
    {
41
    }
510✔
42

43
    public function provide(Operation $operation, array $uriVariables = [], array $context = []): object|array|null
44
    {
45
        $request = $context['request'] ?? null;
495✔
46
        if ($request && null === $request->attributes->get('_api_query_parameters')) {
495✔
47
            $queryString = RequestParser::getQueryString($request);
469✔
48
            $request->attributes->set('_api_query_parameters', $queryString ? RequestParser::parseRequestParams($queryString) : []);
469✔
49
        }
50

51
        if ($request && null === $request->attributes->get('_api_header_parameters')) {
495✔
52
            $request->attributes->set('_api_header_parameters', $request->headers->all());
469✔
53
        }
54

55
        $parameters = $operation->getParameters();
495✔
56

57
        if ($operation instanceof HttpOperation && true === $operation->getStrictQueryParameterValidation()) {
495✔
58
            $keys = [];
4✔
59
            foreach ($parameters as $parameter) {
4✔
60
                $keys[] = $parameter->getKey();
4✔
61
            }
62

63
            foreach (array_keys($request->attributes->get('_api_query_parameters')) as $key) {
4✔
64
                if (!\in_array($key, $keys, true)) {
4✔
65
                    throw new ParameterNotSupportedException($key);
2✔
66
                }
67
            }
68
        }
69

70
        $context = ['operation' => $operation] + $context;
495✔
71

72
        foreach ($parameters ?? [] as $parameter) {
495✔
73
            $values = $this->getParameterValues($parameter, $request, $context);
286✔
74
            $value = $this->extractParameterValues($parameter, $values);
286✔
75
            // we force API Platform's value extraction, use _api_query_parameters or _api_header_parameters if you need to set a value
76
            if (isset($parameter->getExtraProperties()['_api_values'])) {
286✔
77
                unset($parameter->getExtraProperties()['_api_values']);
20✔
78
            }
79

80
            if (($default = $parameter->getSchema()['default'] ?? false) && ($value instanceof ParameterNotFound || !$value)) {
286✔
81
                $value = $default;
10✔
82
            }
83

84
            $parameter->setValue($value);
286✔
85
            $context['operation'] = $operation = $this->callParameterProvider($operation, $parameter, $values, $context);
286✔
86
        }
87

88
        if ($parameters) {
495✔
89
            $operation = $operation->withParameters($parameters);
282✔
90
        }
91

92
        if ($operation instanceof HttpOperation) {
495✔
93
            $operation = $this->handlePathParameters($operation, $uriVariables, $context);
469✔
94
        }
95

96
        $request?->attributes->set('_api_operation', $operation);
495✔
97
        $context['operation'] = $operation;
495✔
98

99
        return $this->decorated?->provide($operation, $uriVariables, $context);
495✔
100
    }
101

102
    /**
103
     * TODO: uriVariables could be a Parameters instance, it'd make things easier.
104
     *
105
     * @param array<string, mixed> $uriVariables
106
     * @param array<string, mixed> $context
107
     */
108
    private function handlePathParameters(HttpOperation $operation, array $uriVariables, array $context): HttpOperation
109
    {
110
        foreach ($operation->getUriVariables() ?? [] as $key => $uriVariable) {
469✔
111
            $uriVariable = $uriVariable->withKey($key);
176✔
112
            if ($uriVariable->getSecurity() && !$uriVariable->getProvider()) {
176✔
113
                $uriVariable = $uriVariable->withProvider(ReadLinkParameterProvider::class);
4✔
114
            }
115

116
            $values = $uriVariables;
176✔
117

118
            if (!\array_key_exists($key, $uriVariables)) {
176✔
119
                continue;
68✔
120
            }
121

122
            $value = $uriVariables[$key];
116✔
123
            // we force API Platform's value extraction, use _api_query_parameters or _api_header_parameters if you need to set a value
124
            if (isset($uriVariable->getExtraProperties()['_api_values'])) {
116✔
125
                unset($uriVariable->getExtraProperties()['_api_values']);
2✔
126
            }
127

128
            if (($default = $uriVariable->getSchema()['default'] ?? false) && ($value instanceof ParameterNotFound || !$value)) {
116✔
129
                $value = $default;
×
130
            }
131

132
            $uriVariable->setValue($value);
116✔
133
            if (($op = $this->callParameterProvider($operation, $uriVariable, $values, $context)) instanceof HttpOperation) {
116✔
134
                $context['operation'] = $operation = $op;
116✔
135
            }
136
        }
137

138
        return $operation;
469✔
139
    }
140

141
    /**
142
     * @param array<string,mixed> $context
143
     */
144
    private function callParameterProvider(Operation $operation, Parameter $parameter, mixed $values, array $context): Operation
145
    {
146
        if ($parameter->getValue() instanceof ParameterNotFound) {
392✔
147
            return $operation;
272✔
148
        }
149

150
        if (null === ($provider = $parameter->getProvider())) {
388✔
151
            return $operation;
366✔
152
        }
153

154
        if (\is_callable($provider)) {
32✔
155
            if (($op = $provider($parameter, $values, $context)) instanceof Operation) {
8✔
156
                $operation = $op;
6✔
157
            }
158

159
            return $operation;
6✔
160
        }
161

162
        if (\is_string($provider)) {
26✔
163
            if (!$this->locator->has($provider)) {
26✔
164
                throw new ProviderNotFoundException(\sprintf('Provider "%s" not found on operation "%s"', $provider, $operation->getName()));
×
165
            }
166

167
            $provider = $this->locator->get($provider);
26✔
168
        }
169

170
        if (($op = $provider->provide($parameter, $values, $context)) instanceof Operation) {
26✔
171
            $operation = $op;
24✔
172
        }
173

174
        return $operation;
24✔
175
    }
176
}
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