Completed
Push — master ( 515aaa...169b7e )
by Song
02:36
created

Extension::getPermissionValidationRules()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 11
rs 9.9
c 0
b 0
f 0
1
<?php
2
3
namespace Encore\Admin;
4
5
use Encore\Admin\Auth\Database\Permission;
6
use Illuminate\Database\Eloquent\Model;
7
use Illuminate\Support\Arr;
8
use Illuminate\Support\Facades\Config;
9
use Illuminate\Support\Facades\DB;
10
use Illuminate\Support\Facades\Route;
11
use Illuminate\Support\Facades\Validator;
12
use Illuminate\Validation\Rule;
13
14
abstract class Extension
15
{
16
    /**
17
     * @var string
18
     */
19
    protected $name;
20
21
    /**
22
     * @var array
23
     */
24
    public $css = [];
25
26
    /**
27
     * @var array
28
     */
29
    public $js = [];
30
31
    /**
32
     * @var string
33
     */
34
    public $assets = '';
35
36
    /**
37
     * @var string
38
     */
39
    public $views = '';
40
41
    /**
42
     * @var string
43
     */
44
    public $migrations = '';
45
46
    /**
47
     * @var array
48
     */
49
    public $menu = [];
50
51
    /**
52
     * @var array
53
     */
54
    public $permission = [];
55
56
    /**
57
     * Extension instance.
58
     *
59
     * @var Extension
60
     */
61
    protected static $instance;
62
63
    /**
64
     * The menu validation rules.
65
     *
66
     * @var array
67
     */
68
    protected $menuValidationRules = [
69
        'title'    => 'required',
70
        'path'     => 'required',
71
        'icon'     => 'required',
72
        'children' => 'nullable|array',
73
    ];
74
75
    /**
76
     * The permission validation rules.
77
     *
78
     * @var array
79
     */
80
    protected $permissionValidationRules = [
81
        'name'  => 'required',
82
        'slug'  => 'required',
83
        'path'  => 'required',
84
    ];
85
86
    /**
87
     * Returns the singleton instance.
88
     *
89
     * @return self
90
     */
91
    protected static function getInstance()
92
    {
93
        $class = get_called_class();
94
95
        if (!isset(self::$instance[$class]) || !self::$instance[$class] instanceof $class) {
96
            self::$instance[$class] = new static();
97
        }
98
99
        return static::$instance[$class];
100
    }
101
102
    /**
103
     * Bootstrap this extension.
104
     */
105
    public static function boot()
106
    {
107
        $extension = static::getInstance();
108
109
        Admin::extend($extension->name, get_called_class());
110
111
        if ($extension->disabled()) {
112
            return false;
113
        }
114
115
        if (!empty($css = $extension->css())) {
116
            Admin::css($css);
117
        }
118
119
        if (!empty($js = $extension->js())) {
120
            Admin::js($js);
121
        }
122
123
        return true;
124
    }
125
126
    /**
127
     * Get the path of assets files.
128
     *
129
     * @return string
130
     */
131
    public function assets()
132
    {
133
        return $this->assets;
134
    }
135
136
    /**
137
     * Get the paths of css files.
138
     *
139
     * @return array
140
     */
141
    public function css()
142
    {
143
        return $this->css;
144
    }
145
146
    /**
147
     * Get the paths of js files.
148
     *
149
     * @return array
150
     */
151
    public function js()
152
    {
153
        return $this->js;
154
    }
155
156
    /**
157
     * Get the path of view files.
158
     *
159
     * @return string
160
     */
161
    public function views()
162
    {
163
        return $this->views;
164
    }
165
166
    /**
167
     * Get the path of migration files.
168
     *
169
     * @return string
170
     */
171
    public function migrations()
172
    {
173
        return $this->migrations;
174
    }
175
176
    /**
177
     * @return array
178
     */
179
    public function menu()
180
    {
181
        return $this->menu;
182
    }
183
184
    /**
185
     * @return array
186
     */
187
    public function permission()
188
    {
189
        return $this->permission;
190
    }
191
192
    /**
193
     * Whether the extension is enabled.
194
     *
195
     * @return bool
196
     */
197
    public function enabled()
198
    {
199
        return static::config('enable') !== false;
200
    }
201
202
    /**
203
     * Whether the extension is disabled.
204
     *
205
     * @return bool
206
     */
207
    public function disabled()
208
    {
209
        return !$this->enabled();
210
    }
211
212
    /**
213
     * Get config set in config/admin.php.
214
     *
215
     * @param string $key
216
     * @param null   $default
217
     *
218
     * @return \Illuminate\Config\Repository|mixed
219
     */
220
    public static function config($key = null, $default = null)
221
    {
222
        $name = array_search(get_called_class(), Admin::$extensions);
223
224
        if (is_null($key)) {
225
            $key = sprintf('admin.extensions.%s', strtolower($name));
226
        } else {
227
            $key = sprintf('admin.extensions.%s.%s', strtolower($name), $key);
228
        }
229
230
        return config($key, $default);
231
    }
232
233
    /**
234
     * Import menu item and permission to laravel-admin.
235
     */
236
    public static function import()
237
    {
238
        $extension = static::getInstance();
239
        DB::transaction(function () use ($extension) {
240
            if ($menu = $extension->menu()) {
241
                if ($extension->validateMenu($menu)) {
242
                    extract($menu);
243
                    $children = Arr::get($menu, 'children', []);
244
                    static::createMenu($title, $path, $icon, 0, $children);
245
                }
246
            }
247
            if ($permission = $extension->permission()) {
248
                $name = Arr::get($permission, 'name', null);
249
                if (null !== $name) {
250
                    $permission = [$permission];
251
                }
252
                foreach ($permission as $item) {
253
                    if ($extension->validatePermission($item)) {
254
                        $method = [];
255
                        extract($item);
256
                        static::createPermission($name, $slug, implode("\r\n", $path), $method);
257
                    }
258
                }
259
            }
260
        });
261
    }
262
263
    /**
264
     * Validate menu fields.
265
     *
266
     * @param array $menu
267
     *
268
     * @throws \Exception
269
     *
270
     * @return bool
271
     */
272
    public function validateMenu(array $menu)
273
    {
274
        /** @var \Illuminate\Validation\Validator $validator */
275
        $validator = Validator::make($menu, $this->getMenuValidationRules());
276
277
        if ($validator->passes()) {
278
            return true;
279
        }
280
281
        $message = "Invalid menu:\r\n".implode("\r\n", Arr::flatten($validator->errors()->messages()));
282
283
        throw new \Exception($message);
284
    }
285
286
    /**
287
     * Get menu validation rules.
288
     *
289
     * @return array
290
     */
291
    protected function getMenuValidationRules()
292
    {
293
        return [
294
            'title'    => 'required',
295
            'path'     => ['required', Rule::unique(Config::get('admin.database.menu_table'), 'uri')],
296
            'icon'     => 'required',
297
            'children' => 'nullable|array',
298
        ];
299
    }
300
301
    /**
302
     * Validate permission fields.
303
     *
304
     * @param array $permission
305
     *
306
     * @throws \Exception
307
     *
308
     * @return bool
309
     */
310
    public function validatePermission(array $permission)
311
    {
312
        if (!empty($permission['method'])) {
313
            $permission['method'] = array_map('strtoupper', $permission['method']);
314
        }
315
316
        /** @var \Illuminate\Validation\Validator $validator */
317
        $validator = Validator::make($permission, $this->getPermissionValidationRules());
318
319
        if ($validator->passes()) {
320
            return true;
321
        }
322
323
        $message = "Invalid permission:\r\n".implode("\r\n", Arr::flatten($validator->errors()->messages()));
324
325
        throw new \Exception($message);
326
    }
327
328
    /**
329
     * Get permission validation rules.
330
     *
331
     * @return array
332
     */
333
    protected function getPermissionValidationRules()
334
    {
335
        return [
336
            'name'     => 'required',
337
            'slug'     => ['required', Rule::unique(Config::get('admin.database.permissions_table'), 'slug')],
338
            'path'     => 'required|array',
339
            'path.*'   => 'string',
340
            'method'   => 'nullable|array',
341
            'method.*' => ['string', Rule::in(Permission::$httpMethods)],
342
        ];
343
    }
344
345
    /**
346
     * Create a item in laravel-admin left side menu.
347
     *
348
     * @param string $title
349
     * @param string $uri
350
     * @param string $icon
351
     * @param int    $parentId
352
     * @param array  $children
353
     *
354
     * @throws \Exception
355
     *
356
     * @return Model
357
     */
358
    protected static function createMenu($title, $uri, $icon = 'fa-bars', $parentId = 0, array $children = [])
359
    {
360
        $menuModel = config('admin.database.menu_model');
361
362
        $lastOrder = $menuModel::max('order');
363
        /**
364
         * @var Model
365
         */
366
        $menu = $menuModel::create([
367
            'parent_id' => $parentId,
368
            'order'     => $lastOrder + 1,
369
            'title'     => $title,
370
            'icon'      => $icon,
371
            'uri'       => $uri,
372
        ]);
373
        if (!empty($children)) {
374
            $extension = static::getInstance();
375
            foreach ($children as $child) {
376
                if ($extension->validateMenu($child)) {
377
                    $subTitle = Arr::get($child, 'title');
378
                    $subUri = Arr::get($child, 'path');
379
                    $subIcon = Arr::get($child, 'icon');
380
                    $subChildren = Arr::get($child, 'children', []);
381
                    static::createMenu($subTitle, $subUri, $subIcon, $menu->getKey(), $subChildren);
382
                }
383
            }
384
        }
385
386
        return $menu;
387
    }
388
389
    /**
390
     * Create a permission for this extension.
391
     *
392
     * @param       $name
393
     * @param       $slug
394
     * @param       $path
395
     * @param array $methods
396
     */
397
    protected static function createPermission($name, $slug, $path, $methods = [])
398
    {
399
        $permissionModel = config('admin.database.permissions_model');
400
401
        $permissionModel::create([
402
            'name'        => $name,
403
            'slug'        => $slug,
404
            'http_path'   => '/'.trim($path, '/'),
405
            'http_method' => $methods,
406
        ]);
407
    }
408
409
    /**
410
     * Set routes for this extension.
411
     *
412
     * @param $callback
413
     */
414
    public static function routes($callback)
415
    {
416
        $attributes = array_merge(
417
            [
418
                'prefix'     => config('admin.route.prefix'),
419
                'middleware' => config('admin.route.middleware'),
420
            ],
421
            static::config('route', [])
422
        );
423
424
        Route::group($attributes, $callback);
425
    }
426
}
427