Completed
Push — master ( d8ea60...50356d )
by Nicolas
12s
created

Repository::findByAlias()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 3.072

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 10
ccs 4
cts 5
cp 0.8
rs 9.4285
cc 3
eloc 5
nc 3
nop 1
crap 3.072
1
<?php
2
3
namespace Nwidart\Modules;
4
5
use Countable;
6
use Illuminate\Container\Container;
7
use Illuminate\Support\Str;
8
use Illuminate\Support\Traits\Macroable;
9
use Nwidart\Modules\Contracts\RepositoryInterface;
10
use Nwidart\Modules\Exceptions\InvalidAssetPath;
11
use Nwidart\Modules\Exceptions\ModuleNotFoundException;
12
use Nwidart\Modules\Process\Installer;
13
use Nwidart\Modules\Process\Updater;
14
15
abstract class Repository implements RepositoryInterface, Countable
16
{
17
    use Macroable;
18
19
    /**
20
     * Application instance.
21
     *
22
     * @var Illuminate\Contracts\Foundation\Application|Laravel\Lumen\Application
23
     */
24
    protected $app;
25
26
    /**
27
     * The module path.
28
     *
29
     * @var string|null
30
     */
31
    protected $path;
32
33
    /**
34
     * The scanned paths.
35
     *
36
     * @var array
37
     */
38
    protected $paths = [];
39
40
    /**
41
     * @var string
42
     */
43
    protected $stubPath;
44
45
    /**
46
     * The constructor.
47
     *
48
     * @param Container $app
49
     * @param string|null $path
50
     */
51 177
    public function __construct(Container $app, $path = null)
52
    {
53 177
        $this->app = $app;
0 ignored issues
show
Documentation Bug introduced by
It seems like $app of type object<Illuminate\Container\Container> is incompatible with the declared type object<Nwidart\Modules\I...avel\Lumen\Application> of property $app.

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...
54 177
        $this->path = $path;
55 177
    }
56
57
    /**
58
     * Add other module location.
59
     *
60
     * @param string $path
61
     *
62
     * @return $this
63
     */
64 15
    public function addLocation($path)
65
    {
66 15
        $this->paths[] = $path;
67
68 15
        return $this;
69
    }
70
71
    /**
72
     * Alternative method for "addPath".
73
     *
74
     * @param string $path
75
     *
76
     * @return $this
77
     * @deprecated
78
     */
79 1
    public function addPath($path)
80
    {
81 1
        return $this->addLocation($path);
82
    }
83
84
    /**
85
     * Get all additional paths.
86
     *
87
     * @return array
88
     */
89 1
    public function getPaths() : array
90
    {
91 1
        return $this->paths;
92
    }
93
94
    /**
95
     * Get scanned modules paths.
96
     *
97
     * @return array
98
     */
99 177
    public function getScanPaths() : array
100
    {
101 177
        $paths = $this->paths;
102
103 177
        $paths[] = $this->getPath();
104
105 177
        if ($this->config('scan.enabled')) {
106
            $paths = array_merge($paths, $this->config('scan.paths'));
107
        }
108 177
        $paths = array_map(function ($path) {
109 177
            return str_finish($path, '/*');
110 177
        }, $paths);
111
112 177
        return $paths;
113
    }
114
115
    /**
116
     * Creates a new Module instance
117
     * 
118
     * @param Container $app
0 ignored issues
show
Bug introduced by
There is no parameter named $app. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
119
     * @param $name
120
     * @param $path
121
     * @return \Nwidart\Modules\Module
122
     */
123
    abstract protected function createModule(...$args);
124
125
    /**
126
     * Get & scan all modules.
127
     *
128
     * @return array
129
     */
130 177
    public function scan()
131
    {
132 177
        $paths = $this->getScanPaths();
133
134 177
        $modules = [];
135
136 177
        foreach ($paths as $key => $path) {
137 177
            $manifests = $this->app['files']->glob("{$path}/module.json");
138
139 177
            is_array($manifests) || $manifests = [];
140
141 177
            foreach ($manifests as $manifest) {
142 104
                $name = Json::make($manifest)->get('name');
143
144 177
                $modules[$name] = $this->createModule($this->app, $name, dirname($manifest));
145
            }
146
        }
147
148 177
        return $modules;
149
    }
150
151
    /**
152
     * Get all modules.
153
     *
154
     * @return array
155
     */
156 177
    public function all() : array
157
    {
158 177
        if (!$this->config('cache.enabled')) {
159 177
            return $this->scan();
160
        }
161
162
        return $this->formatCached($this->getCached());
163
    }
164
165
    /**
166
     * Format the cached data as array of modules.
167
     *
168
     * @param array $cached
169
     *
170
     * @return array
171
     */
172
    protected function formatCached($cached)
173
    {
174
        $modules = [];
175
176
        foreach ($cached as $name => $module) {
177
            $path = $module["path"];
178
179
            $modules[$name] = $this->createModule($this->app, $name, $path);
180
        }
181
182
        return $modules;
183
    }
184
185
    /**
186
     * Get cached modules.
187
     *
188
     * @return array
189
     */
190
    public function getCached()
191
    {
192
        return $this->app['cache']->remember($this->config('cache.key'), $this->config('cache.lifetime'), function () {
193
            return $this->toCollection()->toArray();
194
        });
195
    }
196
197
    /**
198
     * Get all modules as collection instance.
199
     *
200
     * @return Collection
201
     */
202 1
    public function toCollection() : Collection
203
    {
204 1
        return new Collection($this->scan());
205
    }
206
207
    /**
208
     * Get modules by status.
209
     *
210
     * @param $status
211
     *
212
     * @return array
213
     */
214 177
    public function getByStatus($status) : array
215
    {
216 177
        $modules = [];
217
218 177
        foreach ($this->all() as $name => $module) {
219 3
            if ($module->isStatus($status)) {
220 3
                $modules[$name] = $module;
221
            }
222
        }
223
224 177
        return $modules;
225
    }
226
227
    /**
228
     * Determine whether the given module exist.
229
     *
230
     * @param $name
231
     *
232
     * @return bool
233
     */
234 91
    public function has($name) : bool
235
    {
236 91
        return array_key_exists($name, $this->all());
237
    }
238
239
    /**
240
     * Get list of enabled modules.
241
     *
242
     * @return array
243
     */
244 177
    public function enabled() : array
245
    {
246 177
        return $this->getByStatus(1);
247
    }
248
249
    /**
250
     * Get list of disabled modules.
251
     *
252
     * @return array
253
     */
254 1
    public function disabled() : array
255
    {
256 1
        return $this->getByStatus(0);
257
    }
258
259
    /**
260
     * Get count from all modules.
261
     *
262
     * @return int
263
     */
264 1
    public function count() : int
265
    {
266 1
        return count($this->all());
267
    }
268
269
    /**
270
     * Get all ordered modules.
271
     *
272
     * @param string $direction
273
     *
274
     * @return array
275
     */
276 177
    public function getOrdered($direction = 'asc') : array
277
    {
278 177
        $modules = $this->enabled();
279
280 177
        uasort($modules, function (Module $a, Module $b) use ($direction) {
281
            if ($a->order == $b->order) {
0 ignored issues
show
Documentation introduced by
The property order does not exist on object<Nwidart\Modules\Module>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
282
                return 0;
283
            }
284
285
            if ($direction == 'desc') {
286
                return $a->order < $b->order ? 1 : -1;
0 ignored issues
show
Documentation introduced by
The property order does not exist on object<Nwidart\Modules\Module>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
287
            }
288
289
            return $a->order > $b->order ? 1 : -1;
0 ignored issues
show
Documentation introduced by
The property order does not exist on object<Nwidart\Modules\Module>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
290 177
        });
291
292 177
        return $modules;
293
    }
294
295
    /**
296
     * Get a module path.
297
     *
298
     * @return string
299
     */
300 177
    public function getPath() : string
301
    {
302 177
        return $this->path ?: $this->config('paths.modules', base_path('Modules'));
303
    }
304
305
    /**
306
     * Register the modules.
307
     */
308 177
    public function register()
309
    {
310 177
        foreach ($this->getOrdered() as $module) {
311
            $module->register();
312
        }
313 177
    }
314
315
    /**
316
     * Boot the modules.
317
     */
318 177
    public function boot()
319
    {
320 177
        foreach ($this->getOrdered() as $module) {
321
            $module->boot();
322
        }
323 177
    }
324
325
    /**
326
     * Find a specific module.
327
     * @param $name
328
     * @return mixed|void
329
     */
330 100
    public function find($name)
331
    {
332 100
        foreach ($this->all() as $module) {
333 99
            if ($module->getLowerName() === strtolower($name)) {
334 99
                return $module;
335
            }
336
        }
337
338 92
        return;
339
    }
340
341
    /**
342
     * Find a specific module by its alias.
343
     * @param $alias
344
     * @return mixed|void
345
     */
346 2
    public function findByAlias($alias)
347
    {
348 2
        foreach ($this->all() as $module) {
349 2
            if ($module->getAlias() === $alias) {
350 2
                return $module;
351
            }
352
        }
353
354
        return;
355
    }
356
357
    /**
358
     * Find all modules that are required by a module. If the module cannot be found, throw an exception.
359
     *
360
     * @param $name
361
     * @return array
362
     * @throws ModuleNotFoundException
363
     */
364 1
    public function findRequirements($name)
365
    {
366 1
        $requirements = [];
367
368 1
        $module = $this->findOrFail($name);
369
370 1
        foreach ($module->getRequires() as $requirementName) {
371 1
            $requirements[] = $this->findByAlias($requirementName);
372
        }
373
374 1
        return $requirements;
375
    }
376
377
    /**
378
     * Alternative for "find" method.
379
     * @param $name
380
     * @return mixed|void
381
     * @deprecated
382
     */
383 1
    public function get($name)
384
    {
385 1
        return $this->find($name);
386
    }
387
388
    /**
389
     * Find a specific module, if there return that, otherwise throw exception.
390
     *
391
     * @param $name
392
     *
393
     * @return Module
394
     *
395
     * @throws ModuleNotFoundException
396
     */
397 98
    public function findOrFail($name)
398
    {
399 98
        $module = $this->find($name);
400
401 98
        if ($module !== null) {
402 97
            return $module;
403
        }
404
405 92
        throw new ModuleNotFoundException("Module [{$name}] does not exist!");
406
    }
407
408
    /**
409
     * Get all modules as laravel collection instance.
410
     *
411
     * @param $status
412
     *
413
     * @return Collection
414
     */
415 1
    public function collections($status = 1) : Collection
416
    {
417 1
        return new Collection($this->getByStatus($status));
418
    }
419
420
    /**
421
     * Get module path for a specific module.
422
     *
423
     * @param $module
424
     *
425
     * @return string
426
     */
427 91
    public function getModulePath($module)
428
    {
429
        try {
430 91
            return $this->findOrFail($module)->getPath() . '/';
431 91
        } catch (ModuleNotFoundException $e) {
432 91
            return $this->getPath() . '/' . Str::studly($module) . '/';
433
        }
434
    }
435
436
    /**
437
     * Get asset path for a specific module.
438
     *
439
     * @param $module
440
     *
441
     * @return string
442
     */
443 2
    public function assetPath($module) : string
444
    {
445 2
        return $this->config('paths.assets') . '/' . $module;
446
    }
447
448
    /**
449
     * Get a specific config data from a configuration file.
450
     *
451
     * @param $key
452
     *
453
     * @param null $default
454
     * @return mixed
455
     */
456 177
    public function config($key, $default = null)
457
    {
458 177
        return $this->app['config']->get('modules.' . $key, $default);
459
    }
460
461
    /**
462
     * Get storage path for module used.
463
     *
464
     * @return string
465
     */
466 2
    public function getUsedStoragePath() : string
467
    {
468 2
        $directory = storage_path('app/modules');
469 2
        if ($this->app['files']->exists($directory) === false) {
470 1
            $this->app['files']->makeDirectory($directory, 0777, true);
471
        }
472
473 2
        $path = storage_path('app/modules/modules.used');
474 2
        if (!$this->app['files']->exists($path)) {
475 1
            $this->app['files']->put($path, '');
476
        }
477
478 2
        return $path;
479
    }
480
481
    /**
482
     * Set module used for cli session.
483
     *
484
     * @param $name
485
     *
486
     * @throws ModuleNotFoundException
487
     */
488 1
    public function setUsed($name)
489
    {
490 1
        $module = $this->findOrFail($name);
491
492 1
        $this->app['files']->put($this->getUsedStoragePath(), $module);
493 1
    }
494
495
    /**
496
     * Forget the module used for cli session.
497
     */
498
    public function forgetUsed()
499
    {
500
        if ($this->app['files']->exists($this->getUsedStoragePath())) {
501
            $this->app['files']->delete($this->getUsedStoragePath());
502
        }
503
    }
504
505
    /**
506
     * Get module used for cli session.
507
     * @return string
508
     * @throws \Nwidart\Modules\Exceptions\ModuleNotFoundException
509
     */
510 1
    public function getUsedNow() : string
511
    {
512 1
        return $this->findOrFail($this->app['files']->get($this->getUsedStoragePath()));
513
    }
514
515
    /**
516
     * Get used now.
517
     *
518
     * @return string
519
     * @deprecated
520
     */
521 1
    public function getUsed()
522
    {
523 1
        return $this->getUsedNow();
524
    }
525
526
    /**
527
     * Get laravel filesystem instance.
528
     *
529
     * @return \Illuminate\Filesystem\Filesystem
530
     */
531 4
    public function getFiles()
532
    {
533 4
        return $this->app['files'];
534
    }
535
536
    /**
537
     * Get module assets path.
538
     *
539
     * @return string
540
     */
541 2
    public function getAssetsPath() : string
542
    {
543 2
        return $this->config('paths.assets');
544
    }
545
546
    /**
547
     * Get asset url from a specific module.
548
     * @param string $asset
549
     * @return string
550
     * @throws InvalidAssetPath
551
     */
552 2
    public function asset($asset) : string
553
    {
554 2
        if (str_contains($asset, ':') === false) {
555 1
            throw InvalidAssetPath::missingModuleName($asset);
556
        }
557 1
        list($name, $url) = explode(':', $asset);
558
559 1
        $baseUrl = str_replace(public_path() . DIRECTORY_SEPARATOR, '', $this->getAssetsPath());
560
561 1
        $url = $this->app['url']->asset($baseUrl . "/{$name}/" . $url);
562
563 1
        return str_replace(['http://', 'https://'], '//', $url);
564
    }
565
566
    /**
567
     * Determine whether the given module is activated.
568
     *
569
     * @param string $name
570
     *
571
     * @return bool
572
     */
573 4
    public function active($name) : bool
574
    {
575 4
        return $this->findOrFail($name)->active();
0 ignored issues
show
Deprecated Code introduced by
The method Nwidart\Modules\Module::active() has been deprecated.

This method has been deprecated.

Loading history...
576
    }
577
578
    /**
579
     * Determine whether the given module is not activated.
580
     *
581
     * @param string $name
582
     *
583
     * @return bool
584
     */
585 2
    public function notActive($name) : bool
586
    {
587 2
        return !$this->active($name);
588
    }
589
590
    /**
591
     * Enabling a specific module.
592
     * @param string $name
593
     * @return void
594
     * @throws \Nwidart\Modules\Exceptions\ModuleNotFoundException
595
     */
596 1
    public function enable($name)
597
    {
598 1
        $this->findOrFail($name)->enable();
599 1
    }
600
601
    /**
602
     * Disabling a specific module.
603
     * @param string $name
604
     * @return void
605
     * @throws \Nwidart\Modules\Exceptions\ModuleNotFoundException
606
     */
607 1
    public function disable($name)
608
    {
609 1
        $this->findOrFail($name)->disable();
610 1
    }
611
612
    /**
613
     * Delete a specific module.
614
     * @param string $name
615
     * @return bool
616
     * @throws \Nwidart\Modules\Exceptions\ModuleNotFoundException
617
     */
618 2
    public function delete($name) : bool
619
    {
620 2
        return $this->findOrFail($name)->delete();
621
    }
622
623
    /**
624
     * Update dependencies for the specified module.
625
     *
626
     * @param string $module
627
     */
628
    public function update($module)
629
    {
630
        with(new Updater($this))->update($module);
631
    }
632
633
    /**
634
     * Install the specified module.
635
     *
636
     * @param string $name
637
     * @param string $version
638
     * @param string $type
639
     * @param bool   $subtree
640
     *
641
     * @return \Symfony\Component\Process\Process
642
     */
643
    public function install($name, $version = 'dev-master', $type = 'composer', $subtree = false)
644
    {
645
        $installer = new Installer($name, $version, $type, $subtree);
646
647
        return $installer->run();
648
    }
649
650
    /**
651
     * Get stub path.
652
     *
653
     * @return string|null
654
     */
655 3
    public function getStubPath()
656
    {
657 3
        if ($this->stubPath !== null) {
658 1
            return $this->stubPath;
659
        }
660
661 2
        if ($this->config('stubs.enabled') === true) {
662 1
            return $this->config('stubs.path');
663
        }
664
665 1
        return $this->stubPath;
666
    }
667
668
    /**
669
     * Set stub path.
670
     *
671
     * @param string $stubPath
672
     *
673
     * @return $this
674
     */
675 1
    public function setStubPath($stubPath)
676
    {
677 1
        $this->stubPath = $stubPath;
678
679 1
        return $this;
680
    }
681
}
682