Completed
Push — master ( 30c147...23aec3 )
by Nicolas
11:23
created

Repository::allDisabled()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
ccs 2
cts 2
cp 1
crap 1
rs 10
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 179
    public function __construct(Container $app, $path = null)
52
    {
53 179
        $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 179
        $this->path = $path;
55 179
    }
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 179
    public function getScanPaths() : array
100
    {
101 179
        $paths = $this->paths;
102
103 179
        $paths[] = $this->getPath();
104
105 179
        if ($this->config('scan.enabled')) {
106
            $paths = array_merge($paths, $this->config('scan.paths'));
107
        }
108
109 179
        $paths = array_map(function ($path) {
110 179
            return ends_with($path, '/*') ? $path : str_finish($path, '/*');
111 179
        }, $paths);
112
113 179
        return $paths;
114
    }
115
116
    /**
117
     * Creates a new Module instance
118
     *
119
     * @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...
120
     * @param $name
121
     * @param $path
122
     * @return \Nwidart\Modules\Module
123
     */
124
    abstract protected function createModule(...$args);
125
126
    /**
127
     * Get & scan all modules.
128
     *
129
     * @return array
130
     */
131 179
    public function scan()
132
    {
133 179
        $paths = $this->getScanPaths();
134
135 179
        $modules = [];
136
137 179
        foreach ($paths as $key => $path) {
138 179
            $manifests = $this->app['files']->glob("{$path}/module.json");
139
140 179
            is_array($manifests) || $manifests = [];
141
142 179
            foreach ($manifests as $manifest) {
143 104
                $name = Json::make($manifest)->get('name');
144
145 179
                $modules[$name] = $this->createModule($this->app, $name, dirname($manifest));
146
            }
147
        }
148
149 179
        return $modules;
150
    }
151
152
    /**
153
     * Get all modules.
154
     *
155
     * @return array
156
     */
157 179
    public function all() : array
158
    {
159 179
        if (!$this->config('cache.enabled')) {
160 179
            return $this->scan();
161
        }
162
163
        return $this->formatCached($this->getCached());
164
    }
165
166
    /**
167
     * Format the cached data as array of modules.
168
     *
169
     * @param array $cached
170
     *
171
     * @return array
172
     */
173
    protected function formatCached($cached)
174
    {
175
        $modules = [];
176
177
        foreach ($cached as $name => $module) {
178
            $path = $module["path"];
179
180
            $modules[$name] = $this->createModule($this->app, $name, $path);
181
        }
182
183
        return $modules;
184
    }
185
186
    /**
187
     * Get cached modules.
188
     *
189
     * @return array
190
     */
191
    public function getCached()
192
    {
193
        return $this->app['cache']->remember($this->config('cache.key'), $this->config('cache.lifetime'), function () {
194
            return $this->toCollection()->toArray();
195
        });
196
    }
197
198
    /**
199
     * Get all modules as collection instance.
200
     *
201
     * @return Collection
202
     */
203 1
    public function toCollection() : Collection
204
    {
205 1
        return new Collection($this->scan());
206
    }
207
208
    /**
209
     * Get modules by status.
210
     *
211
     * @param $status
212
     *
213
     * @return array
214
     */
215 179
    public function getByStatus($status) : array
216
    {
217 179
        $modules = [];
218
219 179
        foreach ($this->all() as $name => $module) {
220 3
            if ($module->isStatus($status)) {
221 3
                $modules[$name] = $module;
222
            }
223
        }
224
225 179
        return $modules;
226
    }
227
228
    /**
229
     * Determine whether the given module exist.
230
     *
231
     * @param $name
232
     *
233
     * @return bool
234
     */
235 91
    public function has($name) : bool
236
    {
237 91
        return array_key_exists($name, $this->all());
238
    }
239
240
    /**
241
     * Get list of enabled modules.
242
     *
243
     * @return array
244
     */
245 179
    public function allEnabled() : array
246
    {
247 179
        return $this->getByStatus(1);
248
    }
249
250
    /**
251
     * Get list of disabled modules.
252
     *
253
     * @return array
254
     */
255 1
    public function allDisabled() : array
256
    {
257 1
        return $this->getByStatus(0);
258
    }
259
260
    /**
261
     * Get count from all modules.
262
     *
263
     * @return int
264
     */
265 1
    public function count() : int
266
    {
267 1
        return count($this->all());
268
    }
269
270
    /**
271
     * Get all ordered modules.
272
     *
273
     * @param string $direction
274
     *
275
     * @return array
276
     */
277 179
    public function getOrdered($direction = 'asc') : array
278
    {
279 179
        $modules = $this->allEnabled();
280
281 179
        uasort($modules, function (Module $a, Module $b) use ($direction) {
282
            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...
283
                return 0;
284
            }
285
286
            if ($direction == 'desc') {
287
                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...
288
            }
289
290
            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...
291 179
        });
292
293 179
        return $modules;
294
    }
