Passed
Pull Request — master (#239)
by
unknown
02:56
created

ModuleManager::copyAssets()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 3
dl 0
loc 3
rs 10
c 0
b 0
f 0
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.5
13
 */
14
15
namespace Quantum\Libraries\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\Router\Exceptions\ModuleLoaderException;
21
use Quantum\Di\Exceptions\DiException;
22
use Quantum\Exceptions\BaseException;
23
use Quantum\Environment\Environment;
24
use Quantum\Router\ModuleLoader;
25
use ReflectionException;
26
use Exception;
27
28
class ModuleManager
29
{
30
    /**
31
     * @var mixed
32
     */
33
    protected $fs;
34
35
    /**
36
     * @var bool
37
     */
38
    protected $optionEnabled;
39
40
    /**
41
     * @var string
42
     */
43
    private $moduleName;
44
45
    /**
46
     * @var string
47
     */
48
    private $template;
49
50
    /**
51
     * @var string
52
     */
53
    private $modulePath;
54
55
    /**
56
     * @var string
57
     */
58
    private $assetsPath;
59
60
    /**
61
     * @var string
62
     */
63
    private $templatePath;
64
65
    /**
66
     * @var bool
67
     */
68
    private $withAssets;
69
70
    /**
71
     * @var string
72
     */
73
    private $modulesConfigPath;
74
75
    /**
76
     * @param string $moduleName
77
     * @param string $template
78
     * @param bool $enabled
79
     * @param bool $withAssets
80
     * @throws BaseException
81
     * @throws DiException
82
     * @throws ConfigException
83
     * @throws ReflectionException
84
     */
85
    public function __construct(string $moduleName, string $template, bool $enabled, bool $withAssets = false)
86
    {
87
        $this->fs = FileSystemFactory::get();
88
89
        $this->moduleName = $moduleName;
90
91
        $this->withAssets = $withAssets;
92
        $this->optionEnabled = $enabled;
93
        $this->template = $template;
94
95
        $this->assetsPath = assets_dir() . DS . $moduleName;
96
        $this->modulePath = modules_dir() . DS . $moduleName;
97
        $this->templatePath = __DIR__ . DS . 'Templates' . DS . ucfirst($template);
98
        $this->modulesConfigPath = base_dir() . DS . 'shared' . DS . 'config' . DS . 'modules.php';
99
    }
100
101
    /**
102
     * @return string
103
     */
104
    public function getModuleName(): string
105
    {
106
        return $this->moduleName;
107
    }
108
109
    /**
110
     * @return string
111
     */
112
    public function getBaseNamespace(): string
113
    {
114
        return Environment::getInstance()->getAppEnv() === 'testing'
115
            ? "Quantum\\Tests\\_root\\modules"
116
            : "Modules";
117
    }
118
119
    /**
120
     * @throws ModuleLoaderException
121
     * @throws ExceptionInterface
122
     * @throws Exception
123
     */
124
    public function addModuleConfig()
125
    {
126
        if (!$this->fs->isDirectory($this->modulePath)) {
127
            throw new Exception("Module directory does not exist, skipping config update.");
128
        }
129
130
        $moduleConfigs = ModuleLoader::getInstance()->getModuleConfigs();
131
132
        foreach ($moduleConfigs as $module => $options) {
133
            if ($module == $this->moduleName || $options['prefix'] == strtolower($this->moduleName)) {
134
                throw new Exception("A module or prefix named '" . $this->moduleName . "' already exists");
135
            }
136
        }
137
138
        $moduleConfigs[$this->moduleName] = $this->getModuleOptions($this->moduleName);
139
140
        $this->updateModuleConfigFile($moduleConfigs);
141
    }
142
143
    /**
144
     * @throws Exception
145
     */
146
    public function writeContents()
147
    {
148
        $copiedFiles = [];
149
        $this->copyDirectoryWithTemplates($this->templatePath . DS . "src", $this->modulePath, $copiedFiles);
150
151
        if ($this->withAssets) {
152
            $this->copyAssets($this->templatePath . DS . "assets", $this->assetsPath, $copiedFiles);
153
        }
154
155
        if (!$this->validateModuleFiles($copiedFiles)) {
156
            throw new Exception("Module creation incomplete: missing files.");
157
        }
158
    }
159
160
    /**
161
     * @param string $src
162
     * @param string $dst
163
     * @param array $copiedFiles
164
     * @throws Exception
165
     */
166
    private function copyDirectoryWithTemplates(string $src, string $dst, array &$copiedFiles)
167
    {
168
        $this->copyDirectory($src, $dst, true, $copiedFiles);
169
    }
170
171
    /**
172
     * @param string $src
173
     * @param string $dst
174
     * @param array $copiedFiles
175
     * @throws Exception
176
     */
177
    private function copyAssets(string $src, string $dst, array &$copiedFiles)
178
    {
179
        $this->copyDirectory($src, $dst, false, $copiedFiles);
180
    }
181
182
    /**
183
     * @param string $src
184
     * @param string $dst
185
     * @param bool $processTemplates
186
     * @param array $copiedFiles
187
     * @throws Exception
188
     */
189
    private function copyDirectory(string $src, string $dst, bool $processTemplates, array &$copiedFiles)
190
    {
191
        if (!$this->fs->isDirectory($src)) {
192
            throw new Exception("Directory '$src' does not exist");
193
        }
194
195
        if (!$this->fs->isDirectory($dst)) {
196
            $this->fs->makeDirectory($dst);
197
        }
198
199
        $dir = $this->fs->listDirectory($src);
200
201
        foreach ($dir as $file) {
202
            $srcPath = $file;
203
            $dstPath = str_replace($src, $dst, $file);
204
205
            if ($this->fs->isDirectory($srcPath)) {
206
                $this->copyDirectory($srcPath, $dstPath, $processTemplates, $copiedFiles);
207
            } else {
208
                if ($processTemplates) {
209
                    $this->processTemplates($srcPath, $dstPath);
210
                }
211
                else {
212
                    $this->fs->copy($srcPath, $dstPath);
213
                }
214
                $copiedFiles[] = $dstPath;
215
            }
216
        }
217
    }
218
219
    /**
220
     * @param string $srcPath
221
     * @param string $dstPath
222
     */
223
    private function processTemplates(string $srcPath, string &$dstPath){
224
        $dstPath = str_replace('.tpl', '.php', $dstPath);
225
        $content = $this->fs->get($srcPath);
226
        $processedContent = $this->replacePlaceholders($content);
227
        $this->fs->put($dstPath, $processedContent);
228
    }
229
230
    /**
231
     * @param string $content
232
     * @return string
233
     */
234
    private function replacePlaceholders(string $content): string
235
    {
236
        $placeholders = [
237
            '{{MODULE_NAMESPACE}}' => $this->getBaseNamespace() .'\\' . $this->getModuleName(),
238
            '{{MODULE_NAME}}' => $this->getModuleName(),
239
        ];
240
241
        return str_replace(array_keys($placeholders), array_values($placeholders), $content);
242
    }
243
244
    /**
245
     * @param string $module
246
     * @return array
247
     */
248
    private function getModuleOptions(string $module): array
249
    {
250
        return [
251
            'prefix' => $this->template == "DemoWeb" ? "" : strtolower($module),
252
            'enabled' => $this->optionEnabled,
253
        ];
254
    }
255
256
    /**
257
     * @param array $moduleConfigs
258
     * @return void
259
     * @throws ExceptionInterface
260
     */
261
    private function updateModuleConfigFile(array $moduleConfigs): void
262
    {
263
        $this->fs->put(
264
            $this->modulesConfigPath,
265
            "<?php\n\nreturn " . export($moduleConfigs) . ";\n"
266
        );
267
    }
268
269
    /**
270
     * @param array $copiedFiles
271
     * @return bool
272
     */
273
    protected function validateModuleFiles(array $copiedFiles): bool
274
    {
275
        foreach ($copiedFiles as $file) {
276
            if (!$this->fs->exists($file)) {
277
                return false;
278
            }
279
        }
280
        return true;
281
    }
282
}