命令列生成Dcat許可權列表

阿珂發表於2022-06-01

禁用admin.php中

'menu' => [
    #角色繫結選單
    "role_bind_menu" => false
]
<?php

namespace App\Console\Commands;

use Illuminate\Support\Str;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;

class GeneratePermission extends Command
{
    #命令
    protected $signature = 'admin:menu-permission';

    #描述
    protected $description = '備份選單,填充選單資料,填充許可權';

    #磁碟地址
    protected $disk;

    #備份檔案路徑
    protected $backup_path = 'backup/menu.bak';

    #選單模型
    protected $menu_model;

    #許可權模型
    protected $permission_model;

    #選單,許可權中間表名
    protected $permission_menu_table;

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();

        $this->menu_model = config('admin.database.menu_model');

        $this->permission_model = config('admin.database.permissions_model');

        $this->permission_menu_table = config('admin.database.permission_menu_table');

        $this->disk = Storage::disk(config('admin.upload.disk'));
    }

    /**
     * @description:
     * @Author:AKE
     * @Date:2022/5/7 10:40
     */
    public function handle()
    {
        $type = $this->choice('請選擇要執行的步驟', [
            '備份選單', '填充許可權', '填充選單'
        ],0);

        switch ($type){
            case '備份選單':
                $this->generateBackup();
                break;
            case '填充許可權':
                $this->fillpermission();
                break;
            case '填充選單':
                $this->fillMenu();
                break;
            default:
                $this->error('請選擇要執行的步驟');
                break;
        }
    }

    /**
     * @description:生成備份檔案
     * @Author:AKE
     * @Date:2022/5/7 9:46
     */
    private function generateBackup()
    {
        #獲取選單資料
        $arr = optional((new $this->menu_model())->get())->toArray();
        #寫入檔案
        $res = $this->disk->put($this->backup_path, serialize($arr));
        $res ? $this->info('備份成功') : $this->error('備份失敗');
    }

    /**
     * @description:填充許可權
     * @Author:AKE
     * @Date:2022/5/7 10:54
     */
    private function fillPermission()
    {
        $disk = $this->disk;
        #判斷備份檔案是否存在
        $exist = $disk->exists($this->backup_path);
        if (!$exist) {
            $this->error('請先進行選單備份');
            return;
        }
        #獲取資料並反序列化
        $menu = unserialize($disk->get($this->backup_path));
        #資料組裝
        $permission = $this->generatePermissions($menu);
        DB::beginTransaction();
        try {
            $this->info('清除許可權表...');
            #清空許可權表
            (new $this->permission_model())->truncate();
            $this->info('清除完成');

            $this->info('填充許可權...');
            $this->withProgressBar($permission, function ($permission){
                #填充許可權表
                (new $this->permission_model())->insert($permission);
            });
            $this->newLine();
            $this->info('許可權填充完成');

            $this->info('清除許可權選單中間表...');
            #清空許可權,選單中間表
            DB::table($this->permission_menu_table)->truncate();
            $this->info('清除完成');

            $this->info('填充許可權選單中間表...');
            $bar = $this->output->createProgressBar(count($permission));
            $bar->start();
            #迴圈插入許可權選單中間表
            foreach ($permission as $item) {
                $query = DB::table($this->permission_menu_table);
                #選單id和許可權id
                $query->insert([
                    'permission_id' => $item['id'],
                    'menu_id'       => $item['id'],
                    'created_at'    => date('Y-m-d H:i:s'),
                    'updated_at'    => date('Y-m-d H:i:s'),
                ]);
                #如果不是頂級,則另外繫結父級選單
                if ($item['parent_id'] != 0) {
                    $this->recursive($item['id'], $item['parent_id']);
                }
                $bar->advance();
            }
            $bar->finish();
            $this->newLine();
            $this->info('許可權選單中間表填充完成');
            DB::commit();
            $this->info('許可權填充完成');
        }catch (\Exception $exception){
            DB::rollBack();
            $this->error($exception->getMessage());
            $this->newLine();
            $this->error('許可權填充失敗');
        }
    }

    /**
     * @description:遞迴,新增許可權(為了有三級或者四級的選單的情況)
     * @param $id
     * @param $parent_id
     * @Author:AKE
     * @Date:2022/5/16 16:47
     */
    private function recursive($id, $parent_id)
    {
        if ($parent_id != 0){
            $query = DB::table($this->permission_menu_table);
            $query->insert([
                'permission_id' => $id,
                'menu_id' => $parent_id,
                'created_at'    => date('Y-m-d H:i:s'),
                'updated_at'    => date('Y-m-d H:i:s'),
            ]);
            $parent_id = (new $this->permission_model())->where('id', $parent_id)->value('parent_id');
            if ($parent_id != 0){
                $this->recursive($id, $parent_id);
            }
        }
    }

    /**
     * @description:填充選單
     * @Author:AKE
     * @Date:2022/5/7 13:20
     */
    private function fillMenu()
    {
        $disk = $this->disk;
        #判斷備份檔案是否存在
        $exist = $disk->exists($this->backup_path);
        if (!$exist) {
            $this->error('請先進行選單備份');
            return;
        }
        #獲取資料並反序列化
        $menu = unserialize($disk->get($this->backup_path));
        DB::beginTransaction();
        try {
            $this->info('清除選單表...');
            #清空選單表
            (new $this->menu_model())->truncate();
            $this->info('清除完成');

            $this->info('填充選單...');
            $this->withProgressBar($menu, function ($menu){
                #選單表資料填充
                (new $this->menu_model())->insert($menu);
            });
            $this->newLine();
            $this->info('選單填充完成');
            DB::commit();
        }catch (\Exception $exception){
            DB::rollBack();
            $this->error($exception->getMessage());
            $this->newLine();
            $this->error('填充失敗');
        }

    }

    /**
     * @description:生成許可權
     * @param $menu
     * @return array
     * @Author:AKE
     * @Date:2022/5/7 10:47
     */
    private function generatePermissions($menu)
    {
        $permissions = [];
        #迴圈整合資料
        foreach ($menu as $item) {
            #第一條不加入許可權(第一條為主頁,預設所有管理員都可以看到)
            if ($item['id'] == 1) continue;
            $temp = [];

            $temp['id'] = $item['id'];
            $temp['name'] = $item['title'];
            $temp['slug'] = (string)Str::uuid();
            $temp['http_path'] = $this->getHttpPath($item['uri']);
            $temp['order'] = $item['order'];
            $temp['parent_id'] = $item['parent_id'];
            $temp['created_at'] = date('Y-m-d H:i:s');
            $temp['updated_at'] = date('Y-m-d H:i:s');

            $permissions[] = $temp;
            unset($temp);
        }

        return $permissions;
    }

    /**
     * @description:生成許可權連結
     * @param $uri
     * @return string
     * @Author:AKE
     * @Date:2022/5/7 10:47
     */
    private function getHttpPath($uri)
    {
        if ($uri == '/' || $uri == '') return '';
        if (strpos($uri, '/') !== 0)  $uri = '/' . $uri;
        #為了防止有兩個一樣的路由故這樣寫,例如 /index 和 /index-a 等
        #如果沒有可以直接寫成 $uri . '*'
        return $uri . ',' . $uri . '/*';
    }
}
本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章