295
296
    /**
297
     * Get a module path.
298
     *
299
     * @return string
300
     */
301 179
    public function getPath() : string
302
    {
303 179
        return $this->path ?: $this->config('paths.modules', base_path('Modules'));
304
    }
305
306
    /**
307
     * Register the modules.
308
     */
309 179
    public function register()
310
    {
311 179
        foreach ($this->getOrdered() as $module) {
312
            $module->register();
313
        }
314 179
    }
315
316
    /**
317
     * Boot the modules.
318
     */
319 179
    public function boot()
320
    {
321 179
        foreach ($this->getOrdered() as $module) {
322
            $module->boot();
323
        }
324 179
    }
325
326
    /**
327
     * Find a specific module.
328
     * @param $name
329
     * @return mixed|void
330
     */
331 100
    public function find($name)
332
    {
333 100
        foreach ($this->all() as $module) {
334 99
            if ($module->getLowerName() === strtolower($name)) {
335 99
                return $module;
336
            }
337
        }
338
339 92
        return;
340
    }
341
342
    /**
343
     * Find a specific module by its alias.
344
     * @param $alias
345
     * @return mixed|void
346
     */
347 2
    public function findByAlias($alias)
348
    {
349 2
        foreach ($this->all() as $module) {
350 2
            if ($module->getAlias() === $alias) {
351 2
                return $module;
352
            }
353
        }
354
355
        return;
356
    }
357
358
    /**
359
     * Find all modules that are required by a module. If the module cannot be found, throw an exception.
360
     *
361
     * @param $name
362
     * @return array
363
     * @throws ModuleNotFoundException
364
     */
365 1
    public function findRequirements($name)
366
    {
367 1
        $requirements = [];
368
369 1
        $module = $this->findOrFail($name);
370
371 1
        foreach ($module->getRequires() as $requirementName) {
372 1
            $requirements[] = $this->findByAlias($requirementName);
373
        }
374
375 1
        return $requirements;
376
    }
377
378
    /**
379
     * Alternative for "find" method.
380
     * @param $name
381
     * @return mixed|void
382
     * @deprecated
383
     */
384 1
    public function get($name)
385
    {
386 1
        return $this->find($name);
387
    }
388
389
    /**
390
     * Find a specific module, if there return that, otherwise throw exception.
391
     *
392
     * @param $name
393
     *
394
     * @return Module
395
     *
396
     * @throws ModuleNotFoundException
397
     */
398 98
    public function findOrFail($name)
399
    {
400 98
        $module = $this->find($name);
401
402 98
        if ($module !== null) {
403 97
            return $module;
404
        }
405
406 92
        throw new ModuleNotFoundException("Module [{$name}] does not exist!");
407
    }
408
409
    /**
410
     * Get all modules as laravel collection instance.
411
     *
412
     * @param $status
413
     *
414
     * @return Collection
415
     */
416 1
    public function collections($status = 1) : Collection
417
    {
418 1
        return new Collection($this->getByStatus($status));
419
    }
420
421
    /**
422
     * Get module path for a specific module.
423
     *
424
     * @param $module
425
     *
426
     * @return string
427
     */
428 91
    public function getModulePath($module)
429
    {
430
        try {
431 91
            return $this->findOrFail($module)->getPath() . '/';
432 91
        } catch (ModuleNotFoundException $e) {
433 91
            return $this->getPath() . '/' . Str::studly($module) . '/';
434
        }
435
    }
436
437
    /**
438
     * Get asset path for a specific module.
439
     *
440
     * @param $module
441
     *
442
     * @return string
443
     */
444 2
    public function assetPath($module) : string
445
    {
446 2
        return $this->config('paths.assets') . '/' . $module;
447
    }
448
449
    /**
450
     * Get a specific config data from a configuration file.
451
     *
452
     * @param $key
453
     *
454
     * @param null $default
455
     * @return mixed
456
     */
457 179
    public function config($key, $default = null)
458
    {
459 179
        return $this->app['config']->get('modules.' . $key, $default);
460
    }
461
462
    /**
463
     * Get storage path for module used.
464
     *
465
     * @return string
466
     */
467 2
    public function getUsedStoragePath() : string
468
    {
469 2
        $directory = storage_path('app/modules');
470 2
        if ($this->app['files']->exists($directory) === false) {
471 1
            $this->app['files']->makeDirectory($directory, 0777, true);
472
        }
473
474 2
        $path = storage_path('app/modules/modules.used');
475 2
        if (!$this->app['files']->exists($path)) {
476 1
            $this->app['files']->put($path, '');
477
        }
478
479 2
        return $path;
480
    }
481
482
    /**
483
     * Set module used for cli session.
484
     *
485
     * @param $name
486
     *
487
     * @throws ModuleNotFoundException
488
     */
489 1
    public function setUsed($name)
490
    {
491 1
        $module = $this->findOrFail($name);
492
493 1
        $this->app['files']->put($this->getUsedStoragePath(), $module);
494 1
    }
