Completed
Push — master ( 2afc29...29656f )
by Philip
06:07
created

RestResourceLoader::loadAccessTokenController()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 20
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 17
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 20
ccs 17
cts 17
cp 1
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 16
nc 1
nop 1
crap 1
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
                        array_merge(
98
                            $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
                        array_merge(
113
                            $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
                        array_merge(
128
                            $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);
141 12
                    $putRoute->setDefaults(
142
                        array_merge(
143
                            $defaults,
144
                            [
145 12
                                '_controller'      => $controller . ':putAction',
146 12
                                '_defaultincludes' => $method->defaultIncludes
147
                            ]
148
                        )
149
                    );
150 12
                    $routes->add($namePrefix . '.put', $putRoute);
151
152 12
                    $patchRoute = new Route($pathPrefix . '/{id}');
153 12
                    $patchRoute->setMethods(Request::METHOD_PATCH);
154 12
                    $patchRoute->setDefaults(array_merge($defaults, ['_controller' => $controller . ':put']));
155 12
                    $routes->add($namePrefix . '.patch', $patchRoute);
156
                }
157
158 14
                if (null !== $method = $classMetadata->getMethod(Method::DELETE)) {
159 12
                    $deleteRoute = new Route($pathPrefix . '/{id}');
160 12
                    $deleteRoute->setMethods(Request::METHOD_DELETE);
161 12
                    $deleteRoute->setDefaults(
162
                        array_merge(
163
                            $defaults,
164
                            [
165 12
                                '_controller'      => $controller . ':deleteAction',
166 12
                                '_defaultincludes' => $method->defaultIncludes
167
                            ]
168
                        )
169
                    );
170 12
                    $routes->add($namePrefix . '.delete', $deleteRoute);
171
                }
172
173
                /** @var PropertyMetadata $propertyMetadata */
174 14
                foreach ($classMetadata->propertyMetadata as $propertyMetadata) {
175 14
                    if ($propertyMetadata->isSubResource()) {
176
177 12
                        $subResourcePath = strtolower($propertyMetadata->name);
178 12
                        if (null !== $propertyMetadata->getSubResourcePath()) {
179
                            $subResourcePath = $propertyMetadata->getSubResourcePath();
180
                        }
181
182 12
                        if (null !== $method = $propertyMetadata->getMethod(Method::LIST)) {
183 12
                            $subResourceFullPath = $pathPrefix . '/{id}/' . $subResourcePath;
184 12
                            $subResourceRoute = new Route($subResourceFullPath);
185 12
                            $subResourceRoute->setMethods(Request::METHOD_GET);
186 12
                            $subResourceRoute->setDefaults(
187
                                array_merge(
188
                                    $defaults,
189
                                    [
190 12
                                        '_controller'      => $controller . ':listSubresourceAction',
191 12
                                        'subresource'      => $propertyMetadata->name,
192 12
                                        '_defaultincludes' => $method->defaultIncludes
193
                                    ]
194
                                )
195
                            );
196 12
                            $routes->add($namePrefix . '.' . $propertyMetadata->name . '.list', $subResourceRoute);
197
                        }
198
199 12
                        if (null !== $method = $propertyMetadata->getMethod(Method::POST)) {
200 12
                            $subResourceFullPath = $pathPrefix . '/{id}/' . $subResourcePath;
201 12
                            $subResourceRoute = new Route($subResourceFullPath);
202 12
                            $subResourceRoute->setMethods(Request::METHOD_POST);
203 12
                            $subResourceRoute->setDefaults(
204
                                array_merge(
205
                                    $defaults,
206
                                    [
207 12
                                        '_controller'      => $controller . ':postSubresourceAction',
208 12
                                        'subresource'      => $propertyMetadata->name,
209 12
                                        '_defaultincludes' => $method->defaultIncludes
210
                                    ]
211
                                )
212
                            );
213 12
                            $routes->add($namePrefix . '.' . $propertyMetadata->name . '.post', $subResourceRoute);
214
                        }
215
216 12
                        if (null !== $method = $propertyMetadata->getMethod(Method::PUT)) {
217 12
                            $subResourceFullPath = $pathPrefix . '/{id}/' . $subResourcePath . '/{subId}';
218 12
                            $subResourceRoute = new Route($subResourceFullPath);
219 12
                            $subResourceRoute->setMethods(Request::METHOD_PUT);
220 12
                            $subResourceRoute->setDefaults(
221
                                array_merge(
222
                                    $defaults,
223
                                    [
224 12
                                        '_controller'      => $controller . ':putSubresourceAction',
225 12
                                        'subresource'      => $propertyMetadata->name,
226 12
                                        '_defaultincludes' => $method->defaultIncludes
227
                                    ]
228
                                )
229
                            );
230 12
                            $routes->add($namePrefix . '.' . $propertyMetadata->name . '.put', $subResourceRoute);
231
                        }
232
233 12
                        if (null !== $method = $propertyMetadata->getMethod(Method::DELETE)) {
234 12
                            if ($propertyMetadata->isCollection()) {
235 12
                                $subResourceFullPath = $pathPrefix . '/{id}/' . $subResourcePath . '/{subId}';
236
                            } else {
237 12
                                $subResourceFullPath = $pathPrefix . '/{id}/' . $subResourcePath;
238
                            }
239 12
                            $subResourceRoute = new Route($subResourceFullPath);
240 12
                            $subResourceRoute->setMethods(Request::METHOD_DELETE);
241 12
                            $subResourceRoute->setDefaults(
242
                                array_merge(
243
                                    $defaults,
244
                                    [
245 12
                                        '_controller' => $controller . ':deleteSubresourceAction',
246 12
                                        'subresource' => $propertyMetadata->name,
247
                                    ]
248
                                )
249
                            );
250 14
                            $routes->add($namePrefix . '.' . $propertyMetadata->name . '.delete', $subResourceRoute);
251
                        }
252
                    }
253
                }
254
            }
