Completed
Push — master ( cb6c2f...52a6a4 )
by
unknown
05:39 queued 11s
created

Request/ParamFetcher.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
/*
4
 * This file is part of the FOSRestBundle package.
5
 *
6
 * (c) FriendsOfSymfony <http://friendsofsymfony.github.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
namespace FOS\RestBundle\Request;
13
14
use FOS\RestBundle\Controller\Annotations\ParamInterface;
15
use FOS\RestBundle\Exception\InvalidParameterException;
16
use FOS\RestBundle\Util\ResolverTrait;
17
use FOS\RestBundle\Validator\Constraints\ResolvableConstraintInterface;
18
use Symfony\Component\DependencyInjection\ContainerInterface;
19
use Symfony\Component\HttpFoundation\Request;
20
use Symfony\Component\HttpFoundation\RequestStack;
21
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
22
use Symfony\Component\Validator\Constraint;
23
use Symfony\Component\Validator\ConstraintViolationList;
24
use Symfony\Component\Validator\Validator\ValidatorInterface;
25
use Symfony\Component\Validator\Exception\ValidatorException;
26
use Symfony\Component\Validator\ConstraintViolation;
27
28
/**
29
 * Helper to validate parameters of the active request.
30
 *
31
 * @author Alexander <[email protected]>
32
 * @author Lukas Kahwe Smith <[email protected]>
33
 * @author Jordi Boggiano <[email protected]>
34
 * @author Boris Guéry <[email protected]>
35
 */
