Completed
Pull Request — master (#322)
by Mathieu
03:43
created

Repository::update()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

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