ParameterResolver::resolveCriteria()   C
last analyzed

Complexity

Conditions 7
Paths 6

Size

Total Lines 37
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 23
CRAP Score 7

Importance

Changes 0
Metric Value
dl 0
loc 37
rs 6.7272
c 0
b 0
f 0
ccs 23
cts 23
cp 1
cc 7
eloc 20
nc 6
nop 1
crap 7
1
<?php
2
3
/*
4
 * This file is part of the Lug package.
5
 *
6
 * (c) Eric GELOEN <[email protected]>
7
 *
8
 * For the full copyright and license information, please read the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Lug\Bundle\ResourceBundle\Routing;
13
14
use Lug\Bundle\ResourceBundle\Exception\RequestNotFoundException;
15
use Lug\Bundle\ResourceBundle\Exception\RuntimeException;
16
use Lug\Component\Resource\Model\ResourceInterface;
17
use Symfony\Component\HttpFoundation\Request;
18
use Symfony\Component\HttpFoundation\RequestStack;
19
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
20
21
/**
22
 * @author GeLo <[email protected]>
23
 */
24
class ParameterResolver implements ParameterResolverInterface
25
{
26
    /**
27
     * @var RequestStack
28
     */
29
    private $requestStack;
30
31
    /**
32
     * @var PropertyAccessorInterface
33
     */
34
    private $propertyAccessor;
35
36
    /**
37
     * @param RequestStack              $requestStack
38
     * @param PropertyAccessorInterface $propertyAccessor
39
     */
40 82
    public function __construct(RequestStack $requestStack, PropertyAccessorInterface $propertyAccessor)
41
    {
42 82
        $this->requestStack = $requestStack;
43 82
        $this->propertyAccessor = $propertyAccessor;
44 82
    }
45
46
    /**
47
     * {@inheritdoc}
48
     */
49 4
    public function resolveApi()
50
    {
51 4
        if (($request = $this->resolveRequest()) === null) {
52 1
            return true;
53
        }
54
55 3
        return $this->resolveParameter('api', false) || $request->getRequestFormat() !== 'html';
56
    }
57
58
    /**
59
     * {@inheritdoc}
60
     */
61 6
    public function resolveCriteria($mandatory = false)
62
    {
63 6
        if (($request = $this->resolveRequest()) === null) {
64 2
            if ($mandatory) {
65 1
                throw new RequestNotFoundException();
66
            }
67
68 1
            return [];
69
        }
70
71 4
        $value = $this->resolveParameter('criteria', ['id']);
72
73 4
        if (empty($value) && $mandatory) {
74 1
            throw new RuntimeException(sprintf(
75 1
                'The criteria could not be found for the route "%s".',
76 1
                $request->attributes->get('_route')
77 1
            ));
78
        }
79
80 3
        $criteria = [];
81
82 3
        foreach ($value as $identifier) {
83 3
            $value = $request->get($identifier);
84
85 3
            if ($value === null) {
86 1
                throw new RuntimeException(sprintf(
87 1
                    'The criteria "%s" could not be found for the route "%s".',
88 1
                    $identifier,
89 1
                    $request->attributes->get('_route')
90 1
                ));
91
            }
92
93 2
            $criteria[$identifier] = $value;
94 2
        }
95
96 2
        return $criteria;
97
    }
98
99
    /**
100
     * {@inheritdoc}
101
     */
102 3
    public function resolveCurrentPage()
103
    {
104 3
        $default = 1;
105
106 3
        if (($request = $this->resolveRequest()) === null) {
107 1
            return $default;
108
        }
109
110 2
        return $request->get('page', $default);
111
    }
112
113
    /**
114
     * {@inheritdoc}
115
     */
116 3
    public function resolveForm(ResourceInterface $resource)
117
    {
118 3
        return $this->resolveParameter('form', $resource->getForm());
119
    }
120
121
    /**
122
     * {@inheritdoc}
123
     */
124 2
    public function resolveGrid(ResourceInterface $resource)
125
    {
126 2
        if (($request = $this->resolveRequest()) === null) {
127 1
            throw new RequestNotFoundException();
128
        }
129
130 1
        return array_merge(['resource' => $resource], $this->resolveParameter('grid', []));
0 ignored issues
show
Bug Best Practice introduced by
The return type of return array_merge(array...eter('grid', array())); (array<string,Lug\Compone...odel\ResourceInterface>) is incompatible with the return type declared by the interface Lug\Bundle\ResourceBundl...rInterface::resolveGrid of type array.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
131
    }
132
133
    /**
134
     * {@inheritdoc}
135
     */
136 3
    public function resolveHateoas()
137
    {
138 3
        return $this->resolveParameter('hateoas', false);
139
    }
140
141
    /**
142
     * {@inheritdoc}
143
     */
144 3 View Code Duplication
    public function resolveLocationRoute()
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...
145
    {
146 3
        if (($request = $this->resolveRequest()) === null) {
147 1
            throw new RequestNotFoundException();
148
        }
149
150 2
        $locationRoute = $this->resolveParameter('location_route');
151
152 2
        if (empty($locationRoute)) {
153 1
            throw new RuntimeException(sprintf(
154 1
                'The location route could not be found for the route "%s".',
155 1
                $request->attributes->get('_route')
156 1
            ));
157
        }
158
159 1
        return $locationRoute;
160
    }
161
162
    /**
163
     * {@inheritdoc}
164
     */
165 3
    public function resolveLocationRouteParameters($object)
166
    {
167 3
        return $this->resolveRouteParameter('location_route_parameters', $object);
168
    }
169
170
    /**
171
     * {@inheritdoc}
172
     */
173 6
    public function resolveMaxPerPage()
174
    {
175 6
        $default = $this->resolveParameter('max_per_page', 10);
176
177 6
        if (($request = $this->resolveRequest()) === null) {
178 1
            return $default;
179
        }
180
181 5
        $maxPerPage = $request->get('limit', $default);
182
183 5
        if ($maxPerPage <= 0) {
184 1
            return $default;
185
        }
186
187 4
        if ($maxPerPage > 100) {
188 1
            return 100;
189
        }
190
191 3
        return $maxPerPage;
192
    }
193
194
    /**
195
     * {@inheritdoc}
196
     */
197 3 View Code Duplication
    public function resolveRedirectRoute()
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...
198
    {
199 3
        if (($request = $this->resolveRequest()) === null) {
200 1
            throw new RequestNotFoundException();
201
        }
202
203 2
        $redirectRoute = $this->resolveParameter('redirect_route');
204
205 2
        if (empty($redirectRoute)) {
206 1
            throw new RuntimeException(sprintf(
207 1
                'The redirect route could not be found for the route "%s".',
208 1
                $request->attributes->get('_route')
209 1
            ));
210
        }
211
212 1
        return $redirectRoute;
213
    }
214
215
    /**
216
     * {@inheritdoc}
217
     */
218 6
    public function resolveRedirectRouteParameters($object = null, $forwardParameters = false)
219
    {
220 6
        $routeParameters = $this->resolveRouteParameter('redirect_route_parameters', $object);
221
222 5
        if ($forwardParameters && ($request = $this->resolveRequest()) !== null) {
223 1
            return array_replace_recursive($request->query->all(), $routeParameters);
224
        }
225
226 4
        return $routeParameters;
227
    }
228
229
    /**
230
     * @return bool
231
     */
232 3
    public function resolveRedirectRouteParametersForward()
233
    {
234 3
        return $this->resolveParameter('redirect_route_parameters_forward', false);
235
    }
236
237
    /**
238
     * {@inheritdoc}
239
     */
240 3
    public function resolveRepositoryMethod($action)
241
    {
242 3
        return $this->resolveParameter('repository_method', 'findFor'.ucfirst(strtolower($action)));
243
    }
244
245
    /**
246
     * {@inheritdoc}
247
     */
248 3
    public function resolveSerializerGroups()
249
    {
250 3
        return $this->resolveParameter('serializer_groups', []);
251
    }
252
253
    /**
254
     * {@inheritdoc}
255
     */
256 3
    public function resolveSerializerNull()
257
    {
258 3
        return $this->resolveParameter('serializer_null', true);
259
    }
260
261
    /**
262
     * {@inheritdoc}
263
     */
264 3
    public function resolveStatusCode($statusCode)
265
    {
266 3
        return $this->resolveParameter('status_code', $statusCode);
267
    }
268
269
    /**
270
     * {@inheritdoc}
271
     */
272 3
    public function resolveSorting()
273
    {
274 3
        return $this->resolveParameter('sorting', []);
275
    }
276
277
    /**
278
     * {@inheritdoc}
279
     */
280 3 View Code Duplication
    public function resolveTemplate()
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...
281
    {
282 3
        if (($request = $this->resolveRequest()) === null) {
283 1
            throw new RequestNotFoundException();
284
        }
285
286 2
        $template = $this->resolveParameter('template');
287
288 2
        if (empty($template)) {
289 1
            throw new RuntimeException(sprintf(
290 1
                'The template could not be found for the route "%s".',
291 1
                $request->attributes->get('_route')
292 1
            ));
293
        }
294
295 1
        return $template;
296
    }
297
298
    /**
299
     * {@inheritdoc}
300
     */
301 3
    public function resolveThemes()
302
    {
303 3
        return $this->resolveParameter('themes', []);
304
    }
305
306
    /**
307
     * {@inheritdoc}
308
     */
309 5
    public function resolveTranslationDomain()
310
    {
311 5
        return $this->resolveParameter(
312 5
            'translation_domain',
313 5
            $this->resolveParameter('grid') === null ? 'forms' : 'grids'
314 5
        );
315
    }
316
317
    /**
318
     * {@inheritdoc}
319
     */
320 3
    public function resolveValidationGroups()
321
    {
322 3
        return $this->resolveParameter('validation_groups', []);
323
    }
324
325
    /**
326
     * {@inheritdoc}
327
     */
328 3
    public function resolveVoter()
329
    {
330 3
        return $this->resolveParameter('voter', false);
331
    }
332
333
    /**
334
     * @param string $parameter
335
     * @param mixed  $default
336
     *
337
     * @return mixed
338
     */
339 67
    private function resolveParameter($parameter, $default = null)
340
    {
341 67
        if (($request = $this->resolveRequest()) === null) {
342 15
            return $default;
343
        }
344
345 52
        return $request->attributes->get('_lug_'.$parameter, $default);
346
    }
347
348
    /**
349
     * @return Request|null
350
     */
351 77
    private function resolveRequest()
352
    {
353 77
        return $this->requestStack->getMasterRequest();
354
    }
355
356
    /**
357
     * @param string      $parameter
358
     * @param object|null $object
359
     *
360
     * @return mixed[]
361
     */
362 9
    private function resolveRouteParameter($parameter, $object = null)
363
    {
364 9
        $propertyPaths = $this->resolveParameter($parameter, []);
365 9
        $parameters = [];
366
367 9
        if ($object === null) {
368 2
            if (!empty($propertyPaths)) {
369 1
                throw new RuntimeException(sprintf(
370 1
                    'The route parameters could not be found for the route "%s".',
371
                    $parameter
372 1
                ));
373
            }
374
375 1
            return $parameters;
376
        }
377
378 7
        foreach ($propertyPaths as $propertyPath) {
379 3
            $parameters[$propertyPath] = $this->propertyAccessor->getValue($object, $propertyPath);
380 7
        }
381
382 7
        return $parameters;
383
    }
384
}
385