Completed
Push — master ( 094d7a...9edd9c )
by Philip
04:06
created

RestResourceLoader::getController()   A

Complexity

Conditions 4
Paths 6

Size

Total Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 4.1755

Importance

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