Completed
Push — standalone ( 49bbc6...8da518 )
by Philip
09:14
created

RestResourceLoader::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1.008

Importance

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