495
496
    /**
497
     * Forget the module used for cli session.
498
     */
499
    public function forgetUsed()
500
    {
501
        if ($this->app['files']->exists($this->getUsedStoragePath())) {
502
            $this->app['files']->delete($this->getUsedStoragePath());
503
        }
504
    }
505
506
    /**
507
     * Get module used for cli session.
508
     * @return string
509
     * @throws \Nwidart\Modules\Exceptions\ModuleNotFoundException
510
     */
511 1
    public function getUsedNow() : string
512
    {
513 1
        return $this->findOrFail($this->app['files']->get($this->getUsedStoragePath()));
514
    }
515
516
    /**
517
     * Get used now.
518
     *
519
     * @return string
520
     * @deprecated
521
     */
522 1
    public function getUsed()
523
    {
524 1
        return $this->getUsedNow();
525
    }
526
527
    /**
528
     * Get laravel filesystem instance.
529
     *
530
     * @return \Illuminate\Filesystem\Filesystem
531
     */
532 4
    public function getFiles()
533
    {
534 4
        return $this->app['files'];
535
    }
536
537
    /**
538
     * Get module assets path.
539
     *
540
     * @return string
541
     */
542 2
    public function getAssetsPath() : string
543
    {
544 2
        return $this->config('paths.assets');
545
    }
546
547
    /**
548
     * Get asset url from a specific module.
549
     * @param string $asset
550
     * @return string
551
     * @throws InvalidAssetPath
552
     */
553 2
    public function asset($asset) : string
554
    {
555 2
        if (str_contains($asset, ':') === false) {
556 1
            throw InvalidAssetPath::missingModuleName($asset);
557
        }
558 1
        list($name, $url) = explode(':', $asset);
559
560 1
        $baseUrl = str_replace(public_path() . DIRECTORY_SEPARATOR, '', $this->getAssetsPath());
561
562 1
        $url = $this->app['url']->asset($baseUrl . "/{$name}/" . $url);
563
564 1
        return str_replace(['http://', 'https://'], '//', $url);
565
    }
566
567
    /**
568
     * Determine whether the given module is activated.
569
     * @param string $name
570
     * @return bool
571
     * @throws ModuleNotFoundException
572
     */
573 4
    public function enabled($name) : bool
574
    {
575 4
        return $this->findOrFail($name)->enabled();
576
    }
577
578
    /**
579
     * Determine whether the given module is not activated.
580
     * @param string $name
581
     * @return bool
582
     * @throws ModuleNotFoundException
583
     */
584 2
    public function disabled($name) : bool
585
    {
586 2
        return !$this->enabled($name);
587
    }
588
589
    /**
590
     * Enabling a specific module.
591
     * @param string $name
592
     * @return void
593
     * @throws \Nwidart\Modules\Exceptions\ModuleNotFoundException
594
     */
595 1
    public function enable($name)
596
    {
597 1
        $this->findOrFail($name)->enable();
598 1
    }
599
600
    /**
601
     * Disabling a specific module.
602
     * @param string $name
603
     * @return void
604
     * @throws \Nwidart\Modules\Exceptions\ModuleNotFoundException
605
     */
606 1
    public function disable($name)
607
    {
608 1
        $this->findOrFail($name)->disable();
609 1
    }
610
611
    /**
612
     * Delete a specific module.
613
     * @param string $name
614
     * @return bool
615
     * @throws \Nwidart\Modules\Exceptions\ModuleNotFoundException
616
     */
617 2
    public function delete($name) : bool
618
    {
619 2
        return $this->findOrFail($name)->delete();
620
    }
621
622
    /**
623
     * Update dependencies for the specified module.
624
     *
625
     * @param string $module
626
     */
627
    public function update($module)
628
    {
629
        with(new Updater($this))->update($module);
630
    }
631
632
    /**
633
     * Install the specified module.
634
     *
635
     * @param string $name
636
     * @param string $version
637
     * @param string $type
638
     * @param bool   $subtree
639
     *
640
     * @return \Symfony\Component\Process\Process
641
     */
642
    public function install($name, $version = 'dev-master', $type = 'composer', $subtree = false)
643
    {
644
        $installer = new Installer($name, $version, $type, $subtree);
645
646
        return $installer->run();
647
    }
648
649
    /**
650
     * Get stub path.
651
     *
652
     * @return string|null
653
     */
654 3
    public function getStubPath()
655
    {
656 3
        if ($this->stubPath !== null) {
657 1
            return $this->stubPath;
658
        }
659
660 2
        if ($this->config('stubs.enabled') === true) {
661 1
            return $this->config('stubs.path');
662
        }
663
664 1
        return $this->stubPath;
665
    }
666
667
    /**
668
     * Set stub path.
669
     *
670
     * @param string $stubPath
671
     *
672
     * @return $this
673
     */
674 1
    public function setStubPath($stubPath)
675
    {
676 1
        $this->stubPath = $stubPath;
677
678 1
        return $this;
679
    }
680
}
681