Completed
Push — master ( c0bae2...9dc639 )
by Randall
06:18 queued 01:06
created

Repository::getAssetsPath()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

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