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