Completed
Push — master ( 6e27f1...d5fec2 )
by Nicolas
03:36
created

FileRepository::getStubPath()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 3

Importance

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