Completed
Push — master ( c114e4...0fa665 )
by Eric
9s
created

ParameterResolver::resolveRepositoryMethod()   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 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
cc 1
eloc 2
nc 1
nop 1
crap 1
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 77
    public function __construct(RequestStack $requestStack, PropertyAccessorInterface $propertyAccessor)
41
    {
42 77
        $this->requestStack = $requestStack;
43 77
        $this->propertyAccessor = $propertyAccessor;
44 77
    }
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 resolveSorting()
251
    {
252 3
        return $this->resolveParameter('sorting', []);
253
    }
254
255
    /**
256
     * {@inheritdoc}
257
     */
258 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...
259
    {
260 3
        if (($request = $this->resolveRequest()) === null) {
261 1
            throw new RequestNotFoundException();
262
        }
263
264 2
        $template = $this->resolveParameter('template');
265
266 2
        if (empty($template)) {
267 1
            throw new RuntimeException(sprintf(
268 1
                'The template could not be found for the route "%s".',
269 1
                $request->attributes->get('_route')
270 1
            ));
271
        }
272
273 1
        return $template;
274
    }
275
276
    /**
277
     * {@inheritdoc}
278
     */
279 3
    public function resolveThemes()
280
    {
281 3
        return $this->resolveParameter('themes', []);
282
    }
283
284
    /**
285
     * {@inheritdoc}
286
     */
287 5
    public function resolveTranslationDomain()
288
    {
289 5
        return $this->resolveParameter(
290 5
            'translation_domain',
291 5
            $this->resolveParameter('grid') === null ? 'forms' : 'grids'
292 5
        );
293
    }
294
295
    /**
296
     * {@inheritdoc}
297
     */
298 3
    public function resolveValidationGroups()
299
    {
300 3
        return $this->resolveParameter('validation_groups', []);
301
    }
302
303
    /**
304
     * {@inheritdoc}
305
     */
306 3
    public function resolveVoter()
307
    {
308 3
        return $this->resolveParameter('voter', false);
309
    }
310
311
    /**
312
     * @param string $parameter
313
     * @param mixed  $default
314
     *
315
     * @return mixed
316
     */
317 64
    private function resolveParameter($parameter, $default = null)
318
    {
319 64
        if (($request = $this->resolveRequest()) === null) {
320 14
            return $default;
321
        }
322
323 50
        return $request->attributes->get('_lug_'.$parameter, $default);
324
    }
325
326
    /**
327
     * @return Request|null
328
     */
329 72
    private function resolveRequest()
330
    {
331 72
        return $this->requestStack->getMasterRequest();
332
    }
333
334
    /**
335
     * @param string      $parameter
336
     * @param object|null $object
337
     *
338
     * @return mixed[]
339
     */
340 9
    private function resolveRouteParameter($parameter, $object = null)
341
    {
342 9
        $propertyPaths = $this->resolveParameter($parameter, []);
343 9
        $parameters = [];
344
345 9
        if ($object === null) {
346 2
            if (!empty($propertyPaths)) {
347 1
                throw new RuntimeException(sprintf(
348 1
                    'The route parameters could not be found for the route "%s".',
349
                    $parameter
350 1
                ));
351
            }
352
353 1
            return $parameters;
354
        }
355
356 7
        foreach ($propertyPaths as $propertyPath) {
357 3
            $parameters[$propertyPath] = $this->propertyAccessor->getValue($object, $propertyPath);
358 7
        }
359
360 7
        return $parameters;
361
    }
362
}
363