Completed
Push — master ( beec4b...b0a6d2 )
by Philip
08:54
created

RestResourceLoader::load()   F

Complexity

Conditions 21
Paths 12812

Size

Total Lines 203
Code Lines 123

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 118
CRAP Score 21.002

Importance

Changes 1
Bugs 0 Features 0
Metric Value
dl 0
loc 203
ccs 118
cts 120
cp 0.9833
rs 2
c 1
b 0
f 0
cc 21
eloc 123
nc 12812
nop 2
crap 21.002

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace Dontdrinkandroot\RestBundle\Routing;
4
5
use Dontdrinkandroot\RestBundle\Controller\ContainerAwareRestResourceController;
6
use Dontdrinkandroot\RestBundle\Metadata\Annotation\Method;
7
use Dontdrinkandroot\RestBundle\Metadata\ClassMetadata;
8
use Dontdrinkandroot\RestBundle\Metadata\PropertyMetadata;
9
use Metadata\MetadataFactoryInterface;
10
use Symfony\Component\Config\FileLocatorInterface;
11
use Symfony\Component\Config\Loader\Loader;
12
use Symfony\Component\Finder\Finder;
13
use Symfony\Component\Finder\SplFileInfo;
14
use Symfony\Component\HttpFoundation\Request;
15
use Symfony\Component\Routing\Route;
16
use Symfony\Component\Routing\RouteCollection;
17
18
/**
19
 * @author Philip Washington Sorst <[email protected]>
20
 */
