Completed
Push — master ( 69686b...b3f98f )
by Arman
21s queued 16s
created

ModuleManager   A

Complexity

Total Complexity 27

Size/Duplication

Total Lines 252
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 73
c 0
b 0
f 0
dl 0
loc 252
rs 10
wmc 27

12 Methods

Rating   Name   Duplication   Size   Complexity  
A addModuleConfig() 0 17 5
A copyDirectoryWithTemplates() 0 3 1
A replacePlaceholders() 0 8 1
A copyAssets() 0 3 1
A __construct() 0 14 1
A updateModuleConfigFile() 0 5 1
A verifyModuleFilesCreated() 0 8 3
A writeContents() 0 14 4
A getModuleOptions() 0 5 2
A copyDirectory() 0 30 6
A getModuleName() 0 3 1
A processTemplates() 0 5 1
1
<?php
2
3
/**
4
 * Quantum PHP Framework
5
 *
6
 * An open source software development framework for PHP
7
 *
8
 * @package Quantum
9
 * @author Arman Ag. <[email protected]>
10
 * @copyright Copyright (c) 2018 Softberg LLC (https://softberg.org)
11
 * @link http://quantum.softberg.org/
12
 * @since 2.9.7
13
 */
14
15
namespace Quantum\Module;
16
17
use Symfony\Component\VarExporter\Exception\ExceptionInterface;
18
use Quantum\Libraries\Storage\Factories\FileSystemFactory;
19
use Quantum\Libraries\Config\Exceptions\ConfigException;
20
use Quantum\Module\Exceptions\ModuleException;
21
use Quantum\Di\Exceptions\DiException;
22
use Quantum\Exceptions\BaseException;
23
use ReflectionException;
24
use Exception;
25
26
/**
27
 * Class ModuleManager
28
 * @package Quantum\Module
29
 */
