Completed
Push — standalone ( a45559...3ee90b )
by Philip
04:55
created

RestResourceLoader   A

Complexity

Total Complexity 34

Size/Duplication

Total Lines 269
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 9

Test Coverage

Coverage 88.71%

Importance

Changes 0
Metric Value
wmc 34
c 0
b 0
f 0
lcom 1
cbo 9
dl 0
loc 269
ccs 110
cts 124
cp 0.8871
rs 9.2

5 Methods

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