Passed
Push — master ( 3fd782...cac45a )
by Diego
04:58
created

PluginsResource::exists()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 3

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 4
c 1
b 0
f 0
nc 2
nop 1
dl 0
loc 9
ccs 5
cts 5
cp 1
crap 3
rs 10
1
<?php
2
3
namespace JeroenNoten\LaravelAdminLte\Console\PackageResources;
4
5
use Illuminate\Support\Facades\File;
6
use JeroenNoten\LaravelAdminLte\Helpers\CommandHelper;
7
8
class PluginsResource extends PackageResource
9
{
10
    /**
11
     * The available plugins data. A plugin can contain next data keys:
12
     * - name: The name of the plugin.
13
     * - source: The source of the plugin (relative to base source)
14
     * - target: The target of the plugin (relative to base target)
15
     * - resources: An array with resources data items.
16
     * - ignore: A list of file patterns to ignore.
17
     * - recursive: Whether to copy files recursively (default is true).
18
     *
19
     * When the target is not specified, the source will be used as the
20
     * relative path to the base target destination. A resource can contain the
21
     * same keys that are availables for a plugin.
22
     *
23
     * @var array
24
     */
25
    protected $plugins = [
26
        'bootstrap4DualListbox' => [
27
            'name' => 'Bootstrap4 Dual Listbox',
28
            'source' => 'bootstrap4-duallistbox',
29
        ],
30
        'bootstrapColorpicker' => [
31
            'name' => 'Bootstrap Colorpicker',
32
            'source' => 'bootstrap-colorpicker',
33
        ],
34
        'bootstrapSlider' => [
35
            'name' => 'Bootstrap Slider',
36
            'source' => 'bootstrap-slider',
37
        ],
38
        'bootstrapSwitch' => [
39
            'name' => 'Bootstrap Switch',
40
            'source' => 'bootstrap-switch',
41
        ],
42
        'bsCustomFileInput' => [
43
            'name' => 'bs-custom-file-input',
44
            'source' => 'bs-custom-file-input',
45
        ],
46
        'chartJs' => [
47
            'name' => 'Chart.js',
48
            'source' => 'chart.js',
49
        ],
50
        'datatables' => [
51
            'name' => 'Datatables',
52
            'resources' => [
53
                ['source' => 'datatables', 'target' => 'datatables/js'],
54
                ['source' => 'datatables-bs4', 'target' => 'datatables'],
55
            ],
56
        ],
57
        'datatablesPlugins' => [
58
            'name' => 'Datatables Plugins',
59
            'resources' => [
60
                ['source' => 'datatables-autofill', 'target' => 'datatables-plugins/autofill'],
61
                ['source' => 'datatables-buttons', 'target' => 'datatables-plugins/buttons'],
62
                ['source' => 'datatables-colreorder', 'target' => 'datatables-plugins/colreorder'],
63
                ['source' => 'datatables-fixedcolumns', 'target' => 'datatables-plugins/fixedcolumns'],
64
                ['source' => 'datatables-fixedheader', 'target' => 'datatables-plugins/fixedheader'],
65
                ['source' => 'datatables-keytable', 'target' => 'datatables-plugins/keytable'],
66
                ['source' => 'datatables-responsive', 'target' => 'datatables-plugins/responsive'],
67
                ['source' => 'datatables-rowgroup', 'target' => 'datatables-plugins/rowgroup'],
68
                ['source' => 'datatables-rowreorder', 'target' => 'datatables-plugins/rowreorder'],
69
                ['source' => 'datatables-scroller', 'target' => 'datatables-plugins/scroller'],
70
                ['source' => 'datatables-select', 'target' => 'datatables-plugins/select'],
71
                ['source' => 'pdfmake', 'target' => 'datatables-plugins/pdfmake'],
72
                ['source' => 'jszip', 'target' => 'datatables-plugins/jszip'],
73
            ],
74
        ],
75
        'daterangepicker' => [
76
            'name' => 'Date Range Picker',
77
            'resources' => [
78
                ['source' => 'daterangepicker'],
79
                ['source' => 'moment'],
80
            ],
81
        ],
82
        'ekkoLightbox' => [
83
            'name' => 'Ekko Lightbox',
84
            'source' => 'ekko-lightbox',
85
        ],
86
        'fastclick' => [
87
            'name' => 'FastClick',
88
            'source' => 'fastclick',
89
        ],
90
        'filterizr' => [
91
            'name' => 'Filterizr',
92
            'source' => 'filterizr',
93
            'ignore' => ['*.d.ts'],
94
            'recursive' => false,
95
        ],
96
        'flagIconCss' => [
97
            'name' => 'Flag Icon Css',
98
            'source' => 'flag-icon-css',
99
        ],
100
        'flot' => [
101
            'name' => 'Flot',
102
            'source' => 'flot',
103
        ],
104
        'fullcalendar' => [
105
            'name' => 'Fullcalendar',
106
            'source' => 'fullcalendar',
107
            'ignore' => ['*.d.ts', '*.json', '*.md'],
108
        ],
109
        'icheckBootstrap' => [
110
            'name' => 'iCheck Bootstrap',
111
            'source' => 'icheck-bootstrap',
112
            'ignore' => ['*.json', '*.md'],
113
        ],
114
        'inputmask' => [
115
            'name' => 'InputMask',
116
            'source' => 'inputmask',
117
        ],
118
        'ionRangslider' => [
119
            'name' => 'Ion.RangeSlider',
120
            'source' => 'ion-rangeslider',
121
            'ignore' => ['*.json', '*.md', '.editorconfig'],
122
        ],
123
        'jqueryKnob' => [
124
            'name' => 'jQuery Knob',
125
            'source' => 'jquery-knob',
126
        ],
127
        'jqueryMapael' => [
128
            'name' => 'jQuery Mapael',
129
            'resources' => [
130
                ['source' => 'jquery-mapael'],
131
                ['source' => 'raphael'],
132
                ['source' => 'jquery-mousewheel'],
133
            ],
134
            'ignore' => ['*.json', '*.md', '.editorconfig'],
135
        ],
136
        'jqueryUi' => [
137
            'name' => 'jQuery UI',
138
            'resources' => [
139
                ['source' => 'jquery-ui'],
140
                ['source' => 'jquery-ui/images'],
141
            ],
142
            'recursive' => false,
143
        ],
144
        'jqueryValidation' => [
145
            'name' => 'jQuery Validation',
146
            'source' => 'jquery-validation',
147
        ],
148
        'jqvmap' => [
149
            'name' => 'jQVMap',
150
            'source' => 'jqvmap',
151
        ],
152
        'jsgrid' => [
153
            'name' => 'jsGrid',
154
            'resources' => [
155
                ['source' => 'jsgrid'],
156
                ['source' => 'jsgrid/i18n'],
157
            ],
158
            'recursive' => false,
159
        ],
160
        'paceProgress' => [
161
            'name' => 'Pace Progress',
162
            'source' => 'pace-progress',
163
        ],
164
        'select2' => [
165
            'name' => 'Select 2 with Bootstrap 4 Theme',
166
            'resources' => [
167
                ['source' => 'select2'],
168
                ['source' => 'select2-bootstrap4-theme'],
169
            ],
170
            'ignore' => ['*.json', '*.md'],
171
        ],
172
        'sparklines' => [
173
            'name' => 'Sparklines',
174
            'source' => 'sparklines',
175
        ],
176
        'summernote' => [
177
            'name' => 'Summernote',
178
            'source' => 'summernote',
179
        ],
180
        'sweetalert2' => [
181
            'name' => 'Sweetalert 2 with Bootstrap 4 Theme',
182
            'resources' => [
183
                ['source' => 'sweetalert2'],
184
                ['source' => 'sweetalert2-theme-bootstrap-4'],
185
            ],
186
        ],
187
        'tempusdominusBootstrap4' => [
188
            'name' => 'Tempus Dominus for Bootstrap 4',
189
            'resources' => [
190
                ['source' => 'tempusdominus-bootstrap-4'],
191
                ['source' => 'moment'],
192
            ],
193
        ],
194
        'toastr' => [
195
            'name' => 'Toastr',
196
            'source' => 'toastr',
197
        ],
198
    ];
199
200
    /**
201
     * Create a new resource instance.
202
     *
203
     * @return void
204
     */
205 23
    public function __construct()
206
    {
207
        // Fill the basic resource data.
208
209 23
        $this->description = 'The set of extra plugins available with AdminLTE';
210 23
        $this->required = false;
211
212
        // Define the base source folder of the plugins.
213
214 23
        $this->source = base_path('vendor/almasaeed2010/adminlte/plugins');
215
216
        // Define the base target destination for the plugins.
217
218 23
        $this->target = public_path('vendor');
219
220
        // Fill the set of installation messages templates.
221
222 23
        $this->messages = [
223 23
            'install' => 'Do you want to plublish the :plugin plugin?',
224 23
            'overwrite' => 'The :plugin plugin was already published. Want to replace?',
225 23
            'remove' => 'Do you really want to remove the :plugin plugin?',
226 23
        ];
227
    }
228
229
    /**
230
     * Gets the plugins source data.
231
     *
232
     * @param  string  $pluginKey  A plugin key
233
     * @return array
234
     */
235 6
    public function getSourceData($pluginKey = null)
236
    {
237
        // Check if we need to get data of a specific AdminLTE plugin.
238
239 6
        if (! empty($pluginKey)) {
240 6
            return $this->plugins[$pluginKey] ?? [];
241
        }
242
243
        // Otherwise, return all the AdminLTE plugins data.
244
245 2
        return $this->plugins;
246
    }
247
248
    /**
249
     * Installs or publishes the specified plugin.
250
     *
251
     * @param  string  $pluginKey  A plugin key
252
     * @return void
253
     */
254 6
    public function install($pluginKey = null)
255
    {
256 6
        if (isset($pluginKey) && isset($this->plugins[$pluginKey])) {
257 6
            $plugin = $this->preparePlugin($this->plugins[$pluginKey]);
258 6
            $this->installPlugin($plugin);
259
        }
260
    }
261
262
    /**
263
     * Uninstalls the specified plugin.
264
     *
265
     * @param  string  $pluginKey  A plugin key
266
     * @return void
267
     */
268 6
    public function uninstall($pluginKey = null)
269
    {
270 6
        if (isset($pluginKey) && isset($this->plugins[$pluginKey])) {
271 6
            $plugin = $this->preparePlugin($this->plugins[$pluginKey]);
272 6
            $this->uninstallPlugin($plugin);
273
        }
274
    }
275
276
    /**
277
     * Checks whether a plugin already exists in the target location.
278
     *
279
     * @param  string  $pluginKey  A plugin key
280
     * @return bool
281
     */
282 5
    public function exists($pluginKey = null)
283
    {
284 5
        if (isset($pluginKey) && isset($this->plugins[$pluginKey])) {
285 4
            $plugin = $this->preparePlugin($this->plugins[$pluginKey]);
286
287 4
            return $this->pluginExists($plugin);
288
        }
289
290 1
        return false;
291
    }
292
293
    /**
294
     * Checks whether a plugin is correctly installed, i.e. if the source items
295
     * matches with the items available at the target location.
296
     *
297
     * @param  string  $pluginKey  A plugin key
298
     * @return bool
299
     */
300 7
    public function installed($pluginKey = null)
301
    {
302 7
        if (isset($pluginKey) && isset($this->plugins[$pluginKey])) {
303 6
            $plugin = $this->preparePlugin($this->plugins[$pluginKey]);
304
305 6
            return $this->pluginInstalled($plugin);
306
        }
307
308 1
        return false;
309
    }
310
311
    /**
312
     * Prepares a plugin with some sort of normalizations in its data.
313
     *
314
     * @param  array  $plugin  An array with the plugin data
315
     * @return array
316
     */
317 6
    protected function preparePlugin($plugin)
318
    {
319
        // Add source and target when not defined.
320
321 6
        $plugin['source'] = $plugin['source'] ?? '';
322 6
        $plugin['target'] = $plugin['target'] ?? $plugin['source'];
323
324
        // Add fully qualified paths and default values.
325
326 6
        $DS = DIRECTORY_SEPARATOR;
327 6
        $plugin['source'] = $this->source.$DS.$plugin['source'];
328 6
        $plugin['target'] = $this->target.$DS.$plugin['target'];
329 6
        $plugin['ignore'] = $plugin['ignore'] ?? [];
330 6
        $plugin['recursive'] = $plugin['recursive'] ?? true;
331
332
        // Add fully qualified paths and default values on the resources.
333
334 6
        if (isset($plugin['resources'])) {
335 3
            foreach ($plugin['resources'] as $key => $res) {
336 3
                $res['target'] = $res['target'] ?? $res['source'];
337 3
                $res['source'] = $plugin['source'].$DS.$res['source'];
338 3
                $res['target'] = $plugin['target'].$DS.$res['target'];
339 3
                $res['ignore'] = $res['ignore'] ?? $plugin['ignore'];
340 3
                $res['recursive'] = $res['recursive'] ?? $plugin['recursive'];
341 3
                $plugin['resources'][$key] = $res;
342
            }
343
        }
344
345
        // Return normalized plugin data.
346
347 6
        return $plugin;
348
    }
349
350
    /**
351
     * Installs the specified AdminLTE plugin.
352
     *
353
     * @param  array  $plugin  An array with the plugin data
354
     * @return void
355
     */
356 6
    protected function installPlugin($plugin)
357
    {
358
        // Check if we need to export the entire plugin.
359
360 6
        if (! isset($plugin['resources'])) {
361 6
            $this->publishResource($plugin);
362
363 6
            return;
364
        }
365
366
        // Otherwise, publish only the specified plugin resources.
367
368 2
        foreach ($plugin['resources'] as $res) {
369 2
            $this->publishResource($res);
370
        }
371
    }
372
373
    /**
374
     * Publishes the specified resource (usually a file or folder).
375
     *
376
     * @param  array  $res  An array with the resource data
377
     * @return void
378
     */
379 6
    protected function publishResource($res)
380
    {
381
        // Check whether the resource is a file or a directory.
382
383 6
        if (File::isDirectory($res['source'])) {
384 6
            CommandHelper::copyDirectory(
385 6
                $res['source'],
386 6
                $res['target'],
387 6
                $res['force'] ?? true,
388 6
                $res['recursive'] ?? true,
389 6
                $res['ignore'] ?? []
390 6
            );
391
        } else {
392
            File::ensureDirectoryExists(File::dirname($res['target']));
393
            File::copy($res['source'], $res['target']);
394
        }
395
    }
396
397
    /**
398
     * Checks whether the specified plugin already exists in the target
399
     * location.
400
     *
401
     * @param  array  $plugin  An array with the plugin data
402
     * @return bool
403
     */
404 4
    protected function pluginExists($plugin)
405
    {
406
        // When the plugin is not a resources list, just check if target exists.
407
408 4
        if (! isset($plugin['resources'])) {
409 4
            return File::exists($plugin['target']);
410
        }
411
412
        // Otherwise, check if any of the plugin resources already exists.
413
414 2
        foreach ($plugin['resources'] as $res) {
415 2
            if (File::exists($res['target'])) {
416 1
                return true;
417
            }
418
        }
419
420 2
        return false;
421
    }
422
423
    /**
424
     * Checks whether the specified plugin is correctly installed.
425
     *
426
     * @param  array  $plugin  An array with the plugin data
427
     * @return bool
428
     */
429 6
    protected function pluginInstalled($plugin)
430
    {
431
        // Check whether the plugin has resources or not.
432
433 6
        if (! isset($plugin['resources'])) {
434 6
            return $this->resourceInstalled($plugin);
435
        }
436
437 3
        foreach ($plugin['resources'] as $res) {
438 3
            if (! $this->resourceInstalled($res)) {
439 3
                return false;
440
            }
441
        }
442
443 2
        return true;
444
    }
445
446
    /**
447
     * Checks whether the specified resource is correctly installed.
448
     *
449
     * @param  array  $res  An array with the resource data
450
     * @return bool
451
     */
452 6
    protected function resourceInstalled($res)
453
    {
454
        // Check whether the resource is a file or a directory.
455
456 6
        if (File::isDirectory($res['source'])) {
457 6
            return (bool) CommandHelper::compareDirectories(
458 6
                $res['source'],
459 6
                $res['target'],
460 6
                $res['recursive'] ?? true,
461 6
                $res['ignore'] ?? []
462 6
            );
463
        }
464
465
        return CommandHelper::compareFiles($res['source'], $res['target']);
466
    }
467
468
    /**
469
     * Uninstalls the specified plugin.
470
     *
471
     * @param  array  $plugin  An array with the plugin data
472
     * @return void
473
     */
474 6
    protected function uninstallPlugin($plugin)
475
    {
476
        // If the plugin doensn't have resources, remove the main target
477
        // location folder.
478
479 6
        if (! isset($plugin['resources'])) {
480 6
            $this->uninstallResource($plugin);
481
482 6
            return;
483
        }
484
485
        // Otherwise, remove only the specified plugin resources.
486
487 2
        foreach ($plugin['resources'] as $res) {
488 2
            $this->uninstallResource($res);
489
        }
490
    }
491
492
    /**
493
     * Removes the specified resource (usually a folder).
494
     *
495
     * @param  array  $res  An array with the resource data
496
     * @return void
497
     */
498 6
    protected function uninstallResource($res)
499
    {
500 6
        $target = $res['target'];
501
502
        // Uninstall the specified resource. Note the target location is always
503
        // a folder. When the target folder does not exists, we consider the
504
        // resource as uninstalled.
505
506 6
        if (File::isDirectory($target)) {
507 6
            File::deleteDirectory($target);
508
        }
509
    }
510
}
511