Completed
Pull Request — master (#333)
by
unknown
59:20
created

Repository::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

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