Repository   C
last analyzed

Complexity

Total Complexity 64

Size/Duplication

Total Lines 601
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 7

Importance

Changes 0
Metric Value
wmc 64
lcom 1
cbo 7
dl 0
loc 601
rs 5.8294
c 0
b 0
f 0

42 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
A addLocation() 0 6 1
A addPath() 0 4 1
A getPaths() 0 4 1
A getScanPaths() 0 12 2
A scan() 0 20 4
A all() 0 8 2
A formatCached() 0 12 2
A getCached() 0 6 1
A toCollection() 0 4 1
A getByStatus() 0 12 3
A has() 0 4 1
A enabled() 0 4 1
A disabled() 0 4 1
A count() 0 4 1
B getOrdered() 0 18 5
A getPath() 0 4 2
A register() 0 6 2
A boot() 0 6 2
A find() 0 10 3
A get() 0 4 1
A findOrFail() 0 10 2
A collections() 0 4 1
A getComponentPath() 0 8 2
A assetPath() 0 4 1
A config() 0 4 1
A getUsedStoragePath() 0 8 2
A setUsed() 0 6 1
A getUsedNow() 0 4 1
A getUsed() 0 4 1
A getFiles() 0 4 1
A getAssetsPath() 0 4 1
A asset() 0 10 1
A active() 0 4 1
A notActive() 0 4 1
A enable() 0 4 1
A disable() 0 4 1
A delete() 0 4 1
A update() 0 4 1
A install() 0 6 1
A getStubPath() 0 12 3
A setStubPath() 0 6 1

How to fix   Complexity   

Complex Class

Complex classes like Repository often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Repository, and based on these observations, apply Extract Interface, too.

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