Completed
Push — master ( a2ccb4...2afc29 )
by Philip
05:08
created

RestResourceLoader   B

Complexity

Total Complexity 36

Size/Duplication

Total Lines 291
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 9

Test Coverage

Coverage 97.08%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 36
lcom 1
cbo 9
dl 0
loc 291
ccs 133
cts 137
cp 0.9708
rs 8.8
c 1
b 0
f 0

5 Methods

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