Completed
Push — master ( 346488...5472e0 )
by Eric
8s
created

ParameterResolver::resolveLocationRoute()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 17
Code Lines 9

Duplication

Lines 17
Ratio 100 %

Code Coverage

Tests 10
CRAP Score 3

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 17
loc 17
ccs 10
cts 10
cp 1
rs 9.4285
cc 3
eloc 9
nc 3
nop 0
crap 3
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 80
    public function __construct(RequestStack $requestStack, PropertyAccessorInterface $propertyAccessor)
41
    {
42 80
        $this->requestStack = $requestStack;
43 80
        $this->propertyAccessor = $propertyAccessor;
44 80
    }
45
46
    /**
47
     * {@inheritdoc}
48
     */
49 4 View Code Duplication
    public function resolveApi()
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...
50
    {
51 4
        $default = false;
52
53 4
        if (($request = $this->resolveRequest()) === null) {
54 1
            return $default;
55
        }
56
57 3
        return $this->resolveParameter('api', $default) || $request->getRequestFormat() !== 'html';
58
    }
59
60
    /**
61
     * {@inheritdoc}
62
     */
63 6
    public function resolveCriteria($mandatory = false)
64
    {
65 6
        if (($request = $this->resolveRequest()) === null) {
66 2
            if ($mandatory) {
67 1
                throw new RequestNotFoundException();
68
            }
69
70 1
            return [];
71
        }
72
73 4
        $value = $this->resolveParameter('criteria', ['id']);
74
75 4
        if (empty($value) && $mandatory) {
76 1
            throw new RuntimeException(sprintf(
77 1
                'The criteria could not be found for the route "%s".',
78 1
                $request->attributes->get('_route')
79 1
            ));
80
        }
81
82 3
        $criteria = [];
83
84 3
        foreach ($value as $identifier) {
85 3
            $value = $request->get($identifier);
86
87 3
            if ($value === null) {
88 1
                throw new RuntimeException(sprintf(
89 1
                    'The criteria "%s" could not be found for the route "%s".',
90 1
                    $identifier,
91 1
                    $request->attributes->get('_route')
92 1
                ));
93
            }
94
95 2
            $criteria[$identifier] = $value;
96 2
        }
97
98 2
        return $criteria;
99
    }
100
101
    /**
102
     * {@inheritdoc}
103
     */
104 4 View Code Duplication
    public function resolveCurrentPage()
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...
105
    {
106 4
        $default = 1;
107
108 4
        if (($request = $this->resolveRequest()) === null) {
109 1
            return $default;
110
        }
111
112 3
        return $request->get($this->resolveParameter('page_parameter', 'page'), $default);
113
    }
114
115
    /**
116
     * {@inheritdoc}
117
     */
118 3
    public function resolveForm(ResourceInterface $resource)
119
    {
120 3
        return $this->resolveParameter('form', $resource->getForm());
121
    }
122
123
    /**
124
     * {@inheritdoc}
125
     */
126 2
    public function resolveGrid(ResourceInterface $resource)
127
    {
128 2
        if (($request = $this->resolveRequest()) === null) {
129 1
            throw new RequestNotFoundException();
130
        }
131
132 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...
133
    }
134
135
    /**
136
     * {@inheritdoc}
137
     */
138 3
    public function resolveHateoas()
139
    {
140 3
        return $this->resolveParameter('hateoas', false);
141
    }
142
143
    /**
144
     * {@inheritdoc}
145
     */
146 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...
147
    {
148 3
        if (($request = $this->resolveRequest()) === null) {
149 1
            throw new RequestNotFoundException();
150
        }
151
152 2
        $locationRoute = $this->resolveParameter('location_route');
153
154 2
        if (empty($locationRoute)) {
155 1
            throw new RuntimeException(sprintf(
156 1
                'The location route could not be found for the route "%s".',
157 1
                $request->attributes->get('_route')
158 1
            ));
159
        }
160
161 1
        return $locationRoute;
162
    }
163
164
    /**
165
     * {@inheritdoc}
166
     */
167 3
    public function resolveLocationRouteParameters($object)
168
    {
169 3
        return $this->resolveRouteParameter('location_route_parameters', $object);
170
    }
171
172
    /**
173
     * {@inheritdoc}
174
     */
175 3
    public function resolveMaxPerPage()
176
    {
177 3
        return $this->resolveParameter('max_per_page', 10);
178
    }
179
180
    /**
181
     * {@inheritdoc}
182
     */
183 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...
184
    {
185 3
        if (($request = $this->resolveRequest()) === null) {
186 1
            throw new RequestNotFoundException();
187
        }
188
189 2
        $redirectRoute = $this->resolveParameter('redirect_route');
190
191 2
        if (empty($redirectRoute)) {
192 1
            throw new RuntimeException(sprintf(
193 1
                'The redirect route could not be found for the route "%s".',
194 1
                $request->attributes->get('_route')
195 1
            ));
196
        }
197
198 1
        return $redirectRoute;
199
    }