21
class RestResourceLoader extends Loader
22
{
23
    /**
24
     * @var FileLocatorInterface
25
     */
26
    private $fileLocator;
27
28
    /**
29
     * @var MetadataFactoryInterface
30
     */
31
    private $metadataFactory;
32
33
    /**
34
     * @var bool
35
     */
36
    private $securityEnabled;
37
38 14
    public function __construct(
39
        FileLocatorInterface $fileLocator,
40
        MetadataFactoryInterface $metadataFactory,
41
        bool $securityEnabled
42
    ) {
43 14
        $this->fileLocator = $fileLocator;
44 14
        $this->metadataFactory = $metadataFactory;
45 14
        $this->securityEnabled = $securityEnabled;
46 14
    }
47
48
    /**
49
     * {@inheritdoc}
50
     */
51 14
    public function load($resource, $type = null)
52
    {
53 14
        $locatedResource = $this->fileLocator->locate($resource);
54 14
        $files = [];
55 14
        if (is_dir($locatedResource)) {
56 12
            $finder = new Finder();
57 12
            foreach ($finder->in($locatedResource)->name('*.php')->files() as $file) {
58
                /** @var SplFileInfo $file */
59 12
                $files[] = $file->getRealPath();
60
            }
61
        } else {
62 2
            $files[] = $locatedResource;
63
        }
64
65 14
        $routes = new RouteCollection();
66
67 14
        if ($this->securityEnabled) {
68 14
            $this->loadAccessTokenController($routes);
69
        }
70
71 14
        foreach ($files as $file) {
72 14
            $class = $this->findClass($file);
73 14
            if (false === $class) {
74
                throw new \Exception(sprintf('Couldn\'t find class for %s', $file));
75
            }
76
            /** @var ClassMetadata $classMetadata */
77 14
            $classMetadata = $this->metadataFactory->getMetadataForClass($class);
78 14
            if ($classMetadata->isRestResource()) {
79
80 14
                $namePrefix = $classMetadata->getNamePrefix();
81 14
                $pathPrefix = $classMetadata->getPathPrefix();
82 14
                $controller = $this->getController($classMetadata);
83
84
                $defaults = [
85 14
                    '_entityClass' => $class,
86 14
                    '_format'      => 'json'
87
                ];
88
89 14
                if (null !== $classMetadata->getService()) {
90 12
                    $defaults['_service'] = $classMetadata->getService();
91
                }
92
93 14
                if (null !== $method = $classMetadata->getMethod(Method::LIST)) {
94 14
                    $listRoute = new Route($pathPrefix);
95 14
                    $listRoute->setMethods(Request::METHOD_GET);
96 14
                    $listRoute->setDefaults(
97 14
                        array_merge(
98 14
                            $defaults,
99
                            [
100 14
                                '_controller'      => $controller . ':listAction',
101 14
                                '_defaultincludes' => $method->defaultIncludes
102
                            ]
103
                        )
104
                    );
105 14
                    $routes->add($namePrefix . '.list', $listRoute);
106
                }
107
108 14
                if (null !== $method = $classMetadata->getMethod(Method::POST)) {
109 12
                    $postRoute = new Route($pathPrefix);
110 12
                    $postRoute->setMethods(Request::METHOD_POST);
111 12
                    $postRoute->setDefaults(
112 12
                        array_merge(
113 12
                            $defaults,
114
                            [
115 12
                                '_controller'      => $controller . ':postAction',
116 12
                                '_defaultincludes' => $method->defaultIncludes
117
                            ]
118
                        )
119
                    );
120 12
                    $routes->add($namePrefix . '.post', $postRoute);
121
                }
122
123 14
                if (null !== $method = $classMetadata->getMethod(Method::GET)) {
124 14
                    $getRoute = new Route($pathPrefix . '/{id}');
125 14
                    $getRoute->setMethods(Request::METHOD_GET);
126 14
                    $getRoute->setDefaults(
127 14
                        array_merge(
128 14
                            $defaults,
129
                            [
130 14
                                '_controller'      => $controller . ':getAction',
131 14
                                '_defaultincludes' => $method->defaultIncludes
132
                            ]
133
                        )
134
                    );
135 14
                    $routes->add($namePrefix . '.get', $getRoute);
136
                }
137
138 14
                if (null !== $method = $classMetadata->getMethod(Method::PUT)) {
139 12
                    $putRoute = new Route($pathPrefix . '/{id}');
140 12
                    $putRoute->setMethods([Request::METHOD_PUT, Request::METHOD_PATCH]);
141 12
                    $putRoute->setDefaults(
142 12
                        array_merge(
143 12
                            $defaults,
144
                            [
145 12
                                '_controller'      => $controller . ':putAction',
146 12
                                '_defaultincludes' => $method->defaultIncludes
147
                            ]
148
                        )
149
                    );
150 12
                    $routes->add($namePrefix . '.put', $putRoute);
151
                }
152
153 14
                if (null !== $method = $classMetadata->getMethod(Method::DELETE)) {
154 12
                    $deleteRoute = new Route($pathPrefix . '/{id}');
155 12
                    $deleteRoute->setMethods(Request::METHOD_DELETE);
156 12
                    $deleteRoute->setDefaults(
157 12
                        array_merge(
158 12
                            $defaults,
159
                            [
160 12
                                '_controller'      => $controller . ':deleteAction',
161 12
                                '_defaultincludes' => $method->defaultIncludes
162
                            ]
163
                        )
164
                    );
165 12
                    $routes->add($namePrefix . '.delete', $deleteRoute);
166
                }
167
168
                /** @var PropertyMetadata $propertyMetadata */
169 14
                foreach ($classMetadata->propertyMetadata as $propertyMetadata) {
170 14
                    if ($propertyMetadata->isSubResource()) {
171
172 12
                        $subResourcePath = strtolower($propertyMetadata->name);
173 12
                        if (null !== $propertyMetadata->getSubResourcePath()) {
174
                            $subResourcePath = $propertyMetadata->getSubResourcePath();
175
                        }
176
177 12
                        if (null !== $method = $propertyMetadata->getMethod(Method::LIST)) {
178 12
                            $subResourceFullPath = $pathPrefix . '/{id}/' . $subResourcePath;
179 12
                            $subResourceRoute = new Route($subResourceFullPath);
180 12
                            $subResourceRoute->setMethods(Request::METHOD_GET);
181 12
                            $subResourceRoute->setDefaults(
182 12
                                array_merge(
183 12
                                    $defaults,
184
                                    [
185 12
                                        '_controller'      => $controller . ':listSubresourceAction',
186 12
                                        'subresource'      => $propertyMetadata->name,
187 12
                                        '_defaultincludes' => $method->defaultIncludes
188
                                    ]
189
                                )
190
                            );
191 12
                            $routes->add($namePrefix . '.' . $propertyMetadata->name . '.list', $subResourceRoute);
192
                        }
193
194 12
                        if (null !== $method = $propertyMetadata->getMethod(Method::POST)) {
195 12
                            $subResourceFullPath = $pathPrefix . '/{id}/' . $subResourcePath;
196 12
                            $subResourceRoute = new Route($subResourceFullPath);
197 12
                            $subResourceRoute->setMethods(Request::METHOD_POST);
198 12
                            $subResourceRoute->setDefaults(
199 12
                                array_merge(
200 12
                                    $defaults,
201
                                    [
202 12
                                        '_controller'      => $controller . ':postSubresourceAction',
203 12
                                        'subresource'      => $propertyMetadata->name,
204 12
                                        '_defaultincludes' => $method->defaultIncludes
205
                                    ]
206
                                )
207
                            );
208 12
                            $routes->add($namePrefix . '.' . $propertyMetadata->name . '.post', $subResourceRoute);
209
                        }
210
211 12
                        if (null !== $method = $propertyMetadata->getMethod(Method::PUT)) {
212 12
                            $subResourceFullPath = $pathPrefix . '/{id}/' . $subResourcePath . '/{subId}';
213 12
                            $subResourceRoute = new Route($subResourceFullPath);
214 12
                            $subResourceRoute->setMethods(Request::METHOD_PUT);
215 12
                            $subResourceRoute->setDefaults(
216 12
                                array_merge(
217 12
                                    $defaults,
218
                                    [
219 12
                                        '_controller'      => $controller . ':putSubresourceAction',
220 12
                                        'subresource'      => $propertyMetadata->name,
221 12
                                        '_defaultincludes' => $method->defaultIncludes
222
                                    ]
223
                                )
224
                            );
225 12
                            $routes->add($namePrefix . '.' . $propertyMetadata->name . '.put', $subResourceRoute);
226
                        }
227
228 12
                        if (null !== $method = $propertyMetadata->getMethod(Method::DELETE)) {
229 12
                            if ($propertyMetadata->isCollection()) {
230 12
                                $subResourceFullPath = $pathPrefix . '/{id}/' . $subResourcePath . '/{subId}';
231
                            } else {
232 12
                                $subResourceFullPath = $pathPrefix . '/{id}/' . $subResourcePath;
233
                            }
234 12
                            $subResourceRoute = new Route($subResourceFullPath);
235 12
                            $subResourceRoute->setMethods(Request::METHOD_DELETE);
236 12
                            $subResourceRoute->setDefaults(
237 12
                                array_merge(
238 12
                                    $defaults,
239
                                    [
240 12
                                        '_controller' => $controller . ':deleteSubresourceAction',
241 12
                                        'subresource' => $propertyMetadata->name,
242
                                    ]
243
                                )
244
                            );
245 14
                            $routes->add($namePrefix . '.' . $propertyMetadata->name . '.delete', $subResourceRoute);
246
                        }
247
                    }
248
                }
249
            }
250
        }
251
252 14
        return $routes;
253
    }
254
255
    /**
256
     * Taken from {@see AnnotationFileLoader}
257
     * TODO: Evaluate if there is a library method or extract.
258
     *
259
     * @param $file
260
     *
261
     * @return bool|string
262
     */
263 14
    protected function findClass($file)
264
    {
265 14
        $class = false;
266 14
        $namespace = false;
267 14
        $tokens = token_get_all(file_get_contents($file));
268 14
        for ($i = 0; isset($tokens[$i]); ++$i) {
269 14
            $token = $tokens[$i];
270
271 14
            if (!isset($token[1])) {
272 14
                continue;
273
            }
274
275 14
            if (true === $class && T_STRING === $token[0]) {
276 14
                return $namespace . '\\' . $token[1];
277
            }
278
279 14
            if (true === $namespace && T_STRING === $token[0]) {
280 14
                $namespace = $token[1];
281 14
                while (isset($tokens[++$i][1]) && in_array($tokens[$i][0], array(T_NS_SEPARATOR, T_STRING))) {
282 14
                    $namespace .= $tokens[$i][1];
283
                }
284 14
                $token = $tokens[$i];
285
            }
286
287 14
            if (T_CLASS === $token[0]) {
288 14
                $class = true;
289
            }
290
291 14
            if (T_NAMESPACE === $token[0]) {
292 14
                $namespace = true;
293
            }
294
        }
295
296
        return false;
297
    }
298
299
    /**
300
     * {@inheritdoc}
301
     */
302 14
    public function supports($resource, $type = null)
303
    {
304 14
        return 'ddr_rest' === $type;
305
    }
306
307
    /**
308
     * @param ClassMetadata $classMetadata
309
     *
310
     * @return string
311
     */
312 14
    protected function getController(ClassMetadata $classMetadata)
313
    {
314 14
        $controller = ContainerAwareRestResourceController::class;
315 14
        if (null !== $classMetadata->getController()) {
316
            $controller = $classMetadata->getController();
317
        }
318
319 14
        if (strpos($controller, ':') !== false) {
320
            throw new \RuntimeException(sprintf('Short controller notation is not permitted for "%s"', $controller));
321
        }
322
323 14
        if (strpos($controller, '\\') !== false) {
324 14
            $controller .= ':';
325
        }
326
327 14
        return $controller;
328
    }
329
330 14
    private function loadAccessTokenController(RouteCollection $routes)
331
    {
332 14
        $route = new Route('accesstokens');
333 14
        $route->setMethods('POST');
334 14
        $route->setDefault('_controller', 'ddr_rest.controller.access_token:createAction');
335 14
        $route->setDefault('_format', 'json');
336 14
        $routes->add('ddr_rest.accesstoken.create', $route);
337
338 14
        $route = new Route('accesstokens');
339 14
        $route->setMethods('GET');
340 14
        $route->setDefault('_controller', 'ddr_rest.controller.access_token:listAction');
341 14
        $route->setDefault('_format', 'json');
342 14
        $routes->add('ddr_rest.accesstoken.list', $route);
343
344 14
        $route = new Route('accesstokens/{token}');
345 14
        $route->setMethods('DELETE');
346 14
        $route->setDefault('_controller', 'ddr_rest.controller.access_token:deleteAction');
347 14
        $route->setDefault('_format', 'json');
348 14
        $routes->add('ddr_rest.accesstoken.delete', $route);
349 14
    }
350
}
351