Completed
Push — master ( 9d332c...933a2a )
by Guilh
06:03 queued 03:34
created

ParamFetcher::getParams()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 2
Bugs 1 Features 0
Metric Value
c 2
b 1
f 0
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
cc 1
eloc 2
nc 1
nop 0
crap 1
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\Util\ResolverTrait;
16
use FOS\RestBundle\Validator\Constraints\ResolvableConstraintInterface;
17
use FOS\RestBundle\Validator\ViolationFormatterInterface;
18
use FOS\RestBundle\Controller\Annotations\Param;
19
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
20
use Symfony\Component\DependencyInjection\ContainerAwareTrait;
21
use Symfony\Component\HttpFoundation\Request;
22
use Symfony\Component\HttpFoundation\RequestStack;
23
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
24
use Symfony\Component\Validator\Constraint;
25
use Symfony\Component\Validator\ConstraintViolationList;
26
use Symfony\Component\Validator\Validator\ValidatorInterface;
27
use Symfony\Component\Validator\Exception\ValidatorException;
28
use Symfony\Component\Validator\ConstraintViolation;
29
30
/**
31
 * Helper to validate parameters of the active request.
32
 *
33
 * @author Alexander <[email protected]>
34
 * @author Lukas Kahwe Smith <[email protected]>
35
 * @author Jordi Boggiano <[email protected]>
36
 * @author Boris Guéry <[email protected]>
37
 */
