PluginsResource   A
last analyzed

Complexity

Total Complexity 39

Size/Duplication

Total Lines 507
Duplicated Lines 0 %

Test Coverage

Coverage 97.03%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 220
c 2
b 0
f 0
dl 0
loc 507
ccs 98
cts 101
cp 0.9703
rs 9.28
wmc 39

14 Methods

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