Completed
Pull Request — master (#166)
by Josh
12:20
created

Repository::boot()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2.032

Importance

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