30
class ModuleManager
31
{
32
33
    const DEFAULT_TEMPLATE = 'DemoWeb';
34
35
    /**
36
     * @var mixed
37
     */
38
    protected $fs;
39
40
    /**
41
     * @var bool
42
     */
43
    protected $optionEnabled;
44
45
    /**
46
     * @var string
47
     */
48
    private $moduleName;
49
50
    /**
51
     * @var string
52
     */
53
    private $template;
54
55
    /**
56
     * @var string
57
     */
58
    private $modulePath;
59
60
    /**
61
     * @var string
62
     */
63
    private $assetsPath;
64
65
    /**
66
     * @var string
67
     */
68
    private $templatePath;
69
70
    /**
71
     * @var bool
72
     */
73
    private $withAssets;
74
75
    /**
76
     * @var string
77
     */
78
    private $modulesConfigPath;
79
80
    /**
81
     * @param string $moduleName
82
     * @param string $template
83
     * @param bool $enabled
84
     * @param bool $withAssets
85
     * @throws BaseException
86
     * @throws DiException
87
     * @throws ConfigException
88
     * @throws ReflectionException
89
     */
90
    public function __construct(string $moduleName, string $template, bool $enabled, bool $withAssets = false)
91
    {
92
        $this->fs = FileSystemFactory::get();
93
94
        $this->moduleName = $moduleName;
95
96
        $this->withAssets = $withAssets;
97
        $this->optionEnabled = $enabled;
98
        $this->template = $template;
99
100
        $this->assetsPath = assets_dir() . DS . $moduleName;
101
        $this->modulePath = modules_dir() . DS . $moduleName;
102
        $this->templatePath = __DIR__ . DS . 'Templates' . DS . ucfirst($template);
103
        $this->modulesConfigPath = base_dir() . DS . 'shared' . DS . 'config' . DS . 'modules.php';
104
    }
105
106
    /**
107
     * @return string
108
     */
109
    public function getModuleName(): string
110
    {
111
        return $this->moduleName;
112
    }
113
114
    /**
115
     * @throws ModuleException
116
     * @throws ExceptionInterface
117
     * @throws Exception
118
     */
119
    public function addModuleConfig()
120
    {
121
        if (!$this->fs->isDirectory($this->modulePath)) {
122
            throw ModuleException::missingModuleDirectory();
123
        }
124
125
        $moduleConfigs = ModuleLoader::getInstance()->getModuleConfigs();
126
127
        foreach ($moduleConfigs as $module => $options) {
128
            if ($module == $this->moduleName || $options['prefix'] == strtolower($this->moduleName)) {
129
                throw ModuleException::moduleAlreadyExists($this->moduleName);
130
            }
131
        }
132
133
        $moduleConfigs[$this->moduleName] = $this->getModuleOptions($this->moduleName);
134
135
        $this->updateModuleConfigFile($moduleConfigs);
136
    }
137
138
    /**
139
     * @throws Exception
140
     */
141
    public function writeContents()
142
    {
143
        if (!$this->fs->isDirectory(modules_dir())) {
144
            $this->fs->makeDirectory(modules_dir());
145
        }
146
147
        $copiedTemplates = $this->copyDirectoryWithTemplates($this->templatePath . DS . "src", $this->modulePath);
148
149
        if ($this->withAssets) {
150
            $copiedAssets = $this->copyAssets($this->templatePath . DS . "assets", $this->assetsPath);
151
        }
152
153
        if (!$this->verifyModuleFilesCreated(array_merge($copiedTemplates, $copiedAssets ?? []))) {
154
            throw ModuleException::moduleCreationIncomplete();
155
        }
156
    }
157
158
    /**
159
     * @param string $src
160
     * @param string $dst
161
     * @return array
162
     * @throws Exception
163
     */
164
    private function copyDirectoryWithTemplates(string $src, string $dst): array
165
    {
166
        return $this->copyDirectory($src, $dst, true);
167
    }
168
169
    /**
170
     * @param string $src
171
     * @param string $dst
172
     * @return array
173
     * @throws Exception
174
     */
175
    private function copyAssets(string $src, string $dst): array
176
    {
177
        return $this->copyDirectory($src, $dst, false);
178
    }
179
180
    /**
181
     * @param string $src
182
     * @param string $dst
183
     * @param bool $processTemplates
184
     * @param array $copiedFiles
185
     * @return array
186
     * @throws Exception
187
     */
188
    private function copyDirectory(string $src, string $dst, bool $processTemplates, array $copiedFiles = []): array
189
    {
190
        if (!$this->fs->isDirectory($src)) {
191
            throw ModuleException::missingModuleTemplate($this->template);
192
        }
193
194
        if (!$this->fs->isDirectory($dst)) {
195
            $this->fs->makeDirectory($dst);
196
        }
197
198
        $dir = $this->fs->listDirectory($src);
199
200
        foreach ($dir as $file) {
201
            $srcPath = $file;
202
            $dstPath = str_replace($src, $dst, $file);
203
204
            if ($this->fs->isDirectory($srcPath)) {
205
                $copiedFiles = $this->copyDirectory($srcPath, $dstPath, $processTemplates, $copiedFiles);
206
            } else {
207
                if ($processTemplates) {
208
                    $this->processTemplates($srcPath, $dstPath);
209
                }
210
                else {
211
                    $this->fs->copy($srcPath, $dstPath);
212
                }
213
                $copiedFiles[] = $dstPath;
214
            }
215
        }
216
217
        return $copiedFiles;
218
    }
219
220
    /**
221
     * @param string $srcPath
222
     * @param string $dstPath
223
     */
224
    private function processTemplates(string $srcPath, string &$dstPath){
225
        $dstPath = str_replace('.tpl', '.php', $dstPath);
226
        $content = $this->fs->get($srcPath);
227
        $processedContent = $this->replacePlaceholders($content);
228
        $this->fs->put($dstPath, $processedContent);
229
    }
230
231
    /**
232
     * @param string $content
233
     * @return string
234
     */
235
    private function replacePlaceholders(string $content): string
236
    {
237
        $placeholders = [
238
            '{{MODULE_NAMESPACE}}' => module_base_namespace() .'\\' . $this->getModuleName(),
239
            '{{MODULE_NAME}}' => $this->getModuleName(),
240
        ];
241
242
        return str_replace(array_keys($placeholders), array_values($placeholders), $content);
243
    }
244
245
    /**
246
     * @param string $module
247
     * @return array
248
     */
249
    private function getModuleOptions(string $module): array
250
    {
251
        return [
252
            'prefix' => $this->template == self::DEFAULT_TEMPLATE ? "" : strtolower($module),
253
            'enabled' => $this->optionEnabled,
254
        ];
255
    }
256
257
    /**
258
     * @param array $moduleConfigs
259
     * @return void
260
     * @throws ExceptionInterface
261
     */
262
    private function updateModuleConfigFile(array $moduleConfigs): void
263
    {
264
        $this->fs->put(
265
            $this->modulesConfigPath,
266
            "<?php\n\nreturn " . export($moduleConfigs) . ";\n"
267
        );
268
    }
269
270
    /**
271
     * @param array $copiedFiles
272
     * @return bool
273
     */
274
    protected function verifyModuleFilesCreated(array $copiedFiles): bool
275
    {
276
        foreach ($copiedFiles as $file) {
277
            if (!$this->fs->exists($file)) {
278
                return false;
279
            }
280
        }
281
        return true;
282
    }
283
}