Completed
Push — master ( 6477bb...31258d )
by
unknown
26:31 queued 16:34
created

ParamFetcher::checkNotIncompatibleParams()   B

Complexity

Conditions 5
Paths 5

Size

Total Lines 24
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 5

Importance

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

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
239
    {
240
        $request = $this->requestStack->getCurrentRequest();
241 18
        if ($request === null) {
242
            throw new \RuntimeException('There is no current request.');
243
        }
244
245
        return $request;
246
    }
247
}
248