Completed
Push — master ( 4fafa1...e65f27 )
by Nicolas
12:12
created

src/FileRepository.php (2 issues)

Severity

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
namespace Nwidart\Modules;
4
5
use Countable;
6
use Illuminate\Cache\CacheManager;
7
use Illuminate\Container\Container;
8
use Illuminate\Contracts\Config\Repository as ConfigRepository;
9
use Illuminate\Contracts\Routing\UrlGenerator;
10
use Illuminate\Filesystem\Filesystem;
11
use Illuminate\Support\Str;
12
use Illuminate\Support\Traits\Macroable;
13
use Nwidart\Modules\Contracts\RepositoryInterface;
14
use Nwidart\Modules\Exceptions\InvalidAssetPath;
15
use Nwidart\Modules\Exceptions\ModuleNotFoundException;
16
use Nwidart\Modules\Process\Installer;
17
use Nwidart\Modules\Process\Updater;
18
19
abstract class FileRepository implements RepositoryInterface, Countable
20
{
21
    use Macroable;
22
23
    /**
24
     * Application instance.
25
     *
26
     * @var \Illuminate\Contracts\Foundation\Application|\Laravel\Lumen\Application
27
     */
28
    protected $app;
29
30
    /**
31
     * The module path.
32
     *
33
     * @var string|null
34
     */
35
    protected $path;
36
37
    /**
38
     * The scanned paths.
39
     *
40
     * @var array
41
     */
42
    protected $paths = [];
43
44
    /**
45
     * @var string
46
     */
47
    protected $stubPath;
48
    /**
49
     * @var UrlGenerator
50
     */
51
    private $url;
52
    /**
53
     * @var ConfigRepository
54
     */
55
    private $config;
56
    /**
57
     * @var Filesystem
58
     */
59
    private $files;
60
    /**
61
     * @var CacheManager
62
     */
63
    private $cache;
64
65
    /**
66
     * The constructor.
67
     * @param Container $app
68
     * @param string|null $path
69
     */
70 217
    public function __construct(Container $app, $path = null)
71
    {
72 217
        $this->app = $app;
73 217
        $this->path = $path;
74 217
        $this->url = $app['url'];
75 217
        $this->config = $app['config'];
76 217
        $this->files = $app['files'];
77 217
        $this->cache = $app['cache'];
78 217
    }
79
80
    /**
81
     * Add other module location.
82
     *
83
     * @param string $path
84
     *
85
     * @return $this
86
     */
87 15
    public function addLocation($path)
88
    {
89 15
        $this->paths[] = $path;
90
91 15
        return $this;
92
    }
93
94
    /**
95
     * Get all additional paths.
96
     *
97
     * @return array
98
     */
99 1
    public function getPaths() : array
100
    {
101 1
        return $this->paths;
102
    }
103
104
    /**
105
     * Get scanned modules paths.
106
     *
107
     * @return array
108
     */
109 217
    public function getScanPaths() : array
110
    {
111 217
        $paths = $this->paths;
112
113 217
        $paths[] = $this->getPath();
114
115 217
        if ($this->config('scan.enabled')) {
116
            $paths = array_merge($paths, $this->config('scan.paths'));
117
        }
118
119
        $paths = array_map(function ($path) {
120 217
            return Str::endsWith($path, '/*') ? $path : Str::finish($path, '/*');
121 217
        }, $paths);
122
123 217
        return $paths;
124
    }
125
126
    /**
127
     * Creates a new Module instance
128
     *
129
     * @param Container $app
130
     * @param string $args
131
     * @param string $path
132
     * @return \Nwidart\Modules\Module
133
     */
134
    abstract protected function createModule(...$args);
135
136
    /**
137
     * Get & scan all modules.
138
     *
139
     * @return array
140
     */
141 217
    public function scan()
142
    {
143 217
        $paths = $this->getScanPaths();
144
145 217
        $modules = [];
146
147 217
        foreach ($paths as $key => $path) {
148 217
            $manifests = $this->getFiles()->glob("{$path}/module.json");
149
150 217
            is_array($manifests) || $manifests = [];
151
152 217
            foreach ($manifests as $manifest) {
153 133
                $name = Json::make($manifest)->get('name');
154
155 133
                $modules[$name] = $this->createModule($this->app, $name, dirname($manifest));
156
            }
157
        }
158
159 217
        return $modules;
160
    }
161
162
    /**
163
     * Get all modules.
164
     *
165
     * @return array
166
     */
167 217
    public function all() : array
168
    {
169 217
        if (!$this->config('cache.enabled')) {
170 217
            return $this->scan();
171
        }
172
173
        return $this->formatCached($this->getCached());
174
    }
175
176
    /**
177
     * Format the cached data as array of modules.
178
     *
179
     * @param array $cached
180
     *
181
     * @return array
182
     */
183
    protected function formatCached($cached)
184
    {
185
        $modules = [];
186
187
        foreach ($cached as $name => $module) {
188
            $path = $module['path'];
189
190
            $modules[$name] = $this->createModule($this->app, $name, $path);
191
        }
192
193
        return $modules;
194
    }
195
196
    /**
197
     * Get cached modules.
198
     *
199
     * @return array
200
     */
201
    public function getCached()
202
    {
203
        return $this->cache->remember($this->config('cache.key'), $this->config('cache.lifetime'), function () {
204
            return $this->toCollection()->toArray();
205
        });
206
    }
207
208
    /**
209
     * Get all modules as collection instance.
210
     *
211
     * @return Collection
212
     */
213 1
    public function toCollection() : Collection
214
    {
215 1
        return new Collection($this->scan());
216
    }
217
218
    /**
219
     * Get modules by status.
220
     *
221
     * @param $status
222
     *
223
     * @return array
224
     */
225 217
    public function getByStatus($status) : array
226
    {
227 217
        $modules = [];
228
229
        /** @var Module $module */
230 217
        foreach ($this->all() as $name => $module) {
231 3
            if ($module->isStatus($status)) {
232 1
                $modules[$name] = $module;
233
            }
234
        }
235
236 217
        return $modules;
237
    }
238
239
    /**
240
     * Determine whether the given module exist.
241
     *
242
     * @param $name
243
     *
244
     * @return bool
245
     */
246 120
    public function has($name) : bool
247
    {
248 120
        return array_key_exists($name, $this->all());
249
    }
250
251
    /**
252
     * Get list of enabled modules.
253
     *
254
     * @return array
255
     */
256 217
    public function allEnabled() : array
257
    {
258 217
        return $this->getByStatus(true);
0 ignored issues
show
true is of type boolean, but the function expects a integer.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
259
    }
260
261
    /**
262
     * Get list of disabled modules.
263
     *
264
     * @return array
265
     */
266 1
    public function allDisabled() : array
267
    {
268 1
        return $this->getByStatus(false);
0 ignored issues
show
false is of type boolean, but the function expects a integer.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
269
    }
270
271
    /**
272
     * Get count from all modules.
273
     *
274
     * @return int
275
     */
276 1
    public function count() : int
277
    {
278 1
        return count($this->all());
279
    }
280
281
    /**
282
     * Get all ordered modules.
283
     *
284
     * @param string $direction
285
     *
286
     * @return array
287
     */
288 217
    public function getOrdered($direction = 'asc') : array
289
    {
290 217
        $modules = $this->allEnabled();
291
292
        uasort($modules, function (Module $a, Module $b) use ($direction) {
293
            if ($a->get('order') === $b->get('order')) {
294
                return 0;
295
            }
296
297
            if ($direction === 'desc') {
298
                return $a->get('order') < $b->get('order') ? 1 : -1;
299
            }
300
301
            return $a->get('order') > $b->get('order') ? 1 : -1;
302 217
        });
303
304 217
        return $modules;
305
    }
306
307
    /**
308
     * @inheritDoc
309
     */
310 217
    public function getPath() : string
311
    {
312 217
        return $this->path ?: $this->config('paths.modules', base_path('Modules'));
313
    }
314
315
    /**
316
     * @inheritDoc
317
     */
318 217
    public function register(): void
319
    {
320 217
        foreach ($this->getOrdered() as $module) {
321
            $module->register();
322
        }
323 217
    }
324
325
    /**
326
     * @inheritDoc
327
     */
328 217
    public function boot(): void
329
    {
330 217
        foreach ($this->getOrdered() as $module) {
331
            $module->boot();
332
        }
333 217
    }
334
335
    /**
336
     * @inheritDoc
337
     */
338 129
    public function find(string $name)
339
    {
340 129
        foreach ($this->all() as $module) {
341 128
            if ($module->getLowerName() === strtolower($name)) {
342 128
                return $module;
343
            }
344
        }
345
346 121
        return;
347
    }
348
349
    /**
350
     * @inheritDoc
351
     */
352 2
    public function findByAlias(string $alias)
353
    {
354 2
        foreach ($this->all() as $module) {
355 2
            if ($module->getAlias() === $alias) {
356 2
                return $module;
357
            }
358
        }
359
360
        return;
361
    }
362
363
    /**
364
     * @inheritDoc
365
     */
366 1
    public function findRequirements($name): array
367
    {
368 1
        $requirements = [];
369
370 1
        $module = $this->findOrFail($name);
371
372 1
        foreach ($module->getRequires() as $requirementName) {
373 1
            $requirements[] = $this->findByAlias($requirementName);
374
        }
375
376 1
        return $requirements;
377
    }
378
379
    /**
380
     * Find a specific module, if there return that, otherwise throw exception.
381
     *
382
     * @param $name
383
     *
384
     * @return Module
385
     *
386
     * @throws ModuleNotFoundException
387
     */
388 127
    public function findOrFail(string $name)
389
    {
390 127
        $module = $this->find($name);
391
392 127
        if ($module !== null) {
393 126
            return $module;
394
        }
395
396 121
        throw new ModuleNotFoundException("Module [{$name}] does not exist!");
397
    }
398
399
    /**
400
     * Get all modules as laravel collection instance.
401
     *
402
     * @param $status
403
     *
404
     * @return Collection
405
     */
406 1
    public function collections($status = 1) : Collection
407
    {
408 1
        return new Collection($this->getByStatus($status));
409
    }
410
411
    /**
412
     * Get module path for a specific module.
413
     *
414
     * @param $module
415
     *
416
     * @return string
417
     */
418 120
    public function getModulePath($module)
419
    {
420
        try {
421 120
            return $this->findOrFail($module)->getPath() . '/';
422 120
        } catch (ModuleNotFoundException $e) {
423 120
            return $this->getPath() . '/' . Str::studly($module) . '/';
424
        }
425
    }
426
427
    /**
428
     * @inheritDoc
429
     */
430 2
    public function assetPath(string $module) : string
431
    {
432 2
        return $this->config('paths.assets') . '/' . $module;
433
    }
434
435
    /**
436
     * @inheritDoc
437
     */
438 217
    public function config(string $key, $default = null)
439
    {
440 217
        return $this->config->get('modules.' . $key, $default);
441
    }
442
443
    /**
444
     * Get storage path for module used.
445
     *
446
     * @return string
447
     */
448 2
    public function getUsedStoragePath() : string
449
    {
450 2
        $directory = storage_path('app/modules');
451 2
        if ($this->getFiles()->exists($directory) === false) {
452 1
            $this->getFiles()->makeDirectory($directory, 0777, true);
453
        }
454
455 2
        $path = storage_path('app/modules/modules.used');
456 2
        if (!$this->getFiles()->exists($path)) {
457 1
            $this->getFiles()->put($path, '');
458
        }
459
460 2
        return $path;
461
    }
462
463
    /**
464
     * Set module used for cli session.
465
     *
466
     * @param $name
467
     *
468
     * @throws ModuleNotFoundException
469
     */
470 1
    public function setUsed($name)
471
    {
472 1
        $module = $this->findOrFail($name);
473
474 1
        $this->getFiles()->put($this->getUsedStoragePath(), $module);
475 1
    }
476
477
    /**
478
     * Forget the module used for cli session.
479
     */
480
    public function forgetUsed()
481
    {
482
        if ($this->getFiles()->exists($this->getUsedStoragePath())) {
483
            $this->getFiles()->delete($this->getUsedStoragePath());
484
        }
485
    }
486
487
    /**
488
     * Get module used for cli session.
489
     * @return string
490
     * @throws \Nwidart\Modules\Exceptions\ModuleNotFoundException
491
     */
492 1
    public function getUsedNow() : string
493
    {
494 1
        return $this->findOrFail($this->getFiles()->get($this->getUsedStoragePath()));
495
    }
496
497
    /**
498
     * Get laravel filesystem instance.
499
     *
500
     * @return Filesystem
501
     */
502 217
    public function getFiles(): Filesystem
503
    {
504 217
        return $this->files;
505
    }
506
507
    /**
508
     * Get module assets path.
509
     *
510
     * @return string
511
     */
512 2
    public function getAssetsPath() : string
513
    {
514 2
        return $this->config('paths.assets');
515
    }
516
517
    /**
518
     * Get asset url from a specific module.
519
     * @param string $asset
520
     * @return string
521
     * @throws InvalidAssetPath
522
     */
523 2
    public function asset($asset) : string
524
    {
525 2
        if (Str::contains($asset, ':') === false) {
526 1
            throw InvalidAssetPath::missingModuleName($asset);
527
        }
528 1
        list($name, $url) = explode(':', $asset);
529
530 1
        $baseUrl = str_replace(public_path() . DIRECTORY_SEPARATOR, '', $this->getAssetsPath());
531
532 1
        $url = $this->url->asset($baseUrl . "/{$name}/" . $url);
533
534 1
        return str_replace(['http://', 'https://'], '//', $url);
535
    }
536
537
    /**
538
     * @inheritDoc
539
     */
540 6
    public function isEnabled(string $name) : bool
541
    {
542 6
        return $this->findOrFail($name)->isEnabled();
543
    }
544
545
    /**
546
     * @inheritDoc
547
     */
548 3
    public function isDisabled(string $name) : bool
549
    {
550 3
        return !$this->isEnabled($name);
551
    }
552
553
    /**
554
     * Enabling a specific module.
555
     * @param string $name
556
     * @return void
557
     * @throws \Nwidart\Modules\Exceptions\ModuleNotFoundException
558
     */
559 2
    public function enable($name)
560
    {
561 2
        $this->findOrFail($name)->enable();
562 2
    }
563
564
    /**
565
     * Disabling a specific module.
566
     * @param string $name
567
     * @return void
568
     * @throws \Nwidart\Modules\Exceptions\ModuleNotFoundException
569
     */
570 1
    public function disable($name)
571
    {
572 1
        $this->findOrFail($name)->disable();
573 1
    }
574
575
    /**
576
     * @inheritDoc
577
     */
578 100
    public function delete($name) : bool
579
    {
580 100
        return $this->findOrFail($name)->delete();
581
    }
582
583
    /**
584
     * Update dependencies for the specified module.
585
     *
586
     * @param string $module
587
     */
588
    public function update($module)
589
    {
590
        with(new Updater($this))->update($module);
591
    }
592
593
    /**
594
     * Install the specified module.
595
     *
596
     * @param string $name
597
     * @param string $version
598
     * @param string $type
599
     * @param bool   $subtree
600
     *
601
     * @return \Symfony\Component\Process\Process
602
     */
603
    public function install($name, $version = 'dev-master', $type = 'composer', $subtree = false)
604
    {
605
        $installer = new Installer($name, $version, $type, $subtree);
606
607
        return $installer->run();
608
    }
609
610
    /**
611
     * Get stub path.
612
     *
613
     * @return string|null
614
     */
615 3
    public function getStubPath()
616
    {
617 3
        if ($this->stubPath !== null) {
618 1
            return $this->stubPath;
619
        }
620
621 2
        if ($this->config('stubs.enabled') === true) {
622 1
            return $this->config('stubs.path');
623
        }
624
625 1
        return $this->stubPath;
626
    }
627
628
    /**
629
     * Set stub path.
630
     *
631
     * @param string $stubPath
632
     *
633
     * @return $this
634
     */
635 1
    public function setStubPath($stubPath)
636
    {
637 1
        $this->stubPath = $stubPath;
638
639 1
        return $this;
640
    }
641
}
642