Completed
Push — master ( a23a2d...83e21c )
by Iurii
01:22
created

Generator::createStructureTests()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 11
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 7
nc 2
nop 0
1
<?php
2
3
/**
4
 * @package Skeleton module
5
 * @author Iurii Makukh <[email protected]>
6
 * @copyright Copyright (c) 2015, Iurii Makukh
7
 * @license https://www.gnu.org/licenses/gpl.html GNU/GPLv3
8
 */
9
10
namespace gplcart\modules\skeleton\models;
11
12
use gplcart\core\Config;
13
use gplcart\core\helpers\Zip as ZipHelper;
14
15
/**
16
 * Methods to generate module skeletons
17
 */
18
class Generator
19
{
20
21
    /**
22
     * Config class instance
23
     * @var \gplcart\core\Config $config
24
     */
25
    protected $config;
26
27
    /**
28
     * Name of folder that contains module controllers
29
     */
30
    const FOLDER_CONTROLLER = 'controllers';
31
32
    /**
33
     * Name of folder that contains module helpers
34
     */
35
    const FOLDER_HELPER = 'helpers';
36
37
    /**
38
     * Name of folder that contains module models
39
     */
40
    const FOLDER_MODEL = 'models';
41
42
    /**
43
     * Name of folder that contains module handlers
44
     */
45
    const FOLDER_HANDLER = 'handlers';
46
47
    /**
48
     * Name of folder that contains module templates
49
     */
50
    const FOLDER_TEMPLATE = 'templates';
51
52
    /**
53
     * Name of folder that contains module overrides
54
     */
55
    const FOLDER_OVERRIDE = 'override';
56
57
    /**
58
     * Name of folder that contains module translations
59
     */
60
    const FOLDER_LOCALE = 'translations';
61
62
    /**
63
     * Name of folder that contains module tests
64
     */
65
    const FOLDER_TEST = 'tests';
66
67
    /**
68
     * Name of folder that contains JS assets
69
     */
70
    const FOLDER_JS = 'js';
71
72
    /**
73
     * Name of folder that contains CSS assets
74
     */
75
    const FOLDER_CSS = 'css';
76
77
    /**
78
     * Name of folder that contains images
79
     */
80
    const FOLDER_IMAGE = 'image';
81
82
    /**
83
     * Zip class instance
84
     * @var \gplcart\core\helpers\Zip $zip
85
     */
86
    protected $zip;
87
88
    /**
89
     * Full path to a ZIP file containing generated module
90
     * @var string
91
     */
92
    protected $file;
93
94
    /**
95
     * The current module directory
96
     * @var string
97
     */
98
    protected $directory;
99
100
    /**
101
     * An array of module data
102
     * @var array
103
     */
104
    protected $data = array();
105
106
    /**
107
     * @param Config $config
108
     * @param ZipHelper $zip
109
     */
110
    public function __construct(Config $config, ZipHelper $zip)
111
    {
112
        $this->zip = $zip;
113
        $this->config = $config;
114
    }
115
116
    /**
117
     * Returns an array of licenses and their URLs
118
     * @return array
119
     */
120
    public function getLicenses()
121
    {
122
        return array(
123
            'GPL-3.0+' => 'https://www.gnu.org/licenses/gpl-3.0.en.html',
124
            'MIT' => 'https://opensource.org/licenses/MIT',
125
            'Apache-2.0' => 'https://www.apache.org/licenses/LICENSE-2.0',
126
            'BSD-3-Clause' => 'https://opensource.org/licenses/BSD-3-Clause'
127
        );
128
    }
129
130
    /**
131
     * Generates module files and folders
132
     * @param array $data
133
     * @return bool
134
     */
135
    public function generate(array $data)
136
    {
137
        $this->setData($data);
138
139
        $this->createMainClass();
140
        $this->createManifest();
141
        $this->createStructure();
142
143
        return $this->createZip();
144
    }
145
146
    /**
147
     * Create module manifest file
148
     */
149
    protected function createManifest()
150
    {
151
        $data = array(
152
            'name' => $this->data['module']['name'],
153
            'core' => $this->data['module']['core'],
154
            'author' => $this->data['module']['author'],
155
            'license' => $this->data['module']['license'],
156
            'version' => $this->data['module']['version'],
157
            'description' => $this->data['module']['description']
158
        );
159
160
        if (!empty($this->data['structure']) && in_array('configurable', $this->data['structure'])) {
161
            $data['configure'] = 'admin/module/settings/' . $this->data['module']['id'];
162
            $data['settings'] = array();
163
        }
164
165
        $json = json_encode($data, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT);
166
        file_put_contents("$this->directory/module.json", $json);
167
    }
168
169
    /**
170
     * Creates various structure elements
171
     */
172
    protected function createStructure()
173
    {
174
        $this->write("$this->directory/README.md", 'readme');
175
        $this->write("$this->directory/.gitignore", 'gitignore');
176
        $this->write("$this->directory/composer.json", 'composer');
177
        $this->write("$this->directory/.scrutinizer.yml", 'scrutinizer');
178
179
        if (empty($this->data['structure'])) {
180
            return null;
181
        }
182
183
        foreach ($this->data['structure'] as $element) {
184
            switch ($element) {
185
                case 'controller':
186
                    $this->createStructureController();
187
                    break;
188
                case 'model':
189
                    $this->createStructureModel();
190
                    break;
191
                case 'helper':
192
                    $this->createStructureHelper();
193
                    break;
194
                case 'handler':
195
                    $this->createStructureHandler();
196
                    break;
197
                case 'override':
198
                    $this->createStructureOverride();
199
                    break;
200
                case 'template':
201
                    $this->createStructureTemplate();
202
                    break;
203
                case 'asset':
204
                    $this->createStructureAsset();
205
                    break;
206
                case 'locale':
207
                    $this->createStructureLocale();
208
                    break;
209
                case 'tests':
210
                    $this->createStructureTests();
211
                    break;
212
            }
213
        }
214
    }
215
216
    /**
217
     * Creates asset structure
218
     */
219
    protected function createStructureAsset()
220
    {
221
        foreach (array(self::FOLDER_CSS, self::FOLDER_JS) as $folder) {
222
            if ($this->prepareFolder("$this->directory/$folder")) {
223
                $this->write("$this->directory/$folder/common.$folder", $folder);
224
            }
225
        }
226
227
        $this->generateImage();
228
    }
229
230
    /**
231
     * Generate an image sample
232
     * @return bool
233
     */
234
    protected function generateImage()
235
    {
236
        $directory = "$this->directory/" . self::FOLDER_IMAGE;
237
238
        if (!mkdir($directory, 0775, true)) {
239
            return false;
240
        }
241
242
        $im = imagecreate(100, 100);
243
        imagecolorallocate($im, 255, 255, 255);
244
        $text = imagecolorallocate($im, 0, 0, 255);
245
        imagestring($im, 5, 0, 0, $this->data['module']['name'], $text);
246
        $result = imagepng($im, "$directory/image.png");
247
        imagedestroy($im);
248
        return $result;
249
    }
250
251
    /**
252
     * Creates locale structure
253
     */
254
    protected function createStructureLocale()
255
    {
256
        $folder = "$this->directory/" . self::FOLDER_LOCALE;
257
258
        if ($this->prepareFolder($folder)) {
259
            $name = $this->data['module']['name'];
260
            gplcart_file_csv("$folder/en.csv", array($name, $name));
261
        }
262
    }
263
264
    /**
265
     * Creates a controller class
266
     */
267
    protected function createStructureController()
268
    {
269
        $folder = "$this->directory/" . self::FOLDER_CONTROLLER;
270
271
        if ($this->prepareFolder($folder)) {
272
            $this->write("$folder/Settings.php", 'controller');
273
        }
274
    }
275
276
    /**
277
     * Creates module main class
278
     */
279
    protected function createMainClass()
280
    {
281
        if ($this->prepareFolder($this->directory)) {
282
            $this->write("$this->directory/{$this->data['module']['class_name']}.php", 'main');
283
        }
284
    }
285
286
    /**
287
     * Creates a model class
288
     */
289
    protected function createStructureModel()
290
    {
291
        $folder = "$this->directory/" . self::FOLDER_MODEL;
292
293
        if ($this->prepareFolder($folder)) {
294
            $this->write("$folder/{$this->data['module']['class_name']}.php", 'model');
295
        }
296
    }
297
298
    /**
299
     * Creates a helper class
300
     */
301
    protected function createStructureHelper()
302
    {
303
        $folder = "$this->directory/" . self::FOLDER_HELPER;
304
305
        if ($this->prepareFolder($folder)) {
306
            $this->write("$folder/{$this->data['module']['class_name']}.php", 'helper');
307
        }
308
    }
309
310
    /**
311
     * Creates a handler class
312
     */
313
    protected function createStructureHandler()
314
    {
315
        $folder = "$this->directory/" . self::FOLDER_HANDLER;
316
317
        if ($this->prepareFolder($folder)) {
318
            $this->write("$folder/{$this->data['module']['class_name']}.php", 'handler');
319
        }
320
    }
321
322
    /**
323
     * Creates module overrides
324
     */
325
    protected function createStructureOverride()
326
    {
327
        $folder = "$this->directory/" . self::FOLDER_OVERRIDE . "/classes/modules/{$this->data['module']['id']}";
328
329
        if ($this->prepareFolder($folder)) {
330
            $this->write("$folder/{$this->data['module']['class_name']}Override.php", 'override');
331
        }
332
    }
333
334
    /**
335
     * Creates a template sample
336
     */
337
    protected function createStructureTemplate()
338
    {
339
        $folder = "$this->directory/" . self::FOLDER_TEMPLATE;
340
341
        if ($this->prepareFolder($folder)) {
342
            $this->write("$folder/settings.php", 'template');
343
        }
344
    }
345
346
    /**
347
     * Creates files for unit testing
348
     */
349
    protected function createStructureTests()
350
    {
351
        $dir = "$this->directory/" . self::FOLDER_TEST;
352
353
        if ($this->prepareFolder($dir)) {
354
            $this->prepareFolder("$dir/support");
355
            $this->write("$this->directory/phpunit.xml", 'test_xml');
356
            $this->write("$dir/support/bootstrap.php", 'test_bootstrap');
357
            $this->write("$dir/{$this->data['module']['class_name']}.php", 'test');
358
        }
359
    }
360
361
    /**
362
     * Pack module folder into zip file
363
     * @return bool
364
     */
365
    protected function createZip()
366
    {
367
        $this->file = "$this->directory.zip";
368
369
        if (is_file($this->file)) {
370
            unlink($this->file);
371
        }
372
373
        $result = $this->zip->directory($this->directory, $this->file, $this->data['module']['id']);
374
        gplcart_file_delete_recursive($this->directory);
375
        return $result;
376
    }
377
378
    /**
379
     * Returns a path to zip file
380
     * @return string
381
     */
382
    public function getZip()
383
    {
384
        return $this->file;
385
    }
386
387
    /**
388
     * Recursively creates folders
389
     * @param string $folder
390
     * @return bool
391
     */
392
    protected function prepareFolder($folder)
393
    {
394
        return !file_exists($folder) && mkdir($folder, 0775, true);
395
    }
396
397
    /**
398
     * Prepares an array of data before rendering
399
     * @param array $data
400
     * @return array
401
     */
402
    protected function setData(array &$data)
403
    {
404
        $licenses = $this->getLicenses();
405
406
        $data['module']['class_name'] = $this->config->getModuleClassName($data['module']['id']);
407
        $data['module']['namespace'] = $this->config->getModuleClassNamespace($data['module']['id']);
408
        $data['module']['license_url'] = $licenses[$data['module']['license']] . ' ' . $data['module']['license'];
409
410
        $this->directory = gplcart_file_private_module('skeleton', $data['module']['id'], true);
411
        return $this->data = $data;
412
    }
413
414
    /**
415
     * Renders a template
416
     * @param string $template
417
     * @return string|null
418
     */
419
    protected function render($template)
420
    {
421
        $file = GC_DIR_MODULE . "/skeleton/templates/code/$template.php";
422
423
        if (!is_file($file)) {
424
            return null;
425
        }
426
427
        extract($this->data, EXTR_SKIP);
428
        ob_start();
429
        include $file;
430
        return ob_get_clean();
431
    }
432
433
    /**
434
     * Writes to a file using a template as an source
435
     * @param string $file
436
     * @param string $template
437
     * @return null|bool
438
     */
439
    protected function write($file, $template)
440
    {
441
        $content = $this->render($template);
442
443
        if (!isset($content)) {
444
            return null;
445
        }
446
447
        if (pathinfo($file, PATHINFO_EXTENSION) === 'php') {
448
            $content = "<?php\n\n$content";
449
        }
450
451
        return file_put_contents($file, $content) !== false;
452
    }
453
454
}
455