ModuleManager   A
last analyzed

Complexity

Total Complexity 25

Size/Duplication

Total Lines 210
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 25
dl 0
loc 210
rs 10
c 0
b 0
f 0

10 Methods

Rating   Name   Duplication   Size   Complexity  
A hasModule() 0 3 1
A updateModuleRecord() 0 12 2
A setModuleState() 0 10 3
A getModule() 0 7 2
A initializeModuleRoutes() 0 14 3
B initializeModules() 0 23 5
A __construct() 0 6 1
B registerModule() 0 28 4
A enableModule() 0 7 2
A disableModule() 0 7 2
1
<?php
2
3
namespace TwoDojo\ModuleManager;
4
5
use Illuminate\Support\Facades\Route;
6
use TwoDojo\Module\AbstractModule;
7
use TwoDojo\ModuleManager\Exceptions\ModuleNotFoundException;
8
use TwoDojo\ModuleManager\Support\EventDispatcher;
9
use TwoDojo\ModuleManager\Support\Requester;
10
11
class ModuleManager
12
{
13
    /**
14
     * @var \Illuminate\Support\Collection
15
     */
16
    private $modules;
17
18
    /**
19
     * @var \Illuminate\Contracts\Foundation\Application
20
     */
21
    private $app;
22
23
    /**
24
     * @var \TwoDojo\ModuleManager\Repositories\ModuleRegistryRepository
25
     */
26
    private $registry;
27
28
    /**
29
     * @var \TwoDojo\ModuleManager\Support\EventDispatcher
30
     */
31
    private $dispatcher;
32
33
    /**
34
     * @var array
35
     */
36
    private $resolvedModules = [];
37
38
    /**
39
     * ModuleManager constructor.
40
     * @param \Illuminate\Contracts\Foundation\Application $app
41
     * @param \TwoDojo\ModuleManager\Repositories\ModuleRegistryRepository $registry
42
     */
43
    public function __construct($app, $registry)
44
    {
45
        $this->modules = collect([]);
46
        $this->app = $app;
47
        $this->registry = $registry;
48
        $this->dispatcher = $this->app->make(EventDispatcher::class);
49
    }
50
51
    /**
52
     * @param string $module
53
     * @return bool
54
     */
55
    public function registerModule($module) : bool
56
    {
57
        $module = $this->app->make($module);
58
59
        // If the module is already registered we skip it
60
        if ($this->hasModule($module->getUniqueName())) {
61
            return false;
62
        }
63
64
        // If the module not enabled we skip it
65
        if (!$module->isEnabled()) {
66
            return false;
67
        }
68
69
        $this->dispatcher->registerListener($module);
70
71
        $this->modules->put($module->getUniqueName(), $module);
72
73
        $record = $this->registry->find($module->getUniqueName());
74
        // If we not found the record for this module then we assumed the module is just installed
75
        if ($record === null) {
76
            $this->registry->save([
77
                'uniqueName' => $module->getUniqueName(),
78
                'is_enabled' => true,
79
            ]);
80
        }
81
82
        return true;
83
    }
84
85
    /**
86
     * @param string $uniqueName
87
     * @return bool
88
     */
89
    public function hasModule(string $uniqueName) : bool
90
    {
91
        return $this->modules->has($uniqueName);
92
    }
93
94
    /**
95
     * Get the requested module or all registered modules
96
     *
97
     * @param null|string $uniqueName
98
     * @return \Illuminate\Support\Collection|\TwoDojo\Module\AbstractModule|null
99
     */
100
    public function getModule($uniqueName = null)
101
    {
102
        if ($uniqueName === null) {
103
            return $this->modules;
104
        }
105
106
        return $this->modules->get($uniqueName, null);
107
    }
108
109
    /**
110
     * Initialize the modules
111
     */
112
    public function initializeModules()
113
    {
114
        $modules = $this->registry->enabled()->all();
115
        foreach ($modules as $model) {
116
            $module = $this->modules->first(function (AbstractModule $module) use ($model) {
117
                return $module->getUniqueName() === $model->uniqueName;
118
            });
119
120
            if ($module === null) {
121
                continue;
122
            }
123
124
            if (isset($this->resolvedModules[$module->getUniqueName()])) {
125
                continue;
126
            }
127
128
            $requester = Requester::make()->setBasePath($module->getModulePath());
129
            if ($requester->exists('routes')) {
130
                $this->initializeModuleRoutes($module, $requester);
131
            }
132
133
            $this->dispatcher->dispatchEvent($module->getUniqueName(), 'initialized');
134
            $this->resolvedModules[$module->getUniqueName()] = true;
135
        }
136
    }
137
138
    protected function initializeModuleRoutes(AbstractModule $module, Requester $requester)
139
    {
140
        foreach ($requester->getFiles('routes') as $routeFile) {
141
            $name = basename($routeFile->getFilename(), '.php');
142
            $namespace = (new \ReflectionClass($module))->getNamespaceName();
143
144
            $route = Route::middleware($name)->namespace($namespace.'\\Http\\Controllers');
145
            switch ($name) {
146
                case 'api':
147
                    $route = $route->prefix($name);
148
                    break;
149
            }
150
151
            $route->group($requester->path('routes/'.$routeFile->getFilename()));
152
        }
153
    }
154
155
    /**
156
     * Enable a module
157
     *
158
     * @param string $uniqueName
159
     * @return bool
160
     * @throws ModuleNotFoundException
161
     */
162
    public function enableModule($uniqueName) : bool
163
    {
164
        if (!$this->hasModule($uniqueName)) {
165
            throw new ModuleNotFoundException();
166
        }
167
168
        return $this->setModuleState($uniqueName, true);
169
    }
170
171
    /**
172
     * Disable a module
173
     *
174
     * @param string $uniqueName
175
     * @return bool
176
     * @throws ModuleNotFoundException
177
     */
178
    public function disableModule($uniqueName) : bool
179
    {
180
        if (!$this->hasModule($uniqueName)) {
181
            throw new ModuleNotFoundException();
182
        }
183
184
        return $this->setModuleState($uniqueName, false);
185
    }
186
187
    /**
188
     * @param $uniqueName
189
     * @param bool $isEnabled
190
     * @return bool
191
     */
192
    protected function setModuleState($uniqueName, bool $isEnabled) : bool
193
    {
194
        $module = $this->getModule($uniqueName);
195
196
        $saved = $this->updateModuleRecord($module, ['is_enabled' => $isEnabled]);
0 ignored issues
show
Bug introduced by
It seems like $module can also be of type Illuminate\Support\Collection; however, parameter $module of TwoDojo\ModuleManager\Mo...r::updateModuleRecord() does only seem to accept TwoDojo\Module\AbstractModule, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

196
        $saved = $this->updateModuleRecord(/** @scrutinizer ignore-type */ $module, ['is_enabled' => $isEnabled]);
Loading history...
197
        if ($saved) {
198
            $this->dispatcher->dispatchEvent($module->getUniqueName(), $isEnabled ? 'enabled' : 'disabled');
199
        }
200
201
        return $saved;
202
    }
203
204
    /**
205
     * @param \TwoDojo\Module\AbstractModule $module
206
     * @param array $data
207
     * @return bool
208
     */
209
    protected function updateModuleRecord($module, array $data) : bool
210
    {
211
        $record = $this->registry->find($module->getUniqueName())->first();
212
        if ($record === null) {
213
            $record = $this->registry->save(array_merge_recursive([
214
                'uniqueName' => $module->getUniqueName()
215
            ], $data));
216
217
            return $record->id !== null;
218
        }
219
220
        return $this->registry->update($record->id, $data);
221
    }
222
}
223