38
class ParamFetcher implements ParamFetcherInterface, ContainerAwareInterface
39
{
40
    use ResolverTrait, ContainerAwareTrait;
41
42
    private $parameterBag;
43
    private $requestStack;
44
    private $validator;
45
    private $violationFormatter;
46
    /**
47
     * @var callable
48
     */
49
    private $controller;
50
51
    /**
52
     * Initializes fetcher.
53
     *
54
     * @param ParamReaderInterface        $paramReader
55
     * @param RequestStack                $requestStack
56
     * @param ValidatorInterface          $validator
57
     * @param ViolationFormatterInterface $violationFormatter
58
     */
59 22
    public function __construct(ParamReaderInterface $paramReader, RequestStack $requestStack, ViolationFormatterInterface $violationFormatter, ValidatorInterface $validator = null)
60
    {
61 22
        $this->requestStack = $requestStack;
62 22
        $this->violationFormatter = $violationFormatter;
63 22
        $this->validator = $validator;
64
65 22
        $this->parameterBag = new ParameterBag($paramReader);
66 22
    }
67
68
    /**
69
     * {@inheritdoc}
70
     */
71 11
    public function setController($controller)
72
    {
73 11
        $this->parameterBag->setController($this->getRequest(), $controller);
74 11
    }
75
76
    /**
77
     * Add additional params to the ParamFetcher during runtime.
78
     *
79
     * Note that adding a param that has the same name as an existing param will override that param.
80
     *
81
     * @param ParamInterface $param
82
     */
83 1
    public function addParam(ParamInterface $param)
84
    {
85 1
        $this->parameterBag->addParam($this->getRequest(), $param);
86 1
    }
87
88
    /**
89
     * @return ParamInterface[]
90
     */
91 11
    public function getParams()
92
    {
93 11
        return $this->parameterBag->getParams($this->getRequest());
94
    }
95
96
    /**
97
     * {@inheritdoc}
98
     */
99 8
    public function get($name, $strict = null)
100
    {
101 8
        $params = $this->getParams();
102
103 8
        if (!array_key_exists($name, $params)) {
104 1
            throw new \InvalidArgumentException(sprintf("No @ParamInterface configuration for parameter '%s'.", $name));
105
        }
106
107
        /** @var ParamInterface $param */
108 7
        $param = $params[$name];
109 7
        $default = $param->getDefault();
110 7
        $strict = (null !== $strict ? $strict : $param->isStrict());
111
112 7
        $paramValue = $param->getValue($this->getRequest(), $default);
113
114 7
        return $this->cleanParamWithRequirements($param, $paramValue, $strict);
115
    }
116
117
    /**
118
     * @param ParamInterface $param
119
     * @param mixed          $paramValue
120
     * @param bool           $strict
121
     *
122
     * @throws BadRequestHttpException
123
     * @throws \RuntimeException
124
     *
125
     * @return mixed
126
     *
127
     * @internal
128
     */
129 11
    protected function cleanParamWithRequirements(ParamInterface $param, $paramValue, $strict)
130
    {
131 11
        if (empty($this->container)) {
132
            throw new \InvalidArgumentException(
133
                'The ParamFetcher has been not initialized correctly. '.
134
                'The container for parameter resolution is missing.'
135
            );
136
        }
137
138 11
        $default = $param->getDefault();
139 11
        $default = $this->resolveValue($this->container, $default);
140
141 11
        $this->checkNotIncompatibleParams($param);
142 11
        if ($default !== null && $default === $paramValue) {
143 4
            return $paramValue;
144
        }
145
146 10
        $constraints = $param->getConstraints();
147 10
        $this->resolveConstraints($constraints);
148 10
        if (empty($constraints)) {
149 1
            return $paramValue;
150
        }
151 9
        if (null === $this->validator) {
152 1
            throw new \RuntimeException(
153
                'The ParamFetcher requirements feature requires the symfony/validator component.'
154 1
            );
155
        }
156
157
        try {
158 8
            $errors = $this->validator->validate($paramValue, $constraints);
159 8
        } catch (ValidatorException $e) {
160 3
            $violation = new ConstraintViolation(
161 3
                $e->getMessage(),
162 3
                $e->getMessage(),
163 3
                array(),
164 3
                $paramValue,
165 3
                '',
166 3
                null,
167 3
                null,
168 3
                $e->getCode()
169 3
            );
170 3
            $errors = new ConstraintViolationList(array($violation));
171
        }
172
173 8
        if (0 < count($errors)) {
174 7
            if ($strict) {
175 1
                throw new BadRequestHttpException(
176 1
                    $this->violationFormatter->formatList($param, $errors)
177 1
                );
178
            }
179
180 6
            return null === $default ? '' : $default;
181
        }
182
183 6
        return $paramValue;
184
    }
185
186
    /**
187
     * {@inheritdoc}
188
     */
189 10
    public function all($strict = null)
190
    {
191 10
        $configuredParams = $this->getParams();
192
193 6
        $params = [];
194 6
        foreach ($configuredParams as $name => $param) {
195 6
            $params[$name] = $this->get($name, $strict);
196 6
        }
197
198 6
        return $params;
199
    }
200
201
    /**
202
     * Check if current param is not in conflict with other parameters
203
     * according to the "incompatibles" field.
204
     *
205
     * @param ParamInterface $param the configuration for the param fetcher
206
     *
207
     * @throws InvalidArgumentException
208
     * @throws BadRequestHttpException
209
     *
210
     * @internal
211
     */
212 8
    protected function checkNotIncompatibleParams(ParamInterface $param)
213
    {
214 8
        $params = $this->getParams();
215 8
        foreach ($param->getIncompatibilities() as $incompatibleParamName) {
216 2
            if (!array_key_exists($incompatibleParamName, $params)) {
217 1
                throw new \InvalidArgumentException(sprintf("No @ParamInterface configuration for parameter '%s'.", $incompatibleParamName));
218
            }
219 1
            $incompatibleParam = $params[$incompatibleParamName];
220
221 1
            if ($incompatibleParam->getValue($this->getRequest(), null) !== null) {
222 1
                $exceptionMessage = sprintf(
223 1
                    "'%s' param is incompatible with %s param.",
224 1
                    $param->getName(),
225 1
                    $incompatibleParam->getName()
226 1
                );
227
228 1
                throw new BadRequestHttpException($exceptionMessage);
229
            }
230 7
        }
231 6
    }
232
233
    /**
234
     * @param Constraint[] $constraints
235
     */
236 10
    private function resolveConstraints(array $constraints)
237
    {
238 10
        foreach ($constraints as $constraint) {
239 9
            if ($constraint instanceof ResolvableConstraintInterface) {
240
                $constraint->resolve($this->container);
241
            }
242 10
        }
243 10
    }
244
245
    /**
246
     * @throws \RuntimeException
247
     *
248
     * @return Request
249
     */
250 14 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...
251
    {
252 14
        $request = $this->requestStack->getCurrentRequest();
253 14
        if ($request === null) {
254
            throw new \RuntimeException('There is no current request.');
255
        }
256
257 14
        return $request;
258
    }
259
}
260