Completed
Pull Request — master (#138)
by Paul
03:43 queued 19s
created

AbstractModule::loadFastRouteRoutes()   B

Complexity

Conditions 3
Paths 3

Size

Total Lines 33
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 33
rs 8.8571
cc 3
eloc 20
nc 3
nop 1
1
<?php
2
/**
3
 * This file is part of the PPI Framework.
4
 *
5
 * @copyright  Copyright (c) 2011-2013 Paul Dragoonis <[email protected]>
6
 * @license    http://opensource.org/licenses/mit-license.php MIT
7
 *
8
 * @link       http://www.ppi.io
9
 */
10
11
namespace PPI\Framework\Module;
12
13
use PPI\Framework\Config\ConfigLoader;
14
use PPI\Framework\Console\Application;
15
use PPI\LaravelRouting\Loader\LaravelRoutesLoader;
16
use PPI\LaravelRouting\LaravelRouter;
17
use PPI\FastRoute\Wrapper\FastRouteWrapper;
18
use PPI\Framework\Router\Loader\YamlFileLoader;
19
20
use Symfony\Component\Config\FileLocator;
21
use Symfony\Component\Finder\Finder;
22
23
use Zend\ModuleManager\Feature\ConfigProviderInterface;
24
use Zend\Stdlib\ArrayUtils;
25
26
use Aura\Router\Router as AuraRouter;
27
use Aura\Router\RouterFactory as AuraRouterFactory;
28
29
use Illuminate\Events\Dispatcher;
30
31
/**
32
 * The base PPI module class.
33
 *
34
 * @author Paul Dragoonis <[email protected]>
35
 */
36
abstract class AbstractModule implements ModuleInterface, ConfigProviderInterface
37
{
38
    /**
39
     * @var string The Module name.
40
     */
41
    protected $name;
42
43
    /**
44
     * @var \ReflectionObject
45
     */
46
    protected $reflected;
47
48
    /**
49
     * @todo Add inline documentation.
50
     *
51
     * @var null
52
     */
53
    protected $config;
54
55
    /**
56
     * Configuration loader.
57
     *
58
     * @var null|\PPI\Framework\Config\ConfigLoader
59
     */
60
    protected $configLoader;
61
62
    /**
63
     * @todo Add inline documentation.
64
     *
65
     * @var null
66
     */
67
    protected $routes;
68
69
    /**
70
     * @todo Add inline documentation.
71
     *
72
     * @var null
73
     */
74
    protected $services;
75
76
    /**
77
     * Load up our routes.
78
     *
79
     * @param string $path
80
     *
81
     * @return \Symfony\Component\Routing\RouteCollection
82
     */
83 View Code Duplication
    protected function loadSymfonyRoutes($path)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
84
    {
85
        if ($this->routes === null) {
86
            $loader = new YamlFileLoader(new FileLocator(array(dirname($path))));
87
            $loader->setDefaults(array('_module' => $this->getName()));
88
89
            $routesCollection = $loader->load(pathinfo($path, PATHINFO_FILENAME) . '.' . pathinfo($path, PATHINFO_EXTENSION));
90
            $this->routes     = $routesCollection;
0 ignored issues
show
Documentation Bug introduced by
It seems like $routesCollection of type object<Symfony\Component\Routing\RouteCollection> is incompatible with the declared type null of property $routes.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
91
        }
92
93
        return $this->routes;
94
    }
95
96
    /**
97
     * Load up our routes.
98
     *
99
     * @deprecated Please use loadSymfonyRoutes instead
100
     * @param string $path
101
     * @return \Symfony\Component\Routing\RouteCollection
102
     */
103 View Code Duplication
    protected function loadYamlRoutes($path)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
104
    {
105
        if ($this->routes === null) {
106
            $loader = new YamlFileLoader(new FileLocator(array(dirname($path))));
107
            $loader->setDefaults(array('_module' => $this->getName()));
108
109
            $routesCollection = $loader->load(pathinfo($path, PATHINFO_FILENAME) . '.' . pathinfo($path, PATHINFO_EXTENSION));
110
            $this->routes     = $routesCollection;
0 ignored issues
show
Documentation Bug introduced by
It seems like $routesCollection of type object<Symfony\Component\Routing\RouteCollection> is incompatible with the declared type null of property $routes.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
111
        }
112
113
        return $this->routes;
114
    }
115
116
    /**
117
     * @param string $path
118
     * @return AuraRouter
119
     * @throws \Exception when the included routes file doesn't return an AuraRouter back
120
     */
121
    protected function loadLaravelRoutes($path)
122
    {
123
        $router = (new LaravelRoutesLoader(
124
            new LaravelRouter(new Dispatcher)
125
        ))->load($path);
126
        $router->setModuleName($this->getName());
127
        return $router;
128
    }
129
130
    /**
131
     * @param $path
132
     * @return FastRouteWrapper
133
     */
134
    protected function loadFastRouteRoutes($path)
135
    {
136
        $routeParser = new \FastRoute\RouteParser\Std();
137
        $dataGenerator = new \FastRoute\DataGenerator\GroupCountBased();
138
        $routeCollector = new \FastRoute\RouteCollector($routeParser, $dataGenerator);
139
140
        if(!is_readable($path)) {
141
            throw new \InvalidArgumentException('Invalid fast route routes path found: ' . $path);
142
        }
143
144
        // The included file must return the laravel router
145
        $getRouteCollector = function() use ($routeCollector, $path) {
146
            $r = $routeCollector;
147
            include $path;
148
            return $r;
149
        };
150
151
        $routeCollector = $getRouteCollector();
152
        if(!($routeCollector instanceof \FastRoute\RouteCollector)) {
0 ignored issues
show
Bug introduced by
The class FastRoute\RouteCollector does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
153
            throw new \Exception('Invalid return value from '
154
                . pathinfo($path, PATHINFO_FILENAME)
155
                . ' expected instance of RouteCollector'
156
            );
157
        }
158
159
        $dispatcher = new \FastRoute\Dispatcher\GroupCountBased($routeCollector->getData());
160
        $router = new \PPI\FastRoute\Wrapper\FastRouteWrapper(
161
            $dispatcher
162
        );
163
        $router->setModuleName($this->getName());
164
165
        return $router;
166
    }
167
168
    /**
169
     * @todo - move part of this into AuraRouterWrapper->load()
170
     * @todo - consider adding a setModuleName() to the AuraRouterWrapper instead of _module to each route.
171
     * @param string $path
172
     * @return AuraRouter
173
     * @throws \Exception when the included routes file doesn't return an AuraRouter back
174
     */
175
    protected function loadAuraRoutes($path)
176
    {
177
178
        if(!is_readable($path)) {
179
            throw new \InvalidArgumentException('Invalid aura routes path found: ' . $path);
180
        }
181
182
        $router = (new AuraRouterFactory())->newInstance();
183
184
        // The included file must return the aura router
185
        $router = include $path;
186
187 View Code Duplication
        if(!($router instanceof AuraRouter)) {
0 ignored issues
show
Bug introduced by
The class Aura\Router\Router does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
188
            throw new \Exception('Invalid return value from '
189
                . pathinfo($path, PATHINFO_FILENAME)
190
                . ' expected instance of AuraRouter'
191
            );
192
        }
193
194
        foreach($router->getRoutes() as $route) {
195
            $route->addValues(array('_module' => $this->getName()));
196
        }
197
198
        return $router;
199
    }
200
201
    /**
202
     * Load up our config results from the specific yaml file.
203
     *
204
     * @param string $path
205
     *
206
     * @return array
207
     *
208
     * @deprecated since version 2.1, to be removed in 2.2. Use "loadConfig()" instead.
209
     */
210
    protected function loadYamlConfig($path)
211
    {
212
        return $this->loadConfig($path);
213
    }
214
215
    /**
216
     * Set services for our module.
217
     *
218
     * @param string $services
219
     *
220
     * @return Module
221
     */
222
    public function setServices($services)
223
    {
224
        $this->services = $services;
0 ignored issues
show
Documentation Bug introduced by
It seems like $services of type string is incompatible with the declared type null of property $services.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
225
226
        return $this;
227
    }
228
229
    /**
230
     * Get the services.
231
     *
232
     * @return array
233
     */
234
    public function getServices()
235
    {
236
        return $this->services;
237
    }
238
239
    /**
240
     * Get a particular service.
241
     *
242
     * @param string $serviceName
243
     *
244
     * @return mixed
245
     */
246
    public function getService($serviceName)
247
    {
248
        return isset($this->services[$serviceName]) ? $this->services : null;
249
    }
250
251
    /**
252
     * Loads a configuration file (PHP, YAML) or PHP array.
253
     *
254
     * @param string      $resource The resource
255
     * @param null|string $type     The resource type
256
     *
257
     * @return array
258
     */
259
    public function loadConfig($resource, $type = null)
260
    {
261
        return $this->getConfigLoader()->load($resource, $type);
262
    }
263
264
    /**
265
     * Loads and merges the configuration.
266
     *
267
     * @param mixed $resources
268
     *
269
     * @return array
270
     */
271
    public function mergeConfig($resources)
272
    {
273
        $configs = array();
274
        foreach (is_array($resources) ? $resources : func_get_args() as $resource) {
275
            $configs = ArrayUtils::merge($configs, $this->loadConfig($resource));
276
        }
277
278
        return $configs;
279
    }
280
281
    /**
282
     * Set the module name.
283
     *
284
     * @param string $Name
285
     *
286
     * @return $this
287
     */
288
    public function setName($Name)
289
    {
290
        $this->name = $Name;
291
292
        return $this;
293
    }
294
295
    /**
296
     * Returns the module name. Defaults to the module namespace stripped of backslashes.
297
     *
298
     * @return string The Module name
299
     */
300
    public function getName()
301
    {
302
        if (null !== $this->name) {
303
            return $this->name;
304
        }
305
306
        $this->name = str_replace('\\', '', $this->getNamespace());
307
308
        return $this->name;
309
    }
310
311
    /**
312
     * Gets the Module namespace.
313
     *
314
     * @return string The Module namespace
315
     *
316
     * @api
317
     */
318
    public function getNamespace()
319
    {
320
        if (null === $this->reflected) {
321
            $this->reflected = new \ReflectionObject($this);
322
        }
323
324
        return $this->reflected->getNamespaceName();
325
    }
326
327
    /**
328
     * Gets the Module directory path.
329
     *
330
     * @return string The Module absolute path
331
     *
332
     * @api
333
     */
334
    public function getPath()
335
    {
336
        if (null === $this->reflected) {
337
            $this->reflected = new \ReflectionObject($this);
338
        }
339
340
        return dirname($this->reflected->getFileName());
341
    }
342
343
    /**
344
     * Returns configuration to merge with application configuration.
345
     *
346
     * @return array|\Traversable
347
     */
348
    public function getConfig()
349
    {
350
        return array();
351
    }
352
353
    /**
354
     * Finds and registers Commands.
355
     *
356
     * Override this method if your module commands do not follow the conventions:
357
     *
358
     * * Commands are in the 'Command' sub-directory
359
     * * Commands extend PPI\Framework\Console\Command\AbstractCommand
360
     *
361
     * @param Application $application An Application instance
362
     */
363
    public function registerCommands(Application $application)
364
    {
365
        if (!is_dir($dir = $this->getPath() . '/Command')) {
366
            return;
367
        }
368
369
        $finder = new Finder();
370
        $finder->files()->name('*Command.php')->in($dir);
371
372
        $prefix = $this->getNamespace() . '\\Command';
373
        foreach ($finder as $file) {
374
            $ns = $prefix;
375
            if ($relativePath = $file->getRelativePath()) {
376
                $ns .= '\\' . strtr($relativePath, '/', '\\');
377
            }
378
            $r = new \ReflectionClass($ns . '\\' . $file->getBasename('.php'));
379
            if ($r->isSubclassOf('PPI\Framework\\Console\\Command\\AbstractCommand') && !$r->isAbstract()) {
380
                $application->add($r->newInstance());
381
            }
382
        }
383
    }
384
385
    /**
386
     * Returns a ConfigLoader instance.
387
     *
388
     * @return \PPI\Framework\Config\ConfigLoader
389
     */
390
    protected function getConfigLoader()
391
    {
392
        if (null === $this->configLoader) {
393
            $this->configLoader = new ConfigLoader($this->getPath() . '/resources/config');
394
        }
395
396
        return $this->configLoader;
397
    }
398
399
}
400