36
class ParamFetcher implements ParamFetcherInterface
37
{
38
    use ResolverTrait;
39
40
    private $container;
41
    private $parameterBag;
42
    private $requestStack;
43
    private $validator;
44
45
    /**
46
     * Initializes fetcher.
47
     *
48
     * @param ContainerInterface   $container
49
     * @param ParamReaderInterface $paramReader
50
     * @param RequestStack         $requestStack
51
     * @param ValidatorInterface   $validator
52
     */
53 27
    public function __construct(ContainerInterface $container, ParamReaderInterface $paramReader, RequestStack $requestStack, ValidatorInterface $validator = null)
54
    {
55 27
        if (null === $validator) {
56 27
            @trigger_error(sprintf('Using no validator is deprecated since FOSRestBundle 2.6. The `$validator` constructor argument of the `%s` will become mandatory in 3.0.', __CLASS__), E_USER_DEPRECATED);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
57 27
        }
58
59 27
        $this->container = $container;
60 27
        $this->requestStack = $requestStack;
61
        $this->validator = $validator;
62
63
        $this->parameterBag = new ParameterBag($paramReader);
64
    }
65 15
66
    /**
67 15
     * {@inheritdoc}
68 15
     */
69
    public function setController($controller)
70
    {
71
        $this->parameterBag->setController($this->getRequest(), $controller);
72
    }
73
74
    /**
75
     * Add additional params to the ParamFetcher during runtime.
76
     *
77 1
     * Note that adding a param that has the same name as an existing param will override that param.
78
     *
79 1
     * @param ParamInterface $param
80 1
     */
81
    public function addParam(ParamInterface $param)
82
    {
83
        $this->parameterBag->addParam($this->getRequest(), $param);
84
    }
85 15
86
    /**
87 15
     * @return ParamInterface[]
88
     */
89
    public function getParams()
90
    {
91
        return $this->parameterBag->getParams($this->getRequest());
92
    }
93 12
94
    /**
95 12
     * {@inheritdoc}
96
     */
97 12
    public function get($name, $strict = null)
98 1
    {
99
        $params = $this->getParams();
100
101
        if (!array_key_exists($name, $params)) {
102 11
            throw new \InvalidArgumentException(sprintf("No @ParamInterface configuration for parameter '%s'.", $name));
103 11
        }
104 11
105 11
        /** @var ParamInterface $param */
106
        $param = $params[$name];
107 11
        $default = $param->getDefault();
108
        $default = $this->resolveValue($this->container, $default);
109 11
        $strict = (null !== $strict ? $strict : $param->isStrict());
110
111
        $paramValue = $param->getValue($this->getRequest(), $default);
112
113
        return $this->cleanParamWithRequirements($param, $paramValue, $strict, $default);
114
    }
115
116
    /**
117
     * @param ParamInterface $param
118
     * @param mixed          $paramValue
119
     * @param bool           $strict
120
     * @param mixed          $default
121
     *
122
     * @throws BadRequestHttpException
123
     * @throws \RuntimeException
124
     *
125 16
     * @return mixed
126
     *
127 16
     * @internal
128 16
     */
129 4
    protected function cleanParamWithRequirements(ParamInterface $param, $paramValue, $strict, $default)
130
    {
131
        $this->checkNotIncompatibleParams($param);
132 14
        if (null !== $default && $default === $paramValue) {
133 14
            return $paramValue;
134 14
        }
135 1
136
        $constraints = $param->getConstraints();
137 13
        $this->resolveConstraints($constraints);
138 1
        if (empty($constraints)) {
139
            return $paramValue;
140 1
        }
141
        if (null === $this->validator) {
142
            throw new \RuntimeException(
143
                'The ParamFetcher requirements feature requires the symfony/validator component.'
144 12
            );
145 12
        }
146
147
        try {
148
            $errors = $this->validator->validate($paramValue, $constraints);
149
        } catch (ValidatorException $e) {
150
            $violation = new ConstraintViolation(
151
                $e->getMessage(),
152
                $e->getMessage(),
153
                array(),
154
                $paramValue,
155
                '',
156
                null,
157
                null,
158
                $e->getCode()
159 12
            );
160 6
            $errors = new ConstraintViolationList(array($violation));
161 2
        }
162
163
        if (0 < count($errors)) {
164 4
            if ($strict) {
165
                throw InvalidParameterException::withViolations($param, $errors);
166
            }
167 8
168
            return null === $default ? '' : $default;
169
        }
170
171
        return $paramValue;
172
    }
173 9
174
    /**
175 9
     * {@inheritdoc}
176
     */
177 5
    public function all($strict = null)
178 5
    {
179 5
        $configuredParams = $this->getParams();
180 5
181
        $params = [];
182 5
        foreach ($configuredParams as $name => $param) {
183
            $params[$name] = $this->get($name, $strict);
184
        }
185
186
        return $params;
187
    }
188
189
    /**
190
     * Check if current param is not in conflict with other parameters
191
     * according to the "incompatibles" field.
192
     *
193
     * @param ParamInterface $param the configuration for the param fetcher
194
     *
195
     * @throws InvalidArgumentException
196 11
     * @throws BadRequestHttpException
197
     *
198 11
     * @internal
199 11
     */
200 2
    protected function checkNotIncompatibleParams(ParamInterface $param)
201 1
    {
202
        if (null === $param->getValue($this->getRequest(), null)) {
203 1
            return;
204
        }
205 1
206 1
        $params = $this->getParams();
207 1
        foreach ($param->getIncompatibilities() as $incompatibleParamName) {
208 1
            if (!array_key_exists($incompatibleParamName, $params)) {
209 1
                throw new \InvalidArgumentException(sprintf("No @ParamInterface configuration for parameter '%s'.", $incompatibleParamName));
210 1
            }
211
            $incompatibleParam = $params[$incompatibleParamName];
212 1
213
            if (null !== $incompatibleParam->getValue($this->getRequest(), null)) {
214 10
                $exceptionMessage = sprintf(
215 9
                    "'%s' param is incompatible with %s param.",
216
                    $param->getName(),
217
                    $incompatibleParam->getName()
218
                );
219
220 14
                throw new BadRequestHttpException($exceptionMessage);
221
            }
222 14
        }
223 13
    }
224 4
225 4
    /**
226 14
     * @param Constraint[] $constraints
227 14
     */
228
    private function resolveConstraints(array $constraints)
229
    {
230
        foreach ($constraints as $constraint) {
231
            if ($constraint instanceof ResolvableConstraintInterface) {
232
                $constraint->resolve($this->container);
233
            }
234 18
        }
235
    }
236 18
237 18
    /**
238
     * @throws \RuntimeException
239
     *
240
     * @return Request
241 18
     */
242 View Code Duplication
    private function getRequest()
243
    {
244
        $request = $this->requestStack->getCurrentRequest();
245
        if (null === $request) {
246
            throw new \RuntimeException('There is no current request.');
247
        }
248
249
        return $request;
250
    }
251
}
252