255
        }
256
257 14
        return $routes;
258
    }
259
260
    /**
261
     * Taken from {@see AnnotationFileLoader}
262
     * TODO: Evaluate if there is a library method or extract.
263
     *
264
     * @param $file
265
     *
266
     * @return bool|string
267
     */
268 14
    protected function findClass($file)
269
    {
270 14
        $class = false;
271 14
        $namespace = false;
272 14
        $tokens = token_get_all(file_get_contents($file));
273 14
        for ($i = 0; isset($tokens[$i]); ++$i) {
274 14
            $token = $tokens[$i];
275
276 14
            if (!isset($token[1])) {
277 14
                continue;
278
            }
279
280 14
            if (true === $class && T_STRING === $token[0]) {
281 14
                return $namespace . '\\' . $token[1];
282
            }
283
284 14
            if (true === $namespace && T_STRING === $token[0]) {
285 14
                $namespace = $token[1];
286 14
                while (isset($tokens[++$i][1]) && in_array($tokens[$i][0], array(T_NS_SEPARATOR, T_STRING))) {
287 14
                    $namespace .= $tokens[$i][1];
288
                }
289 14
                $token = $tokens[$i];
290
            }
291
292 14
            if (T_CLASS === $token[0]) {
293 14
                $class = true;
294
            }
295
296 14
            if (T_NAMESPACE === $token[0]) {
297 14
                $namespace = true;
298
            }
299
        }
300
301
        return false;
302
    }
303
304
    /**
305
     * {@inheritdoc}
306
     */
307 14
    public function supports($resource, $type = null)
308
    {
309 14
        return 'ddr_rest' === $type;
310
    }
311
312
    /**
313
     * @param ClassMetadata $classMetadata
314
     *
315
     * @return string
316
     */
317 14
    protected function getController(ClassMetadata $classMetadata)
318
    {
319 14
        $controller = ContainerAwareRestResourceController::class;
320 14
        if (null !== $classMetadata->getController()) {
321
            $controller = $classMetadata->getController();
322
        }
323
324 14
        if (strpos($controller, '\\') !== false) {
325 14
            $controller .= ':';
326
        }
327
328 14
        return $controller;
329
    }
330
331 14
    private function loadAccessTokenController(RouteCollection $routes)
332
    {
333 14
        $route = new Route('accesstokens');
334 14
        $route->setMethods('POST');
335 14
        $route->setDefault('_controller', 'ddr_rest.controller.access_token:createAction');
336 14
        $route->setDefault('_format', 'json');
337 14
        $routes->add('ddr_rest.accesstoken.create', $route);
338
339 14
        $route = new Route('accesstokens');
340 14
        $route->setMethods('GET');
341 14
        $route->setDefault('_controller', 'ddr_rest.controller.access_token:listAction');
342 14
        $route->setDefault('_format', 'json');
343 14
        $routes->add('ddr_rest.accesstoken.list', $route);
344
345 14
        $route = new Route('accesstokens/{token}');
346 14
        $route->setMethods('DELETE');
347 14
        $route->setDefault('_controller', 'ddr_rest.controller.access_token:deleteAction');
348 14
        $route->setDefault('_format', 'json');
349 14
        $routes->add('ddr_rest.accesstoken.delete', $route);
350 14
    }
351
}
352