BootManager::compileBootableClasses()   C
last analyzed

Complexity

Conditions 12
Paths 12

Size

Total Lines 29
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 12
eloc 16
c 1
b 0
f 0
nc 12
nop 0
dl 0
loc 29
rs 6.9666

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace Ffcms\Core\Managers;
4
5
use Ffcms\Core\App;
6
use Ffcms\Core\Debug\DebugMeasure;
7
use Ffcms\Core\Helper\FileSystem\Directory;
8
use Ffcms\Core\Helper\FileSystem\File;
9
use Ffcms\Core\Helper\Type\Any;
10
use Ffcms\Core\Helper\Type\Obj;
11
use Ffcms\Core\Helper\Type\Str;
12
13
/**
14
 * Class BootManager. Manage auto executed boot methods in widgets and applications.
15
 * @package Ffcms\Core\Managers
16
 */
17
class BootManager
18
{
19
    use DebugMeasure;
20
21
    const CACHE_TREE_TIME = 120;
22
23
    private $loader;
24
    private $appRoots = [];
25
    private $widgetRoots = [];
26
27
    private $objects = [];
28
29
    /**
30
     * BootManager constructor. Pass composer loader inside
31
     * @param bool|object $loader
32
     */
33
    public function __construct($loader = false)
34
    {
35
        $this->startMeasure(__METHOD__);
36
        // pass loader inside
37
        $this->loader = $loader;
38
        if ($this->loader !== false) {
39
            $this->parseComposerLoader();
40
        }
41
42
        // check if cache is enabled
43
        if (App::$Cache !== null) {
44
            // try to get bootable class map from cache, or initialize parsing
45
            $cache = App::$Cache->getItem('boot.' . env_name . '.class.map');
0 ignored issues
show
Bug introduced by
The constant Ffcms\Core\Managers\env_name was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
46
            if (!$cache->isHit()) {
47
                $this->compileBootableClasses();
48
                $cache->set($this->objects)->expiresAfter(static::CACHE_TREE_TIME);
49
                App::$Cache->save($cache);
50
            } else {
51
                $this->objects = $cache->get();
52
            }
53
        } else {
54
            $this->compileBootableClasses();
55
        }
56
57
        $this->stopMeasure(__METHOD__);
58
    }
59
60
    /**
61
     * Find app's and widgets root directories over composer psr loader
62
     */
63
    private function parseComposerLoader(): void
64
    {
65
        // get composer autoload map
66
        $map = $this->loader->getPrefixes();
67
        if (Any::isArray($map)) {
68
            // get all available apps root dirs by psr loader for apps
69
            if (array_key_exists('Apps\\', $map)) {
70
                foreach ($map['Apps\\'] as $appPath) {
71
                    $this->appRoots[] = $appPath;
72
                }
73
            }
74
75
            // get Widgets map
76
            if (array_key_exists('Widgets\\', $map)) {
77
                // get all available root dirs by psr loader for widgets
78
                foreach ($map['Widgets\\'] as $widgetPath) {
79
                    $this->widgetRoots[] = $widgetPath;
80
                }
81
            }
82
        }
83
84
        // set default root path if not found anything else
85
        if (count($this->appRoots) < 1) {
86
            $this->appRoots = [root];
0 ignored issues
show
Bug introduced by
The constant Ffcms\Core\Managers\root was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
87
        }
88
89
        if (count($this->widgetRoots) < 1) {
90
            $this->widgetRoots = [root];
91
        }
92
    }
93
94
    /**
95
     * Find all bootatble instances and set it to object map
96
     * @return void
97
     */
98
    public function compileBootableClasses(): void
99
    {
100
        // list app root's
101
        foreach ($this->appRoots as $app) {
102
            $app .= '/Apps/Controller/' . env_name;
0 ignored issues
show
Bug introduced by
The constant Ffcms\Core\Managers\env_name was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
103
            $files = File::listFiles($app, ['.php'], true);
104
            foreach ($files as $file) {
105
                // define full class name with namespace
106
                $class = 'Apps\Controller\\' . env_name . '\\' . Str::cleanExtension($file);
107
                // check if class exists (must be loaded over autoloader), boot method exist and this is controller instanceof
108
                if (class_exists($class) && method_exists($class, 'boot') && is_a($class, 'Ffcms\Core\Arch\Controller', true)) {
109
                    $this->objects[] = $class;
110
                }
111
            }
112
        }
113
114
        // list widget root's
115
        foreach ($this->widgetRoots as $widget) {
116
            $widget .= '/Widgets/' . env_name;
117
            // widgets are packed in directory, classname should be the same with root directory name
118
            $dirs = Directory::scan($widget, GLOB_ONLYDIR, true);
119
            if (!Any::isArray($dirs)) {
120
                continue;
121
            }
122
123
            foreach ($dirs as $instance) {
124
                $class = 'Widgets\\' . env_name . '\\' . $instance . '\\' . $instance;
125
                if (class_exists($class) && method_exists($class, 'boot') && is_a($class, 'Ffcms\Core\Arch\Widget', true)) {
126
                    $this->objects[] = $class;
127
                }
128
            }
129
        }
130
    }
131
132
    /**
133
     * Call bootable methods in apps and widgets
134
     * @return bool
135
     */
136
    public function run(): bool
137
    {
138
        $this->startMeasure(__METHOD__);
139
140
        if (!Any::isArray($this->objects)) {
141
            return false;
142
        }
143
144
        foreach ($this->objects as $class) {
145
            forward_static_call([$class, 'boot']);
146
        }
147
148
        $this->stopMeasure(__METHOD__);
149
        return true;
150
    }
151
}
152