200
201
    /**
202
     * {@inheritdoc}
203
     */
204 6
    public function resolveRedirectRouteParameters($object = null, $forwardParameters = false)
205
    {
206 6
        $routeParameters = $this->resolveRouteParameter('redirect_route_parameters', $object);
207
208 5
        if ($forwardParameters && ($request = $this->resolveRequest()) !== null) {
209 1
            return array_replace_recursive($request->query->all(), $routeParameters);
210
        }
211
212 4
        return $routeParameters;
213
    }
214
215
    /**
216
     * @return bool
217
     */
218 3
    public function resolveRedirectRouteParametersForward()
219
    {
220 3
        return $this->resolveParameter('redirect_route_parameters_forward', false);
221
    }
222
223
    /**
224
     * {@inheritdoc}
225
     */
226 3
    public function resolveRepositoryMethod($action)
227
    {
228 3
        return $this->resolveParameter('repository_method', 'findFor'.ucfirst(strtolower($action)));
229
    }
230
231
    /**
232
     * {@inheritdoc}
233
     */
234 3
    public function resolveSerializerGroups()
235
    {
236 3
        return $this->resolveParameter('serializer_groups', []);
237
    }
238
239
    /**
240
     * {@inheritdoc}
241
     */
242 3
    public function resolveSerializerNull()
243
    {
244 3
        return $this->resolveParameter('serializer_null', true);
245
    }
246
247
    /**
248
     * {@inheritdoc}
249
     */
250 3
    public function resolveStatusCode($statusCode)
251
    {
252 3
        return $this->resolveParameter('status_code', $statusCode);
253
    }
254
255
    /**
256
     * {@inheritdoc}
257
     */
258 3
    public function resolveSorting()
259
    {
260 3
        return $this->resolveParameter('sorting', []);
261
    }
262
263
    /**
264
     * {@inheritdoc}
265
     */
266 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...
267
    {
268 3
        if (($request = $this->resolveRequest()) === null) {
269 1
            throw new RequestNotFoundException();
270
        }
271
272 2
        $template = $this->resolveParameter('template');
273
274 2
        if (empty($template)) {
275 1
            throw new RuntimeException(sprintf(
276 1
                'The template could not be found for the route "%s".',
277 1
                $request->attributes->get('_route')
278 1
            ));
279
        }
280
281 1
        return $template;
282
    }
283
284
    /**
285
     * {@inheritdoc}
286
     */
287 3
    public function resolveThemes()
288
    {
289 3
        return $this->resolveParameter('themes', []);
290
    }
291
292
    /**
293
     * {@inheritdoc}
294
     */
295 5
    public function resolveTranslationDomain()
296
    {
297 5
        return $this->resolveParameter(
298 5
            'translation_domain',
299 5
            $this->resolveParameter('grid') === null ? 'forms' : 'grids'
300 5
        );
301
    }
302
303
    /**
304
     * {@inheritdoc}
305
     */
306 3
    public function resolveValidationGroups()
307
    {
308 3
        return $this->resolveParameter('validation_groups', []);
309
    }
310
311
    /**
312
     * {@inheritdoc}
313
     */
314 3
    public function resolveVoter()
315
    {
316 3
        return $this->resolveParameter('voter', false);
317
    }
318
319
    /**
320
     * @param string $parameter
321
     * @param mixed  $default
322
     *
323
     * @return mixed
324
     */
325 67
    private function resolveParameter($parameter, $default = null)
326
    {
327 67
        if (($request = $this->resolveRequest()) === null) {
328 15
            return $default;
329
        }
330
331 52
        return $request->attributes->get('_lug_'.$parameter, $default);
332
    }
333
334
    /**
335
     * @return Request|null
336
     */
337 75
    private function resolveRequest()
338
    {
339 75
        return $this->requestStack->getMasterRequest();
340
    }
341
342
    /**
343
     * @param string      $parameter
344
     * @param object|null $object
345
     *
346
     * @return mixed[]
347
     */
348 9
    private function resolveRouteParameter($parameter, $object = null)
349
    {
350 9
        $propertyPaths = $this->resolveParameter($parameter, []);
351 9
        $parameters = [];
352
353 9
        if ($object === null) {
354 2
            if (!empty($propertyPaths)) {
355 1
                throw new RuntimeException(sprintf(
356 1
                    'The route parameters could not be found for the route "%s".',
357
                    $parameter
358 1
                ));
359
            }
360
361 1
            return $parameters;
362
        }
363
364 7
        foreach ($propertyPaths as $propertyPath) {
365 3
            $parameters[$propertyPath] = $this->propertyAccessor->getValue($object, $propertyPath);
366 7
        }
367
368 7
        return $parameters;
369
    }
370
}
371