Browse Source

Apply fixes from StyleCI

Jiang Qinghua 5 years ago
parent
commit
e916d4f47b
83 changed files with 4299 additions and 4324 deletions
  1. 17 17
      resources/lang/zh-CN/menu.php
  2. 2 3
      src/Admin.php
  3. 1 2
      src/AdminServiceProvider.php
  4. 28 28
      src/Console/ExtensionDiableCommand.php
  5. 28 28
      src/Console/ExtensionEnableCommand.php
  6. 49 49
      src/Console/ExtensionInstallCommand.php
  7. 1 0
      src/Console/ExtensionMakeCommand.php
  8. 38 38
      src/Console/ExtensionRefreshCommand.php
  9. 48 48
      src/Console/ExtensionRollbackCommand.php
  10. 37 37
      src/Console/ExtensionUninstallCommand.php
  11. 26 26
      src/Console/ExtensionUpdateCommand.php
  12. 31 31
      src/Contracts/ExceptionHandler.php
  13. 9 9
      src/Exception/AdminException.php
  14. 7 7
      src/Exception/InvalidArgumentException.php
  15. 7 7
      src/Exception/RuntimeException.php
  16. 540 540
      src/Extend/Manager.php
  17. 34 34
      src/Extend/Note.php
  18. 440 440
      src/Extend/ServiceProvider.php
  19. 89 89
      src/Extend/Setting.php
  20. 117 118
      src/Extend/UpdateManager.php
  21. 432 431
      src/Extend/VersionManager.php
  22. 1 3
      src/Form/BlockForm.php
  23. 1 1
      src/Form/Builder.php
  24. 5 6
      src/Form/Concerns/HasEvents.php
  25. 0 2
      src/Form/Concerns/HasFiles.php
  26. 7 7
      src/Form/Events/Creating.php
  27. 7 7
      src/Form/Events/Deleted.php
  28. 7 7
      src/Form/Events/Deleting.php
  29. 7 7
      src/Form/Events/Editing.php
  30. 21 21
      src/Form/Events/Event.php
  31. 7 7
      src/Form/Events/FileDeleted.php
  32. 7 7
      src/Form/Events/FileDeleting.php
  33. 7 7
      src/Form/Events/Saved.php
  34. 7 7
      src/Form/Events/Saving.php
  35. 7 7
      src/Form/Events/Submitted.php
  36. 7 7
      src/Form/Events/Uploaded.php
  37. 7 7
      src/Form/Events/Uploading.php
  38. 0 1
      src/Form/Field/Checkbox.php
  39. 0 1
      src/Form/Field/KeyValue.php
  40. 0 1
      src/Form/Field/ListField.php
  41. 1 2
      src/Form/Field/Select.php
  42. 0 1
      src/Form/Field/Tags.php
  43. 1 1
      src/Grid/ComplexHeader.php
  44. 231 231
      src/Grid/Concerns/CanHidesColumns.php
  45. 0 1
      src/Grid/Displayers/DropdownActions.php
  46. 0 1
      src/Grid/Filter/Between.php
  47. 0 1
      src/Grid/Filter/Presenter/DateTime.php
  48. 0 2
      src/Grid/Model.php
  49. 139 139
      src/Grid/Tools/ColumnSelector.php
  50. 24 24
      src/Http/Actions/Extensions/Disable.php
  51. 24 24
      src/Http/Actions/Extensions/Enable.php
  52. 21 21
      src/Http/Actions/Extensions/InstallFromLocal.php
  53. 20 20
      src/Http/Actions/Extensions/Marketplace.php
  54. 35 35
      src/Http/Actions/Extensions/Uninstall.php
  55. 28 28
      src/Http/Actions/Extensions/Update.php
  56. 1 1
      src/Http/Controllers/AuthController.php
  57. 2 3
      src/Http/Controllers/ExtensionController.php
  58. 1 1
      src/Http/Controllers/MenuController.php
  59. 1 1
      src/Http/Controllers/PermissionController.php
  60. 1 1
      src/Http/Controllers/UserController.php
  61. 49 49
      src/Http/Displayers/Extensions/Description.php
  62. 36 36
      src/Http/Displayers/Extensions/Name.php
  63. 84 84
      src/Http/Forms/InstallFromLocal.php
  64. 393 393
      src/Http/JsonResponse.php
  65. 2 2
      src/Layout/Asset.php
  66. 21 21
      src/Models/Extension.php
  67. 21 21
      src/Models/ExtensionHistory.php
  68. 22 22
      src/Models/Setting.php
  69. 0 1
      src/Show/Field.php
  70. 34 34
      src/Support/Context.php
  71. 180 182
      src/Support/DatabaseUpdater.php
  72. 90 90
      src/Support/Setting.php
  73. 250 254
      src/Support/Zip.php
  74. 183 183
      src/Traits/HasHtml.php
  75. 39 39
      src/Traits/HasVariables.php
  76. 1 1
      src/Tree.php
  77. 157 157
      src/Tree/Actions.php
  78. 15 15
      src/Tree/Actions/Delete.php
  79. 15 15
      src/Tree/Actions/Edit.php
  80. 25 25
      src/Tree/Actions/QuickEdit.php
  81. 65 65
      src/Tree/RowAction.php
  82. 0 1
      src/Widgets/DarkModeSwitcher.php
  83. 1 1
      src/Widgets/Form.php

+ 17 - 17
resources/lang/zh-CN/menu.php

@@ -1,17 +1,17 @@
-<?php
-
-return [
-    'titles' => [
-        'index'         => '主页',
-        'admin'         => '系统',
-        'users'         => '管理员',
-        'roles'         => '角色',
-        'permission'    => '权限',
-        'menu'          => '菜单',
-        'operation_log' => '操作日志',
-        'helpers'       => '开发工具',
-        'extensions'    => '扩展',
-        'scaffold'      => '代码生成器',
-        'icons'         => '图标',
-    ],
-];
+<?php
+
+return [
+    'titles' => [
+        'index'         => '主页',
+        'admin'         => '系统',
+        'users'         => '管理员',
+        'roles'         => '角色',
+        'permission'    => '权限',
+        'menu'          => '菜单',
+        'operation_log' => '操作日志',
+        'helpers'       => '开发工具',
+        'extensions'    => '扩展',
+        'scaffold'      => '代码生成器',
+        'icons'         => '图标',
+    ],
+];

+ 2 - 3
src/Admin.php

@@ -7,15 +7,14 @@ use Dcat\Admin\Contracts\ExceptionHandler;
 use Dcat\Admin\Contracts\Repository;
 use Dcat\Admin\Exception\InvalidArgumentException;
 use Dcat\Admin\Http\Controllers\AuthController;
-use Dcat\Admin\Exception\Handler;
 use Dcat\Admin\Layout\Menu;
 use Dcat\Admin\Layout\Navbar;
 use Dcat\Admin\Layout\SectionManager;
 use Dcat\Admin\Repositories\EloquentRepository;
 use Dcat\Admin\Support\Composer;
 use Dcat\Admin\Traits\HasAssets;
-use Dcat\Admin\Traits\HasPermissions;
 use Dcat\Admin\Traits\HasHtml;
+use Dcat\Admin\Traits\HasPermissions;
 use Illuminate\Auth\GuardHelpers;
 use Illuminate\Contracts\Auth\Authenticatable;
 use Illuminate\Database\Eloquent\Builder;
@@ -383,7 +382,7 @@ class Admin
         }
 
         $sidebarStyle = config('admin.layout.sidebar_style') ?: 'light';
-        
+
         $jsVariables['pjax_container_selector'] = '#'.static::getPjaxContainerId();
         $jsVariables['token'] = csrf_token();
         $jsVariables['lang'] = __('admin.client') ?: [];

+ 1 - 2
src/AdminServiceProvider.php

@@ -2,9 +2,9 @@
 
 namespace Dcat\Admin;
 
-use Dcat\Admin\Console\ExtensionInstallCommand;
 use Dcat\Admin\Contracts\ExceptionHandler;
 use Dcat\Admin\Exception\Handler;
+use Dcat\Admin\Extend\Manager;
 use Dcat\Admin\Extend\UpdateManager;
 use Dcat\Admin\Extend\VersionManager;
 use Dcat\Admin\Layout\Asset;
@@ -12,7 +12,6 @@ use Dcat\Admin\Layout\Content;
 use Dcat\Admin\Layout\Menu;
 use Dcat\Admin\Layout\Navbar;
 use Dcat\Admin\Layout\SectionManager;
-use Dcat\Admin\Extend\Manager;
 use Dcat\Admin\Support\Context;
 use Dcat\Admin\Support\Setting;
 use Dcat\Admin\Support\WebUploader;

+ 28 - 28
src/Console/ExtensionDiableCommand.php

@@ -1,28 +1,28 @@
-<?php
-
-namespace Dcat\Admin\Console;
-
-use Dcat\Admin\Admin;
-use Illuminate\Console\Command;
-
-class ExtensionDiableCommand extends Command
-{
-    protected $signature = 'admin:ext-disable {name : The name of the extension. Eg: author-name/extension-name} ';
-
-    protected $description = 'Disable an existing extension';
-
-    public function handle()
-    {
-        $extensionManager = Admin::extension();
-
-        $name = $this->argument('name');
-
-        if (! $extensionManager->has($name)) {
-            return $this->error(sprintf('Unable to find a registered extension called "%s"', $name));
-        }
-
-        $extensionManager->enable($name, false);
-
-        $this->output->writeln(sprintf('<info>%s:</info> disabled.', $name));
-    }
-}
+<?php
+
+namespace Dcat\Admin\Console;
+
+use Dcat\Admin\Admin;
+use Illuminate\Console\Command;
+
+class ExtensionDiableCommand extends Command
+{
+    protected $signature = 'admin:ext-disable {name : The name of the extension. Eg: author-name/extension-name} ';
+
+    protected $description = 'Disable an existing extension';
+
+    public function handle()
+    {
+        $extensionManager = Admin::extension();
+
+        $name = $this->argument('name');
+
+        if (! $extensionManager->has($name)) {
+            return $this->error(sprintf('Unable to find a registered extension called "%s"', $name));
+        }
+
+        $extensionManager->enable($name, false);
+
+        $this->output->writeln(sprintf('<info>%s:</info> disabled.', $name));
+    }
+}

+ 28 - 28
src/Console/ExtensionEnableCommand.php

@@ -1,29 +1,29 @@
-<?php
-
-namespace Dcat\Admin\Console;
-
-use Dcat\Admin\Admin;
-use Illuminate\Console\Command;
-
-class ExtensionEnableCommand extends Command
-{
+<?php
+
+namespace Dcat\Admin\Console;
+
+use Dcat\Admin\Admin;
+use Illuminate\Console\Command;
+
+class ExtensionEnableCommand extends Command
+{
     protected $signature = 'admin:ext-enable 
-    {name : The name of the extension. Eg: author-name/extension-name}';
-
-    protected $description = 'Enable an existing extension';
-
-    public function handle()
-    {
-        $extensionManager = Admin::extension();
-
-        $name = $this->argument('name');
-
-        if (! $extensionManager->has($name)) {
-            return $this->error(sprintf('Unable to find a registered extension called "%s"', $name));
-        }
-
-        $extensionManager->enable($name);
-
-        $this->output->writeln(sprintf('<info>%s:</info> enabled.', $name));
-    }
-}
+    {name : The name of the extension. Eg: author-name/extension-name}';
+
+    protected $description = 'Enable an existing extension';
+
+    public function handle()
+    {
+        $extensionManager = Admin::extension();
+
+        $name = $this->argument('name');
+
+        if (! $extensionManager->has($name)) {
+            return $this->error(sprintf('Unable to find a registered extension called "%s"', $name));
+        }
+
+        $extensionManager->enable($name);
+
+        $this->output->writeln(sprintf('<info>%s:</info> enabled.', $name));
+    }
+}

+ 49 - 49
src/Console/ExtensionInstallCommand.php

@@ -1,51 +1,51 @@
-<?php
-
-namespace Dcat\Admin\Console;
-
-use Dcat\Admin\Admin;
-use Illuminate\Console\Command;
-use Illuminate\Support\Arr;
-
-class ExtensionInstallCommand extends Command
-{
+<?php
+
+namespace Dcat\Admin\Console;
+
+use Dcat\Admin\Admin;
+use Illuminate\Console\Command;
+use Illuminate\Support\Arr;
+
+class ExtensionInstallCommand extends Command
+{
     protected $signature = 'admin:ext-install 
     {name : The name of the extension. Eg: author-name/extension-name} 
-    {--path= : The path of the extension.}';
-
-    protected $description = 'Install an extension';
-
-    public function handle()
-    {
-        $name = $this->argument('name');
-        $path = $this->option('path');
-
-        $manager = Admin::extension()->setOutput($this->output);
-
-        if ($path) {
-            if (! is_file($path)) {
-                $path = rtrim($path, '/').sprintf('/%s.zip', str_replace('/', '.', $name));
-            }
-        } else {
-            $extensionDetails = $manager->requestDetails($name);
-
-            $path = $hash = Arr::get($extensionDetails, 'hash');
-
-            $this->output->writeln(sprintf('<info>Downloading extension: %s[%s]</info>', $name, $hash));
-
-            $manager->download($name, $hash, true);
-        }
-
-        $this->output->writeln(sprintf('<info>Unpacking extension: %s</info>', $name));
-
-        $manager->extract($path);
-
-        $this->output->writeln(sprintf('<info>Migrating extension...</info>', $name));
-
-        Admin::extension()->load();
-
-        $manager
-            ->updateManager()
-            ->setOutPut($this->output)
-            ->update($name);
-    }
-}
+    {--path= : The path of the extension.}';
+
+    protected $description = 'Install an extension';
+
+    public function handle()
+    {
+        $name = $this->argument('name');
+        $path = $this->option('path');
+
+        $manager = Admin::extension()->setOutput($this->output);
+
+        if ($path) {
+            if (! is_file($path)) {
+                $path = rtrim($path, '/').sprintf('/%s.zip', str_replace('/', '.', $name));
+            }
+        } else {
+            $extensionDetails = $manager->requestDetails($name);
+
+            $path = $hash = Arr::get($extensionDetails, 'hash');
+
+            $this->output->writeln(sprintf('<info>Downloading extension: %s[%s]</info>', $name, $hash));
+
+            $manager->download($name, $hash, true);
+        }
+
+        $this->output->writeln(sprintf('<info>Unpacking extension: %s</info>', $name));
+
+        $manager->extract($path);
+
+        $this->output->writeln(sprintf('<info>Migrating extension...</info>', $name));
+
+        Admin::extension()->load();
+
+        $manager
+            ->updateManager()
+            ->setOutPut($this->output)
+            ->update($name);
+    }
+}

+ 1 - 0
src/Console/ExtensionMakeCommand.php

@@ -254,6 +254,7 @@ protected $js = [
     ];
 TEXT;
         }
+
         return <<<'TEXT'
 protected $type = self::TYPE_THEME;
 

+ 38 - 38
src/Console/ExtensionRefreshCommand.php

@@ -1,40 +1,40 @@
-<?php
-
-namespace Dcat\Admin\Console;
-
-use Dcat\Admin\Admin;
-use Illuminate\Console\Command;
-
-class ExtensionRefreshCommand extends Command
-{
+<?php
+
+namespace Dcat\Admin\Console;
+
+use Dcat\Admin\Admin;
+use Illuminate\Console\Command;
+
+class ExtensionRefreshCommand extends Command
+{
     protected $signature = 'admin:ext-refresh 
     {name : The name of the extension. Eg: author-name/extension-name} 
-    {--path= : The path of the extension.}';
-
-    protected $description = 'Removes and re-adds an existing extension';
-
-    public function handle()
-    {
-        $name = $this->argument('name');
-
-        if (! Admin::extension()->has($name)) {
-            throw new \InvalidArgumentException(sprintf('Plugin "%s" not found.', $name));
-        }
-
-        $confirmQuestion = 'Please confirm that you wish to reinstall this extension?';
-
-        if (! $this->confirm($confirmQuestion)) {
-            return;
-        }
-
-        $manager = Admin::extension()
-            ->updateManager()
-            ->setOutPut($this->output);
-
-        $manager->rollback($name);
-
-        $this->output->writeln('<info>Reinstalling extension...</info>');
-
-        $manager->update($name);
-    }
-}
+    {--path= : The path of the extension.}';
+
+    protected $description = 'Removes and re-adds an existing extension';
+
+    public function handle()
+    {
+        $name = $this->argument('name');
+
+        if (! Admin::extension()->has($name)) {
+            throw new \InvalidArgumentException(sprintf('Plugin "%s" not found.', $name));
+        }
+
+        $confirmQuestion = 'Please confirm that you wish to reinstall this extension?';
+
+        if (! $this->confirm($confirmQuestion)) {
+            return;
+        }
+
+        $manager = Admin::extension()
+            ->updateManager()
+            ->setOutPut($this->output);
+
+        $manager->rollback($name);
+
+        $this->output->writeln('<info>Reinstalling extension...</info>');
+
+        $manager->update($name);
+    }
+}

+ 48 - 48
src/Console/ExtensionRollbackCommand.php

@@ -1,51 +1,51 @@
-<?php
-
-namespace Dcat\Admin\Console;
-
-use Dcat\Admin\Admin;
-use Illuminate\Console\Command;
-
-class ExtensionRollbackCommand extends Command
-{
+<?php
+
+namespace Dcat\Admin\Console;
+
+use Dcat\Admin\Admin;
+use Illuminate\Console\Command;
+
+class ExtensionRollbackCommand extends Command
+{
     protected $signature = 'admin:ext-rollback 
      {name : The name of the extension. Eg: author-name/extension-name} 
      {ver : If this parameter is specified, the process will stop on the specified version, if not, it will completely rollback the extension. Example: 1.3.9} 
-     {--force : Force rollback}';
-
-    protected $description = 'Rollback an existing extension';
-
-    public function handle()
-    {
-        $name = $this->argument('name');
-
-        if (! Admin::extension()->has($name)) {
-            throw new \InvalidArgumentException('Extension not found');
-        }
-
-        $stopOnVersion = ltrim(($this->argument('ver') ?: null), 'v');
-
-        if ($stopOnVersion) {
-            if (! Admin::extension()->versionManager()->hasDatabaseVersion($name, $stopOnVersion)) {
-                throw new \InvalidArgumentException('Extension version not found');
-            }
-            $confirmQuestion = 'Please confirm that you wish to revert the extension to version '.$stopOnVersion.'. This may result in changes to your database and potential data loss.';
-        } else {
-            $confirmQuestion = 'Please confirm that you wish to completely rollback this extension. This may result in potential data loss.';
-        }
-
-        if ($this->option('force') || $this->confirm($confirmQuestion)) {
-            try {
-                Admin::extension()
-                    ->updateManager()
-                    ->setOutPut($this->output)
-                    ->rollback($name, $stopOnVersion);
-            } catch (\Throwable $exception) {
-                $lastVersion = Admin::extension()->versionManager()->getCurrentVersion($name);
-
-                $this->output->writeln(sprintf("<comment>An exception occurred during the rollback and the process has been stopped. The extension was rolled back to version v%s.</comment>", $lastVersion));
-
-                throw $exception;
-            }
-        }
-    }
-}
+     {--force : Force rollback}';
+
+    protected $description = 'Rollback an existing extension';
+
+    public function handle()
+    {
+        $name = $this->argument('name');
+
+        if (! Admin::extension()->has($name)) {
+            throw new \InvalidArgumentException('Extension not found');
+        }
+
+        $stopOnVersion = ltrim(($this->argument('ver') ?: null), 'v');
+
+        if ($stopOnVersion) {
+            if (! Admin::extension()->versionManager()->hasDatabaseVersion($name, $stopOnVersion)) {
+                throw new \InvalidArgumentException('Extension version not found');
+            }
+            $confirmQuestion = 'Please confirm that you wish to revert the extension to version '.$stopOnVersion.'. This may result in changes to your database and potential data loss.';
+        } else {
+            $confirmQuestion = 'Please confirm that you wish to completely rollback this extension. This may result in potential data loss.';
+        }
+
+        if ($this->option('force') || $this->confirm($confirmQuestion)) {
+            try {
+                Admin::extension()
+                    ->updateManager()
+                    ->setOutPut($this->output)
+                    ->rollback($name, $stopOnVersion);
+            } catch (\Throwable $exception) {
+                $lastVersion = Admin::extension()->versionManager()->getCurrentVersion($name);
+
+                $this->output->writeln(sprintf('<comment>An exception occurred during the rollback and the process has been stopped. The extension was rolled back to version v%s.</comment>', $lastVersion));
+
+                throw $exception;
+            }
+        }
+    }
+}

+ 37 - 37
src/Console/ExtensionUninstallCommand.php

@@ -1,38 +1,38 @@
-<?php
-
-namespace Dcat\Admin\Console;
-
-use Dcat\Admin\Admin;
-use Illuminate\Console\Command;
-
-class ExtensionUninstallCommand extends Command
-{
+<?php
+
+namespace Dcat\Admin\Console;
+
+use Dcat\Admin\Admin;
+use Illuminate\Console\Command;
+
+class ExtensionUninstallCommand extends Command
+{
     protected $signature = 'admin:ext-uninstall 
-    {name : The name of the extension. Eg: author-name/extension-name}';
-
-    protected $description = 'Uninstall an existing extension';
-
-    public function handle()
-    {
-        $name = $this->argument('name');
-
-        $confirmQuestion = 'Please confirm that you wish to completely rollback this extension. This may result in potential data loss.';
-
-        if ($this->confirm($confirmQuestion)) {
-            try {
-                Admin::extension()
-                    ->updateManager()
-                    ->setOutPut($this->output)
-                    ->rollback($name);
-
-                Admin::extension()->get($name)->uninstall();
-            } catch (\Throwable $exception) {
-                $lastVersion = Admin::extension()->versionManager()->getCurrentVersion($name);
-
-                $this->output->writeln(sprintf("<comment>An exception occurred during the rollback and the process has been stopped. The extension was rolled back to version v%s.</comment>", $lastVersion));
-
-                throw $exception;
-            }
-        }
-    }
-}
+    {name : The name of the extension. Eg: author-name/extension-name}';
+
+    protected $description = 'Uninstall an existing extension';
+
+    public function handle()
+    {
+        $name = $this->argument('name');
+
+        $confirmQuestion = 'Please confirm that you wish to completely rollback this extension. This may result in potential data loss.';
+
+        if ($this->confirm($confirmQuestion)) {
+            try {
+                Admin::extension()
+                    ->updateManager()
+                    ->setOutPut($this->output)
+                    ->rollback($name);
+
+                Admin::extension()->get($name)->uninstall();
+            } catch (\Throwable $exception) {
+                $lastVersion = Admin::extension()->versionManager()->getCurrentVersion($name);
+
+                $this->output->writeln(sprintf('<comment>An exception occurred during the rollback and the process has been stopped. The extension was rolled back to version v%s.</comment>', $lastVersion));
+
+                throw $exception;
+            }
+        }
+    }
+}

+ 26 - 26
src/Console/ExtensionUpdateCommand.php

@@ -1,28 +1,28 @@
-<?php
-
-namespace Dcat\Admin\Console;
-
-use Dcat\Admin\Admin;
-use Illuminate\Console\Command;
-
-class ExtensionUpdateCommand extends Command
-{
+<?php
+
+namespace Dcat\Admin\Console;
+
+use Dcat\Admin\Admin;
+use Illuminate\Console\Command;
+
+class ExtensionUpdateCommand extends Command
+{
     protected $signature = 'admin:ext-update 
     {name : The name of the extension. Eg: author-name/extension-name}
-    {--ver= : If this parameter is specified, the process will stop on the specified version, if not, it will update to the latest version. Example: 1.3.9}';
-
-    protected $description = 'Update an existing extension';
-
-    public function handle()
-    {
-        $name = $this->argument('name');
-        $version = ltrim($this->option('ver'), 'v');
-
-        Admin::extension()->load();
-
-        Admin::extension()
-            ->updateManager()
-            ->setOutPut($this->output)
-            ->update($name, $version);
-    }
-}
+    {--ver= : If this parameter is specified, the process will stop on the specified version, if not, it will update to the latest version. Example: 1.3.9}';
+
+    protected $description = 'Update an existing extension';
+
+    public function handle()
+    {
+        $name = $this->argument('name');
+        $version = ltrim($this->option('ver'), 'v');
+
+        Admin::extension()->load();
+
+        Admin::extension()
+            ->updateManager()
+            ->setOutPut($this->output)
+            ->update($name, $version);
+    }
+}

+ 31 - 31
src/Contracts/ExceptionHandler.php

@@ -1,31 +1,31 @@
-<?php
-
-namespace Dcat\Admin\Contracts;
-
-interface ExceptionHandler
-{
-    /**
-     * 处理异常.
-     *
-     * @param \Throwable $e
-     *
-     * @return array|string|void
-     */
-    public function handle(\Throwable $e);
-
-    /**
-     * 显示异常信息.
-     *
-     * @param \Throwable $exception
-     *
-     * @return array|string|void
-     */
-    public function render(\Throwable $exception);
-
-    /**
-     * 上报异常信息.
-     *
-     * @param \Throwable $e
-     */
-    public function report(\Throwable $e);
-}
+<?php
+
+namespace Dcat\Admin\Contracts;
+
+interface ExceptionHandler
+{
+    /**
+     * 处理异常.
+     *
+     * @param \Throwable $e
+     *
+     * @return array|string|void
+     */
+    public function handle(\Throwable $e);
+
+    /**
+     * 显示异常信息.
+     *
+     * @param \Throwable $exception
+     *
+     * @return array|string|void
+     */
+    public function render(\Throwable $exception);
+
+    /**
+     * 上报异常信息.
+     *
+     * @param \Throwable $e
+     */
+    public function report(\Throwable $e);
+}

+ 9 - 9
src/Exception/AdminException.php

@@ -1,9 +1,9 @@
-<?php
-
-namespace Dcat\Admin\Exception;
-
-use Exception;
-
-class AdminException extends Exception
-{
-}
+<?php
+
+namespace Dcat\Admin\Exception;
+
+use Exception;
+
+class AdminException extends Exception
+{
+}

+ 7 - 7
src/Exception/InvalidArgumentException.php

@@ -1,7 +1,7 @@
-<?php
-
-namespace Dcat\Admin\Exception;
-
-class InvalidArgumentException extends AdminException
-{
-}
+<?php
+
+namespace Dcat\Admin\Exception;
+
+class InvalidArgumentException extends AdminException
+{
+}

+ 7 - 7
src/Exception/RuntimeException.php

@@ -1,7 +1,7 @@
-<?php
-
-namespace Dcat\Admin\Exception;
-
-class RuntimeException extends AdminException
-{
-}
+<?php
+
+namespace Dcat\Admin\Exception;
+
+class RuntimeException extends AdminException
+{
+}

+ 540 - 540
src/Extend/Manager.php

@@ -1,540 +1,540 @@
-<?php
-
-namespace Dcat\Admin\Extend;
-
-use Dcat\Admin\Admin;
-use Dcat\Admin\Exception\AdminException;
-use Dcat\Admin\Exception\RuntimeException;
-use Dcat\Admin\Models\Extension as ExtensionModel;
-use Dcat\Admin\Models\Extension;
-use Dcat\Admin\Support\Composer;
-use Dcat\Admin\Support\Helper;
-use Dcat\Admin\Support\Zip;
-use Illuminate\Contracts\Container\Container;
-use Illuminate\Filesystem\Filesystem;
-use Illuminate\Support\Collection;
-use Illuminate\Support\Str;
-use RecursiveDirectoryIterator;
-use RecursiveIteratorIterator;
-
-class Manager
-{
-    use Note;
-
-    /**
-     * @var Container
-     */
-    protected $app;
-
-    /**
-     * @var ServiceProvider[]|Collection
-     */
-    protected $extensions;
-
-    /**
-     * @var array
-     */
-    protected $extensionPaths = [];
-
-    /**
-     * @var ExtensionModel[]|Collection
-     */
-    protected $settings;
-
-    /**
-     * @var Filesystem
-     */
-    protected $files;
-
-    public function __construct(Container $app)
-    {
-        $this->app = $app;
-
-        $this->extensions = new Collection();
-
-        $this->files = app('files');
-    }
-
-    /**
-     * 注册扩展.
-     *
-     * @return void
-     */
-    public function register()
-    {
-        $this->load();
-
-        $this->extensions->each->register();
-    }
-
-    /**
-     * 初始化扩展.
-     */
-    public function boot()
-    {
-        $this->extensions->each->boot();
-    }
-
-    /**
-     * 判断扩展是否启用.
-     *
-     * @param string|null $name
-     *
-     * @return bool
-     */
-    public function enabled(?string $name)
-    {
-        return (bool) optional($this->settings()->get($name))->is_enabled;
-    }
-
-    /**
-     * 启用或禁用扩展.
-     *
-     * @param string|null $name
-     * @param bool        $enable
-     *
-     * @return void
-     */
-    public function enable(?string $name, bool $enable = true)
-    {
-        $name = $this->getName($name);
-
-        $extension = Extension::where('name', $name)->first();
-
-        if (! $extension) {
-            throw new RuntimeException(sprintf('Please install the extension(%s) first!', $name));
-        }
-
-        $extension->is_enabled = $enable;
-
-        $extension->save();
-    }
-
-    /**
-     * 加载扩展,注册自动加载规则.
-     *
-     * @return void
-     */
-    public function load()
-    {
-        foreach ($this->getExtensionDirectories() as $directory) {
-            try {
-                $this->loadExtension($directory);
-            } catch (\Throwable $e) {
-                $this->reportException($e);
-            }
-        }
-    }
-
-    /**
-     * 获取扩展路径.
-     *
-     * @param string|ServiceProvider $name
-     * @param string|null            $path
-     *
-     * @return string|void
-     *
-     * @throws \ReflectionException
-     */
-    public function path($name, $path = null)
-    {
-        if (! $extension = $this->get($name)) {
-            return;
-        }
-
-        return $extension->path($path);
-    }
-
-    /**
-     * 获取扩展对象.
-     *
-     * @param string|ServiceProvider $name
-     *
-     * @return ServiceProvider|null
-     */
-    public function get($name)
-    {
-        if ($name instanceof ServiceProvider) {
-            return $name;
-        }
-
-        return $this->extensions->get($this->formatName($name));
-    }
-
-    /**
-     * 判断插件是否存在.
-     *
-     * @param string $name
-     *
-     * @return bool
-     */
-    public function has($name)
-    {
-        return $this->extensions->has($this->formatName($name));
-    }
-
-    /**
-     * @param string $name
-     *
-     * @return mixed
-     */
-    protected function formatName($name)
-    {
-        if (! is_string($name)) {
-            return $name;
-        }
-
-        return str_replace('/', '.', $name);
-    }
-
-    /**
-     * 获取所有扩展.
-     *
-     * @return ServiceProvider[]|Collection
-     */
-    public function all()
-    {
-        return $this->extensions;
-    }
-
-    /**
-     * 获取已启用的扩展.
-     *
-     * @return ServiceProvider[]|Collection
-     */
-    public function available()
-    {
-        return $this->all()->filter->enabled();
-    }
-
-    /**
-     * 加载扩展.
-     *
-     * @param string $directory
-     * @param bool   $addPsr4
-     *
-     * @return ServiceProvider|null
-     */
-    public function loadExtension(string $directory, bool $addPsr4 = true)
-    {
-        if (array_key_exists($directory, $this->extensionPaths)) {
-            return $this->extensionPaths[$directory];
-        }
-
-        $this->extensionPaths[$directory] = $serviceProvider = $this->resolveExtension($directory, $addPsr4);
-
-        if ($serviceProvider) {
-            $this->addExtension($serviceProvider);
-        }
-
-        return $serviceProvider;
-    }
-
-    /**
-     * 获取扩展类实例.
-     *
-     * @param string $directory
-     * @param bool   $addPsr4
-     *
-     * @return ServiceProvider
-     */
-    public function resolveExtension(string $directory, bool $addPsr4 = true)
-    {
-        $composerProperty = Composer::parse($directory.'/composer.json');
-
-        $serviceProvider = $composerProperty->get('extra.dcat-admin');
-        $psr4 = $composerProperty->get('autoload.psr-4');
-
-        if (! $serviceProvider || ! $psr4) {
-            return;
-        }
-
-        if ($addPsr4) {
-            $this->registerPsr4($directory, $psr4);
-        }
-
-        $serviceProvider = new $serviceProvider($this->app);
-
-        return $serviceProvider->withComposerProperty($composerProperty);
-    }
-
-    /**
-     * 获取扩展目录.
-     *
-     * @param string $dirPath
-     *
-     * @return array
-     */
-    public function getExtensionDirectories($dirPath = null)
-    {
-        $extensions = [];
-
-        $dirPath = $dirPath ?: admin_extension_path();
-
-        if (! is_dir($dirPath)) {
-            return $extensions;
-        }
-
-        $it = new RecursiveIteratorIterator(
-            new RecursiveDirectoryIterator($dirPath, RecursiveDirectoryIterator::FOLLOW_SYMLINKS)
-        );
-        $it->setMaxDepth(2);
-        $it->rewind();
-
-        while ($it->valid()) {
-            if ($it->getDepth() > 1 && $it->getFilename() === 'composer.json') {
-                $extensions[] = dirname($it->getPathname());
-            }
-
-            $it->next();
-        }
-
-        return $extensions;
-    }
-
-    /**
-     * 添加扩展.
-     *
-     * @param \Dcat\Admin\Extend\ServiceProvider $serviceProvider
-     */
-    public function addExtension(ServiceProvider $serviceProvider)
-    {
-        if (! $serviceProvider->getName()) {
-            $json = dirname(Helper::guessClassFileName($serviceProvider)).'/composer.json';
-
-            if (! is_file($json)) {
-                throw new RuntimeException('Error extension "%s"', get_class($serviceProvider));
-            }
-
-            $serviceProvider->withComposerProperty(Composer::parse($json));
-        }
-
-        $this->extensions->put($serviceProvider->getName(), $serviceProvider);
-
-        $this->app->instance($abstract = get_class($serviceProvider), $serviceProvider);
-        $this->app->alias($abstract, $serviceProvider->getName());
-    }
-
-    /**
-     * 获取扩展名称.
-     *
-     * @param $extension
-     *
-     * @return string
-     */
-    public function getName($extension)
-    {
-        if ($extension instanceof ServiceProvider) {
-            return $extension->getName();
-        }
-
-        return $this->formatName($extension);
-    }
-
-    /**
-     * 解压缩扩展包.
-     */
-    public function extract($filePath)
-    {
-        $filePath = is_file($filePath) ? $filePath : $this->getFilePath($filePath);
-
-        $this->extractZip($filePath);
-
-        @unlink($filePath);
-    }
-
-    /**
-     * @param string $filePath
-     *
-     * @return bool
-     */
-    public function extractZip($filePath)
-    {
-        // 创建临时目录.
-        $tempPath = $this->makeTempDirectory();
-
-        try {
-            $filePath = is_file($filePath) ? $filePath : $this->getFilePath($filePath);
-
-            if (! Zip::extract($filePath, $tempPath)) {
-                throw new AdminException(sprintf('Unable to extract core file \'%s\'.', $filePath));
-            }
-
-            $extensions = $this->getExtensionDirectories($tempPath);
-
-            // 无上层目录
-            $directory = $tempPath;
-
-            if (count($extensions) === 1) {
-                // 双层目录
-                $directory = current($extensions);
-            } elseif (count($results = $this->scandir($tempPath)) === 1) {
-                // 单层目录
-                $directory = current($results);
-            }
-
-            // 验证扩展包内容是否正确.
-            if (! $this->checkFiles($directory)) {
-                throw new RuntimeException(sprintf('Error extension file "%s".', $filePath));
-            }
-
-            $composerProperty = Composer::parse($directory.'/composer.json');
-
-            $extensionDir = admin_extension_path($composerProperty->name);
-
-            if (is_dir($extensionDir)) {
-                throw new RuntimeException(sprintf('The extension [%s] already exist!', $composerProperty->name));
-            }
-
-            $this->files->makeDirectory($extensionDir, 0755, true);
-
-            $this->files->copyDirectory($directory, $extensionDir);
-        } finally {
-            $this->files->deleteDirectory($tempPath);
-        }
-    }
-
-    /**
-     * 校验扩展包内容是否正确.
-     *
-     * @param $directory
-     *
-     * @return bool
-     */
-    protected function checkFiles($directory)
-    {
-        if (
-            ! is_dir($directory.'/src')
-            || ! is_file($directory.'/composer.json')
-            || ! is_file($directory.'/version.php')
-        ) {
-            return false;
-        }
-
-        $composerProperty = Composer::parse($directory.'/composer.json');
-
-        if (! $composerProperty->name || ! $composerProperty->get('extra.dcat-admin')) {
-            return false;
-        }
-
-        return true;
-    }
-
-    /**
-     * 生成临时文件.
-     *
-     * @param string $fileCode A unique file code
-     * @return string           Full path on the disk
-     */
-    protected function getFilePath($fileCode)
-    {
-        $name = md5($fileCode).'.arc';
-
-        return $this->makeTempDirectory('extensions').'/'.$name;
-    }
-
-    /**
-     * 获取配置.
-     *
-     * @return ExtensionModel[]|Collection
-     */
-    public function settings()
-    {
-        if ($this->settings === null) {
-            try {
-                $this->settings = ExtensionModel::all()->keyBy('name');
-            } catch (\Throwable $e) {
-                $this->reportException($e);
-
-                $this->settings = new Collection();
-            }
-        }
-
-        return $this->settings;
-    }
-
-    /**
-     * @return UpdateManager
-     */
-    public function updateManager()
-    {
-        return app('admin.extend.update');
-    }
-
-    /**
-     * @return VersionManager
-     */
-    public function versionManager()
-    {
-        return app('admin.extend.version');
-    }
-
-    /**
-     * 创建临时目录.
-     *
-     * @param string $dir
-     *
-     * @return string
-     */
-    protected function makeTempDirectory($dir = null)
-    {
-        $tempDir = storage_path('tmp/'.($dir ?: time().Str::random()));
-
-        if (! is_dir($tempDir)) {
-            if (! $this->files->makeDirectory($tempDir, 777, true)) {
-                throw new RuntimeException(sprintf('Cannot write to directory "%s"', storage_path()));
-            }
-        }
-
-        return $tempDir;
-    }
-
-    /**
-     * 注册 PSR4 验证规则.
-     *
-     * @param string $directory
-     * @param array  $psr4
-     */
-    protected function registerPsr4($directory, array $psr4)
-    {
-        $classLoader = Admin::classLoader();
-
-        foreach ($psr4 as $namespace => $path) {
-            $path = $directory.'/'.trim($path, '/').'/';
-
-            $classLoader->addPsr4($namespace, $path);
-        }
-    }
-
-    /**
-     * 上报异常.
-     *
-     * @param \Throwable $e
-     */
-    protected function reportException(\Throwable $e)
-    {
-        Admin::reportException($e);
-    }
-
-    /**
-     * @param string $dir
-     *
-     * @return array
-     */
-    protected function scandir($dir)
-    {
-        $results = [];
-
-        foreach (scandir($dir) as $value) {
-            if (
-                $value !== '.'
-                && $value !== '..'
-                && is_dir($value = $dir.'/'.$value)
-            ) {
-                $results[] = $value;
-            }
-        }
-
-        return $results;
-    }
-}
+<?php
+
+namespace Dcat\Admin\Extend;
+
+use Dcat\Admin\Admin;
+use Dcat\Admin\Exception\AdminException;
+use Dcat\Admin\Exception\RuntimeException;
+use Dcat\Admin\Models\Extension;
+use Dcat\Admin\Models\Extension as ExtensionModel;
+use Dcat\Admin\Support\Composer;
+use Dcat\Admin\Support\Helper;
+use Dcat\Admin\Support\Zip;
+use Illuminate\Contracts\Container\Container;
+use Illuminate\Filesystem\Filesystem;
+use Illuminate\Support\Collection;
+use Illuminate\Support\Str;
+use RecursiveDirectoryIterator;
+use RecursiveIteratorIterator;
+
+class Manager
+{
+    use Note;
+
+    /**
+     * @var Container
+     */
+    protected $app;
+
+    /**
+     * @var ServiceProvider[]|Collection
+     */
+    protected $extensions;
+
+    /**
+     * @var array
+     */
+    protected $extensionPaths = [];
+
+    /**
+     * @var ExtensionModel[]|Collection
+     */
+    protected $settings;
+
+    /**
+     * @var Filesystem
+     */
+    protected $files;
+
+    public function __construct(Container $app)
+    {
+        $this->app = $app;
+
+        $this->extensions = new Collection();
+
+        $this->files = app('files');
+    }
+
+    /**
+     * 注册扩展.
+     *
+     * @return void
+     */
+    public function register()
+    {
+        $this->load();
+
+        $this->extensions->each->register();
+    }
+
+    /**
+     * 初始化扩展.
+     */
+    public function boot()
+    {
+        $this->extensions->each->boot();
+    }
+
+    /**
+     * 判断扩展是否启用.
+     *
+     * @param string|null $name
+     *
+     * @return bool
+     */
+    public function enabled(?string $name)
+    {
+        return (bool) optional($this->settings()->get($name))->is_enabled;
+    }
+
+    /**
+     * 启用或禁用扩展.
+     *
+     * @param string|null $name
+     * @param bool        $enable
+     *
+     * @return void
+     */
+    public function enable(?string $name, bool $enable = true)
+    {
+        $name = $this->getName($name);
+
+        $extension = Extension::where('name', $name)->first();
+
+        if (! $extension) {
+            throw new RuntimeException(sprintf('Please install the extension(%s) first!', $name));
+        }
+
+        $extension->is_enabled = $enable;
+
+        $extension->save();
+    }
+
+    /**
+     * 加载扩展,注册自动加载规则.
+     *
+     * @return void
+     */
+    public function load()
+    {
+        foreach ($this->getExtensionDirectories() as $directory) {
+            try {
+                $this->loadExtension($directory);
+            } catch (\Throwable $e) {
+                $this->reportException($e);
+            }
+        }
+    }
+
+    /**
+     * 获取扩展路径.
+     *
+     * @param string|ServiceProvider $name
+     * @param string|null            $path
+     *
+     * @return string|void
+     *
+     * @throws \ReflectionException
+     */
+    public function path($name, $path = null)
+    {
+        if (! $extension = $this->get($name)) {
+            return;
+        }
+
+        return $extension->path($path);
+    }
+
+    /**
+     * 获取扩展对象.
+     *
+     * @param string|ServiceProvider $name
+     *
+     * @return ServiceProvider|null
+     */
+    public function get($name)
+    {
+        if ($name instanceof ServiceProvider) {
+            return $name;
+        }
+
+        return $this->extensions->get($this->formatName($name));
+    }
+
+    /**
+     * 判断插件是否存在.
+     *
+     * @param string $name
+     *
+     * @return bool
+     */
+    public function has($name)
+    {
+        return $this->extensions->has($this->formatName($name));
+    }
+
+    /**
+     * @param string $name
+     *
+     * @return mixed
+     */
+    protected function formatName($name)
+    {
+        if (! is_string($name)) {
+            return $name;
+        }
+
+        return str_replace('/', '.', $name);
+    }
+
+    /**
+     * 获取所有扩展.
+     *
+     * @return ServiceProvider[]|Collection
+     */
+    public function all()
+    {
+        return $this->extensions;
+    }
+
+    /**
+     * 获取已启用的扩展.
+     *
+     * @return ServiceProvider[]|Collection
+     */
+    public function available()
+    {
+        return $this->all()->filter->enabled();
+    }
+
+    /**
+     * 加载扩展.
+     *
+     * @param string $directory
+     * @param bool   $addPsr4
+     *
+     * @return ServiceProvider|null
+     */
+    public function loadExtension(string $directory, bool $addPsr4 = true)
+    {
+        if (array_key_exists($directory, $this->extensionPaths)) {
+            return $this->extensionPaths[$directory];
+        }
+
+        $this->extensionPaths[$directory] = $serviceProvider = $this->resolveExtension($directory, $addPsr4);
+
+        if ($serviceProvider) {
+            $this->addExtension($serviceProvider);
+        }
+
+        return $serviceProvider;
+    }
+
+    /**
+     * 获取扩展类实例.
+     *
+     * @param string $directory
+     * @param bool   $addPsr4
+     *
+     * @return ServiceProvider
+     */
+    public function resolveExtension(string $directory, bool $addPsr4 = true)
+    {
+        $composerProperty = Composer::parse($directory.'/composer.json');
+
+        $serviceProvider = $composerProperty->get('extra.dcat-admin');
+        $psr4 = $composerProperty->get('autoload.psr-4');
+
+        if (! $serviceProvider || ! $psr4) {
+            return;
+        }
+
+        if ($addPsr4) {
+            $this->registerPsr4($directory, $psr4);
+        }
+
+        $serviceProvider = new $serviceProvider($this->app);
+
+        return $serviceProvider->withComposerProperty($composerProperty);
+    }
+
+    /**
+     * 获取扩展目录.
+     *
+     * @param string $dirPath
+     *
+     * @return array
+     */
+    public function getExtensionDirectories($dirPath = null)
+    {
+        $extensions = [];
+
+        $dirPath = $dirPath ?: admin_extension_path();
+
+        if (! is_dir($dirPath)) {
+            return $extensions;
+        }
+
+        $it = new RecursiveIteratorIterator(
+            new RecursiveDirectoryIterator($dirPath, RecursiveDirectoryIterator::FOLLOW_SYMLINKS)
+        );
+        $it->setMaxDepth(2);
+        $it->rewind();
+
+        while ($it->valid()) {
+            if ($it->getDepth() > 1 && $it->getFilename() === 'composer.json') {
+                $extensions[] = dirname($it->getPathname());
+            }
+
+            $it->next();
+        }
+
+        return $extensions;
+    }
+
+    /**
+     * 添加扩展.
+     *
+     * @param \Dcat\Admin\Extend\ServiceProvider $serviceProvider
+     */
+    public function addExtension(ServiceProvider $serviceProvider)
+    {
+        if (! $serviceProvider->getName()) {
+            $json = dirname(Helper::guessClassFileName($serviceProvider)).'/composer.json';
+
+            if (! is_file($json)) {
+                throw new RuntimeException('Error extension "%s"', get_class($serviceProvider));
+            }
+
+            $serviceProvider->withComposerProperty(Composer::parse($json));
+        }
+
+        $this->extensions->put($serviceProvider->getName(), $serviceProvider);
+
+        $this->app->instance($abstract = get_class($serviceProvider), $serviceProvider);
+        $this->app->alias($abstract, $serviceProvider->getName());
+    }
+
+    /**
+     * 获取扩展名称.
+     *
+     * @param $extension
+     *
+     * @return string
+     */
+    public function getName($extension)
+    {
+        if ($extension instanceof ServiceProvider) {
+            return $extension->getName();
+        }
+
+        return $this->formatName($extension);
+    }
+
+    /**
+     * 解压缩扩展包.
+     */
+    public function extract($filePath)
+    {
+        $filePath = is_file($filePath) ? $filePath : $this->getFilePath($filePath);
+
+        $this->extractZip($filePath);
+
+        @unlink($filePath);
+    }
+
+    /**
+     * @param string $filePath
+     *
+     * @return bool
+     */
+    public function extractZip($filePath)
+    {
+        // 创建临时目录.
+        $tempPath = $this->makeTempDirectory();
+
+        try {
+            $filePath = is_file($filePath) ? $filePath : $this->getFilePath($filePath);
+
+            if (! Zip::extract($filePath, $tempPath)) {
+                throw new AdminException(sprintf('Unable to extract core file \'%s\'.', $filePath));
+            }
+
+            $extensions = $this->getExtensionDirectories($tempPath);
+
+            // 无上层目录
+            $directory = $tempPath;
+
+            if (count($extensions) === 1) {
+                // 双层目录
+                $directory = current($extensions);
+            } elseif (count($results = $this->scandir($tempPath)) === 1) {
+                // 单层目录
+                $directory = current($results);
+            }
+
+            // 验证扩展包内容是否正确.
+            if (! $this->checkFiles($directory)) {
+                throw new RuntimeException(sprintf('Error extension file "%s".', $filePath));
+            }
+
+            $composerProperty = Composer::parse($directory.'/composer.json');
+
+            $extensionDir = admin_extension_path($composerProperty->name);
+
+            if (is_dir($extensionDir)) {
+                throw new RuntimeException(sprintf('The extension [%s] already exist!', $composerProperty->name));
+            }
+
+            $this->files->makeDirectory($extensionDir, 0755, true);
+
+            $this->files->copyDirectory($directory, $extensionDir);
+        } finally {
+            $this->files->deleteDirectory($tempPath);
+        }
+    }
+
+    /**
+     * 校验扩展包内容是否正确.
+     *
+     * @param $directory
+     *
+     * @return bool
+     */
+    protected function checkFiles($directory)
+    {
+        if (
+            ! is_dir($directory.'/src')
+            || ! is_file($directory.'/composer.json')
+            || ! is_file($directory.'/version.php')
+        ) {
+            return false;
+        }
+
+        $composerProperty = Composer::parse($directory.'/composer.json');
+
+        if (! $composerProperty->name || ! $composerProperty->get('extra.dcat-admin')) {
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * 生成临时文件.
+     *
+     * @param string $fileCode A unique file code
+     * @return string           Full path on the disk
+     */
+    protected function getFilePath($fileCode)
+    {
+        $name = md5($fileCode).'.arc';
+
+        return $this->makeTempDirectory('extensions').'/'.$name;
+    }
+
+    /**
+     * 获取配置.
+     *
+     * @return ExtensionModel[]|Collection
+     */
+    public function settings()
+    {
+        if ($this->settings === null) {
+            try {
+                $this->settings = ExtensionModel::all()->keyBy('name');
+            } catch (\Throwable $e) {
+                $this->reportException($e);
+
+                $this->settings = new Collection();
+            }
+        }
+
+        return $this->settings;
+    }
+
+    /**
+     * @return UpdateManager
+     */
+    public function updateManager()
+    {
+        return app('admin.extend.update');
+    }
+
+    /**
+     * @return VersionManager
+     */
+    public function versionManager()
+    {
+        return app('admin.extend.version');
+    }
+
+    /**
+     * 创建临时目录.
+     *
+     * @param string $dir
+     *
+     * @return string
+     */
+    protected function makeTempDirectory($dir = null)
+    {
+        $tempDir = storage_path('tmp/'.($dir ?: time().Str::random()));
+
+        if (! is_dir($tempDir)) {
+            if (! $this->files->makeDirectory($tempDir, 777, true)) {
+                throw new RuntimeException(sprintf('Cannot write to directory "%s"', storage_path()));
+            }
+        }
+
+        return $tempDir;
+    }
+
+    /**
+     * 注册 PSR4 验证规则.
+     *
+     * @param string $directory
+     * @param array  $psr4
+     */
+    protected function registerPsr4($directory, array $psr4)
+    {
+        $classLoader = Admin::classLoader();
+
+        foreach ($psr4 as $namespace => $path) {
+            $path = $directory.'/'.trim($path, '/').'/';
+
+            $classLoader->addPsr4($namespace, $path);
+        }
+    }
+
+    /**
+     * 上报异常.
+     *
+     * @param \Throwable $e
+     */
+    protected function reportException(\Throwable $e)
+    {
+        Admin::reportException($e);
+    }
+
+    /**
+     * @param string $dir
+     *
+     * @return array
+     */
+    protected function scandir($dir)
+    {
+        $results = [];
+
+        foreach (scandir($dir) as $value) {
+            if (
+                $value !== '.'
+                && $value !== '..'
+                && is_dir($value = $dir.'/'.$value)
+            ) {
+                $results[] = $value;
+            }
+        }
+
+        return $results;
+    }
+}

+ 34 - 34
src/Extend/Note.php

@@ -1,34 +1,34 @@
-<?php
-
-namespace Dcat\Admin\Extend;
-
-use Symfony\Component\Console\Output\OutputInterface;
-
-trait Note
-{
-    /**
-     * @var \Symfony\Component\Console\Output\OutputInterface
-     */
-    public $output;
-
-    /**
-     * @var array
-     */
-    public $notes = [];
-
-    public function note($message)
-    {
-        if ($this->output instanceof OutputInterface) {
-            $this->output->writeln($message);
-        } else {
-            $this->notes[] = $message;
-        }
-    }
-
-    public function setOutPut($output)
-    {
-        $this->output = $output;
-
-        return $this;
-    }
-}
+<?php
+
+namespace Dcat\Admin\Extend;
+
+use Symfony\Component\Console\Output\OutputInterface;
+
+trait Note
+{
+    /**
+     * @var \Symfony\Component\Console\Output\OutputInterface
+     */
+    public $output;
+
+    /**
+     * @var array
+     */
+    public $notes = [];
+
+    public function note($message)
+    {
+        if ($this->output instanceof OutputInterface) {
+            $this->output->writeln($message);
+        } else {
+            $this->notes[] = $message;
+        }
+    }
+
+    public function setOutPut($output)
+    {
+        $this->output = $output;
+
+        return $this;
+    }
+}

+ 440 - 440
src/Extend/ServiceProvider.php

@@ -1,440 +1,440 @@
-<?php
-
-namespace Dcat\Admin\Extend;
-
-use Dcat\Admin\Admin;
-use Dcat\Admin\Exception\RuntimeException;
-use Dcat\Admin\Support\ComposerProperty;
-use Illuminate\Support\Arr;
-use Illuminate\Support\ServiceProvider as LaravelServiceProvider;
-use Symfony\Component\Console\Output\NullOutput;
-
-abstract class ServiceProvider extends LaravelServiceProvider
-{
-    const TYPE_THEME = 'theme';
-
-    /**
-     * @var ComposerProperty
-     */
-    public $composerProperty;
-
-    /**
-     * @var string
-     */
-    protected $name;
-
-    /**
-     * @var string
-     */
-    protected $packageName;
-
-    /**
-     * @var string
-     */
-    protected $type;
-
-    /**
-     * @var string
-     */
-    protected $path;
-
-    /**
-     * @var array
-     */
-    protected $js = [];
-
-    /**
-     * @var array
-     */
-    protected $css = [];
-
-    /**
-     * @var \Symfony\Component\Console\Output\OutputInterface
-     */
-    public $output;
-
-    /**
-     * @var array
-     */
-    protected $config;
-
-    public function __construct($app)
-    {
-        parent::__construct($app);
-
-        $this->output = new NullOutput();
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    final public function boot()
-    {
-        $this->autoRegister();
-
-        if ($this->disabled()) {
-            return;
-        }
-
-        $this->init();
-    }
-
-    /**
-     * 初始化操作.
-     *
-     * @return void
-     */
-    public function init()
-    {
-        if ($views = $this->getViewPath()) {
-            $this->loadViewsFrom($views, $this->getName());
-        }
-
-        if ($lang = $this->getLangPath()) {
-            $this->loadTranslationsFrom($lang, $this->getName());
-        }
-
-        if ($routes = $this->getRoutes()) {
-            $this->registerRoutes($routes);
-        }
-
-        $this->aliasAssets();
-    }
-
-    /**
-     * 自动注册扩展.
-     */
-    protected function autoRegister()
-    {
-        if (! $this->getName()) {
-            return;
-        }
-
-        Admin::extension()->addExtension($this);
-    }
-
-    /**
-     * 获取扩展名称.
-     *
-     * @return string|void
-     */
-    final public function getName()
-    {
-        return $this->name ?: ($this->name = str_replace('/', '.', $this->getPackageName()));
-    }
-
-    /**
-     * 获取包名.
-     *
-     * @return string|void
-     */
-    final public function getPackageName()
-    {
-        if (! $this->packageName) {
-            if (! $this->composerProperty) {
-                return;
-            }
-
-            $this->packageName = $this->composerProperty->name;
-        }
-
-        return $this->packageName;
-    }
-
-    /**
-     * 获取插件类型.
-     *
-     * @return string
-     */
-    public function getType()
-    {
-        return $this->type;
-    }
-
-    /**
-     * 获取当前已安装版本.
-     *
-     * @return string
-     */
-    final public function getVersion()
-    {
-        return Admin::extension()->versionManager()->getCurrentVersion($this);
-    }
-
-    /**
-     * 获取当前最新版本.
-     *
-     * @return string
-     */
-    final public function getLatestVersion()
-    {
-        return Admin::extension()->versionManager()->getFileVersions($this);
-    }
-
-    /**
-     * 获取当前本地最新版本.
-     *
-     * @return string
-     */
-    final public function getLocalLatestVersion()
-    {
-        return last(
-            array_keys(Admin::extension()->versionManager()->getFileVersions($this))
-        );
-    }
-
-    /**
-     * 获取扩展包路径.
-     *
-     * @param string $path
-     *
-     * @return string
-     *
-     * @throws \ReflectionException
-     */
-    public function path(?string $path = null)
-    {
-        if (! $this->path) {
-            $this->path = realpath(dirname((new \ReflectionClass(static::class))->getFileName()).'/..');
-
-            if (! is_dir($this->path)) {
-                throw new RuntimeException("The {$this->path} is not a directory.");
-            }
-        }
-
-        $path = ltrim($path, '/');
-
-        return $path ? $this->path.'/'.$path : $this->path;
-    }
-
-    /**
-     * 判断扩展是否启用.
-     *
-     * @return bool
-     */
-    final public function enabled()
-    {
-        return Admin::extension()->enabled($this->getName());
-    }
-
-    /**
-     * 判断扩展是否禁用.
-     *
-     * @return bool
-     */
-    final public function disabled()
-    {
-        return ! $this->enabled();
-    }
-
-    /**
-     * 获取或保存配置.
-     *
-     * @param string $key
-     * @param null   $default
-     *
-     * @return mixed
-     */
-    final public function config($key = null, $default = null)
-    {
-        if ($this->config === null) {
-            $this->config = Admin::setting()->get($this->getConfigKey());
-            $this->config = $this->config ? $this->unserializeConfig($this->config) : [];
-        }
-
-        if (is_array($key)) {
-            $this->config = array_merge($this->config, $key);
-
-            Admin::setting()->save([$this->getConfigKey() => $this->serializeConfig($this->config)]);
-
-            return;
-        }
-
-        if ($key === null) {
-            return $this->config;
-        }
-
-        return Arr::get($this->config, $key, $default);
-    }
-
-    /**
-     * 卸载扩展.
-     */
-    public function uninstall()
-    {
-    }
-
-    /**
-     * 发布静态资源.
-     */
-    public function publishable()
-    {
-        if ($assets = $this->getAssetPath()) {
-            $this->publishes([
-                $assets => $this->getPublishsPath(),
-            ], $this->getName());
-        }
-    }
-
-    /**
-     * 获取资源发布路径.
-     *
-     * @return string
-     */
-    protected function getPublishsPath()
-    {
-        return public_path(
-            Admin::asset()->getRealPath('@extension/'.str_replace('.', '/', $this->getName()))
-        );
-    }
-
-    /**
-     * 注册路由.
-     *
-     * @param $callback
-     */
-    public function registerRoutes($callback)
-    {
-        Admin::app()->routes(function ($router) use ($callback) {
-            $router->group([
-                'prefix'     => config('admin.route.prefix'),
-                'middleware' => config('admin.route.middleware'),
-            ], $callback);
-        });
-    }
-
-    /**
-     * 获取静态资源路径.
-     *
-     * @return string
-     */
-    final public function getAssetPath()
-    {
-        return $this->path('resources/assets');
-    }
-
-    /**
-     * 获取视图路径.
-     *
-     * @return string
-     */
-    final public function getViewPath()
-    {
-        return $this->path('resources/views');
-    }
-
-    /**
-     * 获取语言包路径.
-     *
-     * @return string
-     */
-    final public function getLangPath()
-    {
-        return $this->path('resources/lang');
-    }
-
-    /**
-     * 获取路由地址.
-     *
-     * @return string
-     *
-     * @throws \ReflectionException
-     */
-    final public function getRoutes()
-    {
-        $path = $this->path('src/Http/routes.php');
-
-        return is_file($path) ? $path : null;
-    }
-
-    /**
-     * @param ComposerProperty $composerProperty
-     *
-     * @return $this
-     */
-    public function withComposerProperty(ComposerProperty $composerProperty)
-    {
-        $this->composerProperty = $composerProperty;
-
-        return $this;
-    }
-
-    /**
-     * 获取或保存配置.
-     *
-     * @param string $key
-     * @param string $value
-     *
-     * @return mixed
-     */
-    public static function setting($key = null, $value = null)
-    {
-        $extension = app(static::class);
-
-        if ($extension && $extension instanceof ServiceProvider) {
-            return $extension->config($key, $value);
-        }
-    }
-
-    /**
-     * 注册别名.
-     */
-    protected function aliasAssets()
-    {
-        $asset = Admin::asset();
-
-        // 注册静态资源路径别名
-        $asset->alias($this->getName().'.path', '@extension/'.$this->getPackageName());
-
-        if ($this->js || $this->css) {
-            $asset->alias($this->getName(), [
-                'js'  => $this->formatAssetFiles($this->js),
-                'css' => $this->formatAssetFiles($this->css),
-            ]);
-        }
-    }
-
-    /**
-     * @param string|array $files
-     *
-     * @return mixed
-     */
-    protected function formatAssetFiles($files)
-    {
-        if (is_array($files)) {
-            return array_map([$this, 'formatAssetFiles'], $files);
-        }
-
-        return '@'.$this->getName().'.path/'.trim($files, '/');
-    }
-
-    /**
-     * 配置key.
-     *
-     * @return mixed
-     */
-    protected function getConfigKey()
-    {
-        return str_replace('.', ':', $this->getName());
-    }
-
-    /**
-     * @param $config
-     *
-     * @return false|string
-     */
-    protected function serializeConfig($config)
-    {
-        return json_encode($config);
-    }
-
-    /**
-     * @param $config
-     *
-     * @return array
-     */
-    protected function unserializeConfig($config)
-    {
-        return json_decode($config, true);
-    }
-}
+<?php
+
+namespace Dcat\Admin\Extend;
+
+use Dcat\Admin\Admin;
+use Dcat\Admin\Exception\RuntimeException;
+use Dcat\Admin\Support\ComposerProperty;
+use Illuminate\Support\Arr;
+use Illuminate\Support\ServiceProvider as LaravelServiceProvider;
+use Symfony\Component\Console\Output\NullOutput;
+
+abstract class ServiceProvider extends LaravelServiceProvider
+{
+    const TYPE_THEME = 'theme';
+
+    /**
+     * @var ComposerProperty
+     */
+    public $composerProperty;
+
+    /**
+     * @var string
+     */
+    protected $name;
+
+    /**
+     * @var string
+     */
+    protected $packageName;
+
+    /**
+     * @var string
+     */
+    protected $type;
+
+    /**
+     * @var string
+     */
+    protected $path;
+
+    /**
+     * @var array
+     */
+    protected $js = [];
+
+    /**
+     * @var array
+     */
+    protected $css = [];
+
+    /**
+     * @var \Symfony\Component\Console\Output\OutputInterface
+     */
+    public $output;
+
+    /**
+     * @var array
+     */
+    protected $config;
+
+    public function __construct($app)
+    {
+        parent::__construct($app);
+
+        $this->output = new NullOutput();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    final public function boot()
+    {
+        $this->autoRegister();
+
+        if ($this->disabled()) {
+            return;
+        }
+
+        $this->init();
+    }
+
+    /**
+     * 初始化操作.
+     *
+     * @return void
+     */
+    public function init()
+    {
+        if ($views = $this->getViewPath()) {
+            $this->loadViewsFrom($views, $this->getName());
+        }
+
+        if ($lang = $this->getLangPath()) {
+            $this->loadTranslationsFrom($lang, $this->getName());
+        }
+
+        if ($routes = $this->getRoutes()) {
+            $this->registerRoutes($routes);
+        }
+
+        $this->aliasAssets();
+    }
+
+    /**
+     * 自动注册扩展.
+     */
+    protected function autoRegister()
+    {
+        if (! $this->getName()) {
+            return;
+        }
+
+        Admin::extension()->addExtension($this);
+    }
+
+    /**
+     * 获取扩展名称.
+     *
+     * @return string|void
+     */
+    final public function getName()
+    {
+        return $this->name ?: ($this->name = str_replace('/', '.', $this->getPackageName()));
+    }
+
+    /**
+     * 获取包名.
+     *
+     * @return string|void
+     */
+    final public function getPackageName()
+    {
+        if (! $this->packageName) {
+            if (! $this->composerProperty) {
+                return;
+            }
+
+            $this->packageName = $this->composerProperty->name;
+        }
+
+        return $this->packageName;
+    }
+
+    /**
+     * 获取插件类型.
+     *
+     * @return string
+     */
+    public function getType()
+    {
+        return $this->type;
+    }
+
+    /**
+     * 获取当前已安装版本.
+     *
+     * @return string
+     */
+    final public function getVersion()
+    {
+        return Admin::extension()->versionManager()->getCurrentVersion($this);
+    }
+
+    /**
+     * 获取当前最新版本.
+     *
+     * @return string
+     */
+    final public function getLatestVersion()
+    {
+        return Admin::extension()->versionManager()->getFileVersions($this);
+    }
+
+    /**
+     * 获取当前本地最新版本.
+     *
+     * @return string
+     */
+    final public function getLocalLatestVersion()
+    {
+        return last(
+            array_keys(Admin::extension()->versionManager()->getFileVersions($this))
+        );
+    }
+
+    /**
+     * 获取扩展包路径.
+     *
+     * @param string $path
+     *
+     * @return string
+     *
+     * @throws \ReflectionException
+     */
+    public function path(?string $path = null)
+    {
+        if (! $this->path) {
+            $this->path = realpath(dirname((new \ReflectionClass(static::class))->getFileName()).'/..');
+
+            if (! is_dir($this->path)) {
+                throw new RuntimeException("The {$this->path} is not a directory.");
+            }
+        }
+
+        $path = ltrim($path, '/');
+
+        return $path ? $this->path.'/'.$path : $this->path;
+    }
+
+    /**
+     * 判断扩展是否启用.
+     *
+     * @return bool
+     */
+    final public function enabled()
+    {
+        return Admin::extension()->enabled($this->getName());
+    }
+
+    /**
+     * 判断扩展是否禁用.
+     *
+     * @return bool
+     */
+    final public function disabled()
+    {
+        return ! $this->enabled();
+    }
+
+    /**
+     * 获取或保存配置.
+     *
+     * @param string $key
+     * @param null   $default
+     *
+     * @return mixed
+     */
+    final public function config($key = null, $default = null)
+    {
+        if ($this->config === null) {
+            $this->config = Admin::setting()->get($this->getConfigKey());
+            $this->config = $this->config ? $this->unserializeConfig($this->config) : [];
+        }
+
+        if (is_array($key)) {
+            $this->config = array_merge($this->config, $key);
+
+            Admin::setting()->save([$this->getConfigKey() => $this->serializeConfig($this->config)]);
+
+            return;
+        }
+
+        if ($key === null) {
+            return $this->config;
+        }
+
+        return Arr::get($this->config, $key, $default);
+    }
+
+    /**
+     * 卸载扩展.
+     */
+    public function uninstall()
+    {
+    }
+
+    /**
+     * 发布静态资源.
+     */
+    public function publishable()
+    {
+        if ($assets = $this->getAssetPath()) {
+            $this->publishes([
+                $assets => $this->getPublishsPath(),
+            ], $this->getName());
+        }
+    }
+
+    /**
+     * 获取资源发布路径.
+     *
+     * @return string
+     */
+    protected function getPublishsPath()
+    {
+        return public_path(
+            Admin::asset()->getRealPath('@extension/'.str_replace('.', '/', $this->getName()))
+        );
+    }
+
+    /**
+     * 注册路由.
+     *
+     * @param $callback
+     */
+    public function registerRoutes($callback)
+    {
+        Admin::app()->routes(function ($router) use ($callback) {
+            $router->group([
+                'prefix'     => config('admin.route.prefix'),
+                'middleware' => config('admin.route.middleware'),
+            ], $callback);
+        });
+    }
+
+    /**
+     * 获取静态资源路径.
+     *
+     * @return string
+     */
+    final public function getAssetPath()
+    {
+        return $this->path('resources/assets');
+    }
+
+    /**
+     * 获取视图路径.
+     *
+     * @return string
+     */
+    final public function getViewPath()
+    {
+        return $this->path('resources/views');
+    }
+
+    /**
+     * 获取语言包路径.
+     *
+     * @return string
+     */
+    final public function getLangPath()
+    {
+        return $this->path('resources/lang');
+    }
+
+    /**
+     * 获取路由地址.
+     *
+     * @return string
+     *
+     * @throws \ReflectionException
+     */
+    final public function getRoutes()
+    {
+        $path = $this->path('src/Http/routes.php');
+
+        return is_file($path) ? $path : null;
+    }
+
+    /**
+     * @param ComposerProperty $composerProperty
+     *
+     * @return $this
+     */
+    public function withComposerProperty(ComposerProperty $composerProperty)
+    {
+        $this->composerProperty = $composerProperty;
+
+        return $this;
+    }
+
+    /**
+     * 获取或保存配置.
+     *
+     * @param string $key
+     * @param string $value
+     *
+     * @return mixed
+     */
+    public static function setting($key = null, $value = null)
+    {
+        $extension = app(static::class);
+
+        if ($extension && $extension instanceof ServiceProvider) {
+            return $extension->config($key, $value);
+        }
+    }
+
+    /**
+     * 注册别名.
+     */
+    protected function aliasAssets()
+    {
+        $asset = Admin::asset();
+
+        // 注册静态资源路径别名
+        $asset->alias($this->getName().'.path', '@extension/'.$this->getPackageName());
+
+        if ($this->js || $this->css) {
+            $asset->alias($this->getName(), [
+                'js'  => $this->formatAssetFiles($this->js),
+                'css' => $this->formatAssetFiles($this->css),
+            ]);
+        }
+    }
+
+    /**
+     * @param string|array $files
+     *
+     * @return mixed
+     */
+    protected function formatAssetFiles($files)
+    {
+        if (is_array($files)) {
+            return array_map([$this, 'formatAssetFiles'], $files);
+        }
+
+        return '@'.$this->getName().'.path/'.trim($files, '/');
+    }
+
+    /**
+     * 配置key.
+     *
+     * @return mixed
+     */
+    protected function getConfigKey()
+    {
+        return str_replace('.', ':', $this->getName());
+    }
+
+    /**
+     * @param $config
+     *
+     * @return false|string
+     */
+    protected function serializeConfig($config)
+    {
+        return json_encode($config);
+    }
+
+    /**
+     * @param $config
+     *
+     * @return array
+     */
+    protected function unserializeConfig($config)
+    {
+        return json_decode($config, true);
+    }
+}

+ 89 - 89
src/Extend/Setting.php

@@ -1,89 +1,89 @@
-<?php
-
-namespace Dcat\Admin\Extend;
-
-use Dcat\Admin\Admin;
-use Dcat\Admin\Contracts\LazyRenderable;
-use Dcat\Admin\Traits\LazyWidget;
-use Dcat\Admin\Widgets\Form;
-
-abstract class Setting extends Form implements LazyRenderable
-{
-    use LazyWidget;
-
-    /**
-     * @var ServiceProvider
-     */
-    protected $extension;
-
-    public function __construct(ServiceProvider $extension = null)
-    {
-        parent::__construct();
-
-        $this->initExtension($extension);
-    }
-
-    protected function initExtension(?ServiceProvider $extension)
-    {
-        if ($extension) {
-            $this->extension = $extension;
-
-            $this->payload(['_extension_' => $extension->getName()]);
-        }
-    }
-
-    /**
-     * 处理请求.
-     *
-     * @param array $input
-     *
-     * @return \Dcat\Admin\Http\JsonResponse
-     */
-    public function handle(array $input)
-    {
-        $this->extension()->config($this->formatInput($input));
-
-        return $this->response()->success(trans('admin.save_succeeded'));
-    }
-
-    /**
-     * 格式化配置信息.
-     *
-     * @param array $input
-     *
-     * @return array
-     */
-    protected function formatInput(array $input)
-    {
-        return $input;
-    }
-
-    /**
-     * 表单字段定义.
-     *
-     * @return void
-     */
-    abstract public function form();
-
-    /**
-     * 填充表单数据.
-     *
-     * @return array
-     */
-    public function default()
-    {
-        return $this->extension()->config() ?: [];
-    }
-
-    /**
-     * @return ServiceProvider
-     */
-    public function extension()
-    {
-        if (! empty($this->payload['_extension_'])) {
-            return Admin::extension()->get($this->payload['_extension_']);
-        }
-
-        return $this->extension;
-    }
-}
+<?php
+
+namespace Dcat\Admin\Extend;
+
+use Dcat\Admin\Admin;
+use Dcat\Admin\Contracts\LazyRenderable;
+use Dcat\Admin\Traits\LazyWidget;
+use Dcat\Admin\Widgets\Form;
+
+abstract class Setting extends Form implements LazyRenderable
+{
+    use LazyWidget;
+
+    /**
+     * @var ServiceProvider
+     */
+    protected $extension;
+
+    public function __construct(ServiceProvider $extension = null)
+    {
+        parent::__construct();
+
+        $this->initExtension($extension);
+    }
+
+    protected function initExtension(?ServiceProvider $extension)
+    {
+        if ($extension) {
+            $this->extension = $extension;
+
+            $this->payload(['_extension_' => $extension->getName()]);
+        }
+    }
+
+    /**
+     * 处理请求.
+     *
+     * @param array $input
+     *
+     * @return \Dcat\Admin\Http\JsonResponse
+     */
+    public function handle(array $input)
+    {
+        $this->extension()->config($this->formatInput($input));
+
+        return $this->response()->success(trans('admin.save_succeeded'));
+    }
+
+    /**
+     * 格式化配置信息.
+     *
+     * @param array $input
+     *
+     * @return array
+     */
+    protected function formatInput(array $input)
+    {
+        return $input;
+    }
+
+    /**
+     * 表单字段定义.
+     *
+     * @return void
+     */
+    abstract public function form();
+
+    /**
+     * 填充表单数据.
+     *
+     * @return array
+     */
+    public function default()
+    {
+        return $this->extension()->config() ?: [];
+    }
+
+    /**
+     * @return ServiceProvider
+     */
+    public function extension()
+    {
+        if (! empty($this->payload['_extension_'])) {
+            return Admin::extension()->get($this->payload['_extension_']);
+        }
+
+        return $this->extension;
+    }
+}

+ 117 - 118
src/Extend/UpdateManager.php

@@ -1,118 +1,117 @@
-<?php
-
-namespace Dcat\Admin\Extend;
-
-use Dcat\Admin\Exception\AdminException;
-use Illuminate\Support\Facades\Artisan;
-use Illuminate\Support\Facades\Lang;
-
-/**
- * Class UpdateManager
- *
- * @see https://github.com/octobercms/october/blob/develop/modules/system/classes/UpdateManager.php
- */
-class UpdateManager
-{
-    use Note;
-
-    /**
-     * @var Manager
-     */
-    protected $manager;
-
-    /**
-     * @var VersionManager
-     */
-    protected $versionManager;
-
-    public function __construct(Manager $manager)
-    {
-        $this->manager = $manager;
-        $this->versionManager = $manager->versionManager();
-    }
-
-    public function install($extension)
-    {
-        return $this->update($extension);
-    }
-    
-    public function uninstall($extension)
-    {
-        return $this->rollback($extension);
-    }
-
-    public function rollback($name, ?string $stopOnVersion = null)
-    {
-        if (
-            ! ($extension = $this->manager->get($name))
-            && $this->versionManager->purge($name)
-        ) {
-            $this->note('<info>Purged from database:</info> ' . $name);
-
-            return $this;
-        }
-
-        if ($stopOnVersion && ! $this->versionManager->hasDatabaseVersion($extension, $stopOnVersion)) {
-            throw new AdminException('Extension version not found');
-        }
-
-        if ($this->versionManager->remove($extension, $stopOnVersion, true)) {
-            $this->note('<info>Rolled back:</info> ' . $name);
-
-            if ($currentVersion = $this->versionManager->getCurrentVersion($extension)) {
-                $this->note('<info>Current Version:</info> '.$currentVersion.' ('.$this->versionManager->getCurrentVersionNote($extension).')');
-            }
-
-            return $this;
-        }
-
-        $this->note('<error>Unable to find:</error> '.$name);
-
-        return $this;
-    }
-
-    public function update($name, ?string $stopOnVersion = null)
-    {
-        $name = $this->manager->getName($name);
-
-        if (! ($extension = $this->manager->get($name))) {
-            $this->note('<error>Unable to find:</error> '.$name);
-
-            return;
-        }
-
-        $this->note($name);
-
-        $this->versionUpdate($extension, $stopOnVersion);
-
-        $this->publish($name);
-
-        return $this;
-    }
-
-    /**
-     * 发布扩展资源.
-     *
-     * @param string $name
-     */
-    public function publish($name)
-    {
-        $name = $this->manager->getName($name);
-
-        $this->manager->get($name)->publishable();
-
-        Artisan::call('vendor:publish', ['--force' => true, '--tag' => $name]);
-    }
-
-    protected function versionUpdate($extension, $stopOnVersion)
-    {
-        $this->versionManager->notes = [];
-        $this->versionManager->output = $this->output;
-
-        if ($this->versionManager->update($extension, $stopOnVersion) !== false) {
-            foreach ($this->versionManager->notes as $note) {
-                $this->note($note);
-            }
-        }
-    }
-}
+<?php
+
+namespace Dcat\Admin\Extend;
+
+use Dcat\Admin\Exception\AdminException;
+use Illuminate\Support\Facades\Artisan;
+
+/**
+ * Class UpdateManager.
+ *
+ * @see https://github.com/octobercms/october/blob/develop/modules/system/classes/UpdateManager.php
+ */
+class UpdateManager
+{
+    use Note;
+
+    /**
+     * @var Manager
+     */
+    protected $manager;
+
+    /**
+     * @var VersionManager
+     */
+    protected $versionManager;
+
+    public function __construct(Manager $manager)
+    {
+        $this->manager = $manager;
+        $this->versionManager = $manager->versionManager();
+    }
+
+    public function install($extension)
+    {
+        return $this->update($extension);
+    }
+
+    public function uninstall($extension)
+    {
+        return $this->rollback($extension);
+    }
+
+    public function rollback($name, ?string $stopOnVersion = null)
+    {
+        if (
+            ! ($extension = $this->manager->get($name))
+            && $this->versionManager->purge($name)
+        ) {
+            $this->note('<info>Purged from database:</info> '.$name);
+
+            return $this;
+        }
+
+        if ($stopOnVersion && ! $this->versionManager->hasDatabaseVersion($extension, $stopOnVersion)) {
+            throw new AdminException('Extension version not found');
+        }
+
+        if ($this->versionManager->remove($extension, $stopOnVersion, true)) {
+            $this->note('<info>Rolled back:</info> '.$name);
+
+            if ($currentVersion = $this->versionManager->getCurrentVersion($extension)) {
+                $this->note('<info>Current Version:</info> '.$currentVersion.' ('.$this->versionManager->getCurrentVersionNote($extension).')');
+            }
+
+            return $this;
+        }
+
+        $this->note('<error>Unable to find:</error> '.$name);
+
+        return $this;
+    }
+
+    public function update($name, ?string $stopOnVersion = null)
+    {
+        $name = $this->manager->getName($name);
+
+        if (! ($extension = $this->manager->get($name))) {
+            $this->note('<error>Unable to find:</error> '.$name);
+
+            return;
+        }
+
+        $this->note($name);
+
+        $this->versionUpdate($extension, $stopOnVersion);
+
+        $this->publish($name);
+
+        return $this;
+    }
+
+    /**
+     * 发布扩展资源.
+     *
+     * @param string $name
+     */
+    public function publish($name)
+    {
+        $name = $this->manager->getName($name);
+
+        $this->manager->get($name)->publishable();
+
+        Artisan::call('vendor:publish', ['--force' => true, '--tag' => $name]);
+    }
+
+    protected function versionUpdate($extension, $stopOnVersion)
+    {
+        $this->versionManager->notes = [];
+        $this->versionManager->output = $this->output;
+
+        if ($this->versionManager->update($extension, $stopOnVersion) !== false) {
+            foreach ($this->versionManager->notes as $note) {
+                $this->note($note);
+            }
+        }
+    }
+}

+ 432 - 431
src/Extend/VersionManager.php

@@ -1,431 +1,432 @@
-<?php
-
-namespace Dcat\Admin\Extend;
-
-use Dcat\Admin\Models\Extension;
-use Dcat\Admin\Models\ExtensionHistory;
-use Carbon\Carbon;
-use Dcat\Admin\Support\DatabaseUpdater;
-use Illuminate\Support\Arr;
-
-/**
- * Class VersionManager
- *
- * @see https://github.com/octobercms/october/blob/develop/modules/system/classes/VersionManager.php
- */
-class VersionManager
-{
-    use Note;
-
-    const NO_VERSION_VALUE = 0;
-
-    const HISTORY_TYPE_COMMENT = 1;
-    const HISTORY_TYPE_SCRIPT = 2;
-
-    protected $fileVersions;
-    protected $databaseVersions;
-    protected $databaseHistory;
-    protected $updater;
-    protected $manager;
-
-    public function __construct(Manager $manager)
-    {
-        $this->manager = $manager;
-        $this->updater = new DatabaseUpdater();
-    }
-
-    public function update($extension, $stopOnVersion = null)
-    {
-        $name = $this->manager->getName($extension);
-
-        if (! $this->hasVersionFile($name)) {
-            return false;
-        }
-
-        $currentVersion = $this->getLatestFileVersion($name);
-        $databaseVersion = $this->getDatabaseVersion($name);
-
-        if ($currentVersion === $databaseVersion) {
-            $this->note('- <info>Nothing to update.</info>');
-
-            return;
-        }
-
-        $newUpdates = $this->getNewFileVersions($name, $databaseVersion);
-
-        foreach ($newUpdates as $version => $details) {
-            $this->applyExtensionUpdate($name, $version, $details);
-
-            if ($stopOnVersion === $version) {
-                return true;
-            }
-        }
-
-        return true;
-    }
-
-    public function listNewVersions($extension)
-    {
-        $name = $this->manager->getName($extension);
-
-        if (!$this->hasVersionFile($name)) {
-            return [];
-        }
-
-        return $this->getNewFileVersions($name, $this->getDatabaseVersion($name));
-    }
-
-    protected function applyExtensionUpdate($name, $version, $details)
-    {
-        [$comments, $scripts] = $this->extractScriptsAndComments($details);
-
-        foreach ($scripts as $script) {
-            if ($this->hasDatabaseHistory($name, $version, $script)) {
-                continue;
-            }
-
-            $this->applyDatabaseScript($name, $version, $script);
-        }
-
-        if (! $this->hasDatabaseHistory($name, $version)) {
-            foreach ($comments as $comment) {
-                $this->applyDatabaseComment($name, $version, $comment);
-
-                $this->note(sprintf('- <info>v%s: </info> %s', $version, $comment));
-            }
-        }
-
-        $this->setDatabaseVersion($name, $version);
-    }
-
-    public function remove($extension, $stopOnVersion = null, $stopCurrentVersion = false)
-    {
-        $name = $this->manager->getName($extension);
-
-        if (! $this->hasVersionFile($name)) {
-            return false;
-        }
-
-        $extensionHistory = $this->getDatabaseHistory($name);
-        $extensionHistory = array_reverse($extensionHistory);
-
-        $stopOnNextVersion = false;
-        $newExtensionVersion = null;
-
-        try {
-            foreach ($extensionHistory as $history) {
-                if ($stopCurrentVersion && $stopOnVersion === $history->version) {
-                    $newExtensionVersion = $history->version;
-
-                    break;
-                }
-
-                if ($stopOnNextVersion && $history->version !== $stopOnVersion) {
-                    $newExtensionVersion = $history->version;
-
-                    break;
-                }
-
-                if ($history->type == static::HISTORY_TYPE_COMMENT) {
-                    $this->removeDatabaseComment($name, $history->version);
-                } elseif ($history->type == static::HISTORY_TYPE_SCRIPT) {
-                    $this->removeDatabaseScript($name, $history->version, $history->detail);
-                }
-
-                if ($stopOnVersion === $history->version) {
-                    $stopOnNextVersion = true;
-                }
-            }
-        } catch (\Throwable $exception) {
-            $lastHistory = $this->getLastHistory($name);
-            if ($lastHistory) {
-                $this->setDatabaseVersion($name, $lastHistory->version);
-            }
-            throw $exception;
-        }
-
-        $this->setDatabaseVersion($name, $newExtensionVersion);
-
-        if (isset($this->fileVersions[$name])) {
-            unset($this->fileVersions[$name]);
-        }
-
-        if (isset($this->databaseVersions[$name])) {
-            unset($this->databaseVersions[$name]);
-        }
-
-        if (isset($this->databaseHistory[$name])) {
-            unset($this->databaseHistory[$name]);
-        }
-        return true;
-    }
-
-    public function purge($name)
-    {
-        $name = $this->manager->getName($name);
-
-        $versions = Extension::query()->where('name', $name);
-
-        if ($countVersions = $versions->count()) {
-            $versions->delete();
-        }
-
-        $history = ExtensionHistory::query()->where('name', $name);
-
-        if ($countHistory = $history->count()) {
-            $history->delete();
-        }
-
-        return $countHistory + $countVersions;
-    }
-
-    protected function getLatestFileVersion($name)
-    {
-        $versionInfo = $this->getFileVersions($name);
-        if (! $versionInfo) {
-            return static::NO_VERSION_VALUE;
-        }
-
-        return trim(key(array_slice($versionInfo, -1, 1)));
-    }
-
-    public function getNewFileVersions($name, $version = null)
-    {
-        $name = $this->manager->getName($name);
-
-        if ($version === null) {
-            $version = static::NO_VERSION_VALUE;
-        }
-
-        $versions = $this->getFileVersions($name);
-
-        $position = array_search($version, array_keys($versions));
-
-        return array_slice($versions, ++$position);
-    }
-
-    public function getFileVersions($name)
-    {
-        $name = $this->manager->getName($name);
-
-        if ($this->fileVersions !== null && array_key_exists($name, $this->fileVersions)) {
-            return $this->fileVersions[$name];
-        }
-
-        $versionInfo = (array) $this->parseVersionFile($this->getVersionFile($name));
-
-        if ($versionInfo) {
-            uksort($versionInfo, function ($a, $b) {
-                return version_compare($a, $b);
-            });
-        }
-
-        return $this->fileVersions[$name] = $versionInfo;
-    }
-
-    protected function parseVersionFile($file)
-    {
-        if ($file && is_file($file)) {
-            return include $file;
-        }
-    }
-
-    protected function getVersionFile($name)
-    {
-        return $this->manager->path($name, 'version.php');
-    }
-
-    protected function hasVersionFile($name)
-    {
-        $versionFile = $this->getVersionFile($name);
-
-        return $versionFile && is_file($versionFile);
-    }
-
-    protected function getDatabaseVersion($name)
-    {
-        if ($this->databaseVersions === null) {
-            $this->databaseVersions = Extension::query()->pluck('version', 'name');
-        }
-
-        if (! isset($this->databaseVersions[$name])) {
-            $this->databaseVersions[$name] =
-                Extension::query()
-                ->where('name', $name)
-                ->value('version');
-        }
-
-        return $this->databaseVersions[$name] ?? static::NO_VERSION_VALUE;
-    }
-
-    protected function setDatabaseVersion($name, $version = null)
-    {
-        $currentVersion = $this->getDatabaseVersion($name);
-
-        if ($version && ! $currentVersion) {
-            Extension::query()->create([
-                'name'    => $name,
-                'version' => $version,
-            ]);
-        } elseif ($version && $currentVersion) {
-            Extension::query()->where('name', $name)->update([
-                'version'    => $version,
-                'updated_at' => new Carbon
-            ]);
-        } elseif ($currentVersion) {
-            Extension::query()->where('name', $name)->delete();
-        }
-
-        $this->databaseVersions[$name] = $version;
-    }
-
-    protected function applyDatabaseComment($name, $version, $comment)
-    {
-        ExtensionHistory::query()->create([
-            'name'    => $name,
-            'type'    => static::HISTORY_TYPE_COMMENT,
-            'version' => $version,
-            'detail'  => $comment,
-        ]);
-    }
-
-    protected function removeDatabaseComment($name, $version)
-    {
-        ExtensionHistory::query()
-            ->where('name', $name)
-            ->where('type', static::HISTORY_TYPE_COMMENT)
-            ->where('version', $version)
-            ->delete();
-    }
-
-    protected function applyDatabaseScript($name, $version, $script)
-    {
-        $updateFile = $this->manager->path($name, 'updates/'.$script);
-
-        if (! is_file($updateFile)) {
-            $this->note('- <error>v'.$version.':  Migration file "'.$script.'" not found</error>');
-
-            return;
-        }
-
-        $this->updater->setUp($updateFile, function () use ($name, $version, $script) {
-            ExtensionHistory::query()->create([
-                'name'    => $name,
-                'type'    => static::HISTORY_TYPE_SCRIPT,
-                'version' => $version,
-                'detail'  => $script,
-            ]);
-        });
-    }
-
-    protected function removeDatabaseScript($name, $version, $script)
-    {
-        $updateFile = $this->manager->path($name, 'updates/'.$script);
-
-        $this->updater->packDown($updateFile, function () use ($name, $version, $script) {
-            ExtensionHistory::query()
-                ->where('name', $name)
-                ->where('type', static::HISTORY_TYPE_SCRIPT)
-                ->where('version', $version)
-                ->where('detail', $script)
-                ->delete();
-        });
-    }
-
-    protected function getDatabaseHistory($name)
-    {
-        if ($this->databaseHistory !== null && array_key_exists($name, $this->databaseHistory)) {
-            return $this->databaseHistory[$name];
-        }
-
-        $historyInfo = ExtensionHistory::query()
-            ->where('name', $name)
-            ->orderBy('id')
-            ->get()
-            ->all();
-
-        return $this->databaseHistory[$name] = $historyInfo;
-    }
-
-    protected function getLastHistory($name)
-    {
-        return ExtensionHistory::query()
-            ->where('name', $name)
-            ->orderByDesc('id')
-            ->first();
-    }
-
-    protected function hasDatabaseHistory($name, $version, $script = null)
-    {
-        $historyInfo = $this->getDatabaseHistory($name);
-        if (! $historyInfo) {
-            return false;
-        }
-
-        foreach ($historyInfo as $history) {
-            if ($history->version != $version) {
-                continue;
-            }
-
-            if ($history->type == static::HISTORY_TYPE_COMMENT && ! $script) {
-                return true;
-            }
-
-            if ($history->type == static::HISTORY_TYPE_SCRIPT && $history->detail == $script) {
-                return true;
-            }
-        }
-
-        return false;
-    }
-
-    protected function extractScriptsAndComments($details): array
-    {
-        $details = (array) $details;
-
-        $fileNamePattern = "/^[a-z0-9\_\-\.\/\\\]+\.php$/i";
-
-        $comments = array_values(array_filter($details, function ($detail) use ($fileNamePattern) {
-            return ! preg_match($fileNamePattern, $detail);
-        }));
-
-        $scripts = array_values(array_filter($details, function ($detail) use ($fileNamePattern) {
-            return preg_match($fileNamePattern, $detail);
-        }));
-
-        return [$comments, $scripts];
-    }
-
-    public function getCurrentVersion($extension): string
-    {
-        return $this->getDatabaseVersion($this->manager->getName($extension));
-    }
-
-    public function hasDatabaseVersion($extension, string $version): bool
-    {
-        $name = $this->manager->getName($extension);
-
-        $histories = $this->getDatabaseHistory($name);
-
-        foreach ($histories as $history) {
-            if ($history->version === $version) {
-                return true;
-            }
-        }
-
-        return false;
-    }
-
-    public function getCurrentVersionNote($extension): string
-    {
-        $name = $this->manager->getName($extension);
-
-        $histories = $this->getDatabaseHistory($name);
-
-        $lastHistory = Arr::last(Arr::where($histories, function ($history) {
-            return $history->type === static::HISTORY_TYPE_COMMENT;
-        }));
-
-        return $lastHistory ? $lastHistory->detail : '';
-    }
-}
+<?php
+
+namespace Dcat\Admin\Extend;
+
+use Carbon\Carbon;
+use Dcat\Admin\Models\Extension;
+use Dcat\Admin\Models\ExtensionHistory;
+use Dcat\Admin\Support\DatabaseUpdater;
+use Illuminate\Support\Arr;
+
+/**
+ * Class VersionManager.
+ *
+ * @see https://github.com/octobercms/october/blob/develop/modules/system/classes/VersionManager.php
+ */
+class VersionManager
+{
+    use Note;
+
+    const NO_VERSION_VALUE = 0;
+
+    const HISTORY_TYPE_COMMENT = 1;
+    const HISTORY_TYPE_SCRIPT = 2;
+
+    protected $fileVersions;
+    protected $databaseVersions;
+    protected $databaseHistory;
+    protected $updater;
+    protected $manager;
+
+    public function __construct(Manager $manager)
+    {
+        $this->manager = $manager;
+        $this->updater = new DatabaseUpdater();
+    }
+
+    public function update($extension, $stopOnVersion = null)
+    {
+        $name = $this->manager->getName($extension);
+
+        if (! $this->hasVersionFile($name)) {
+            return false;
+        }
+
+        $currentVersion = $this->getLatestFileVersion($name);
+        $databaseVersion = $this->getDatabaseVersion($name);
+
+        if ($currentVersion === $databaseVersion) {
+            $this->note('- <info>Nothing to update.</info>');
+
+            return;
+        }
+
+        $newUpdates = $this->getNewFileVersions($name, $databaseVersion);
+
+        foreach ($newUpdates as $version => $details) {
+            $this->applyExtensionUpdate($name, $version, $details);
+
+            if ($stopOnVersion === $version) {
+                return true;
+            }
+        }
+
+        return true;
+    }
+
+    public function listNewVersions($extension)
+    {
+        $name = $this->manager->getName($extension);
+
+        if (! $this->hasVersionFile($name)) {
+            return [];
+        }
+
+        return $this->getNewFileVersions($name, $this->getDatabaseVersion($name));
+    }
+
+    protected function applyExtensionUpdate($name, $version, $details)
+    {
+        [$comments, $scripts] = $this->extractScriptsAndComments($details);
+
+        foreach ($scripts as $script) {
+            if ($this->hasDatabaseHistory($name, $version, $script)) {
+                continue;
+            }
+
+            $this->applyDatabaseScript($name, $version, $script);
+        }
+
+        if (! $this->hasDatabaseHistory($name, $version)) {
+            foreach ($comments as $comment) {
+                $this->applyDatabaseComment($name, $version, $comment);
+
+                $this->note(sprintf('- <info>v%s: </info> %s', $version, $comment));
+            }
+        }
+
+        $this->setDatabaseVersion($name, $version);
+    }
+
+    public function remove($extension, $stopOnVersion = null, $stopCurrentVersion = false)
+    {
+        $name = $this->manager->getName($extension);
+
+        if (! $this->hasVersionFile($name)) {
+            return false;
+        }
+
+        $extensionHistory = $this->getDatabaseHistory($name);
+        $extensionHistory = array_reverse($extensionHistory);
+
+        $stopOnNextVersion = false;
+        $newExtensionVersion = null;
+
+        try {
+            foreach ($extensionHistory as $history) {
+                if ($stopCurrentVersion && $stopOnVersion === $history->version) {
+                    $newExtensionVersion = $history->version;
+
+                    break;
+                }
+
+                if ($stopOnNextVersion && $history->version !== $stopOnVersion) {
+                    $newExtensionVersion = $history->version;
+
+                    break;
+                }
+
+                if ($history->type == static::HISTORY_TYPE_COMMENT) {
+                    $this->removeDatabaseComment($name, $history->version);
+                } elseif ($history->type == static::HISTORY_TYPE_SCRIPT) {
+                    $this->removeDatabaseScript($name, $history->version, $history->detail);
+                }
+
+                if ($stopOnVersion === $history->version) {
+                    $stopOnNextVersion = true;
+                }
+            }
+        } catch (\Throwable $exception) {
+            $lastHistory = $this->getLastHistory($name);
+            if ($lastHistory) {
+                $this->setDatabaseVersion($name, $lastHistory->version);
+            }
+            throw $exception;
+        }
+
+        $this->setDatabaseVersion($name, $newExtensionVersion);
+
+        if (isset($this->fileVersions[$name])) {
+            unset($this->fileVersions[$name]);
+        }
+
+        if (isset($this->databaseVersions[$name])) {
+            unset($this->databaseVersions[$name]);
+        }
+
+        if (isset($this->databaseHistory[$name])) {
+            unset($this->databaseHistory[$name]);
+        }
+
+        return true;
+    }
+
+    public function purge($name)
+    {
+        $name = $this->manager->getName($name);
+
+        $versions = Extension::query()->where('name', $name);
+
+        if ($countVersions = $versions->count()) {
+            $versions->delete();
+        }
+
+        $history = ExtensionHistory::query()->where('name', $name);
+
+        if ($countHistory = $history->count()) {
+            $history->delete();
+        }
+
+        return $countHistory + $countVersions;
+    }
+
+    protected function getLatestFileVersion($name)
+    {
+        $versionInfo = $this->getFileVersions($name);
+        if (! $versionInfo) {
+            return static::NO_VERSION_VALUE;
+        }
+
+        return trim(key(array_slice($versionInfo, -1, 1)));
+    }
+
+    public function getNewFileVersions($name, $version = null)
+    {
+        $name = $this->manager->getName($name);
+
+        if ($version === null) {
+            $version = static::NO_VERSION_VALUE;
+        }
+
+        $versions = $this->getFileVersions($name);
+
+        $position = array_search($version, array_keys($versions));
+
+        return array_slice($versions, ++$position);
+    }
+
+    public function getFileVersions($name)
+    {
+        $name = $this->manager->getName($name);
+
+        if ($this->fileVersions !== null && array_key_exists($name, $this->fileVersions)) {
+            return $this->fileVersions[$name];
+        }
+
+        $versionInfo = (array) $this->parseVersionFile($this->getVersionFile($name));
+
+        if ($versionInfo) {
+            uksort($versionInfo, function ($a, $b) {
+                return version_compare($a, $b);
+            });
+        }
+
+        return $this->fileVersions[$name] = $versionInfo;
+    }
+
+    protected function parseVersionFile($file)
+    {
+        if ($file && is_file($file)) {
+            return include $file;
+        }
+    }
+
+    protected function getVersionFile($name)
+    {
+        return $this->manager->path($name, 'version.php');
+    }
+
+    protected function hasVersionFile($name)
+    {
+        $versionFile = $this->getVersionFile($name);
+
+        return $versionFile && is_file($versionFile);
+    }
+
+    protected function getDatabaseVersion($name)
+    {
+        if ($this->databaseVersions === null) {
+            $this->databaseVersions = Extension::query()->pluck('version', 'name');
+        }
+
+        if (! isset($this->databaseVersions[$name])) {
+            $this->databaseVersions[$name] =
+                Extension::query()
+                ->where('name', $name)
+                ->value('version');
+        }
+
+        return $this->databaseVersions[$name] ?? static::NO_VERSION_VALUE;
+    }
+
+    protected function setDatabaseVersion($name, $version = null)
+    {
+        $currentVersion = $this->getDatabaseVersion($name);
+
+        if ($version && ! $currentVersion) {
+            Extension::query()->create([
+                'name'    => $name,
+                'version' => $version,
+            ]);
+        } elseif ($version && $currentVersion) {
+            Extension::query()->where('name', $name)->update([
+                'version'    => $version,
+                'updated_at' => new Carbon,
+            ]);
+        } elseif ($currentVersion) {
+            Extension::query()->where('name', $name)->delete();
+        }
+
+        $this->databaseVersions[$name] = $version;
+    }
+
+    protected function applyDatabaseComment($name, $version, $comment)
+    {
+        ExtensionHistory::query()->create([
+            'name'    => $name,
+            'type'    => static::HISTORY_TYPE_COMMENT,
+            'version' => $version,
+            'detail'  => $comment,
+        ]);
+    }
+
+    protected function removeDatabaseComment($name, $version)
+    {
+        ExtensionHistory::query()
+            ->where('name', $name)
+            ->where('type', static::HISTORY_TYPE_COMMENT)
+            ->where('version', $version)
+            ->delete();
+    }
+
+    protected function applyDatabaseScript($name, $version, $script)
+    {
+        $updateFile = $this->manager->path($name, 'updates/'.$script);
+
+        if (! is_file($updateFile)) {
+            $this->note('- <error>v'.$version.':  Migration file "'.$script.'" not found</error>');
+
+            return;
+        }
+
+        $this->updater->setUp($updateFile, function () use ($name, $version, $script) {
+            ExtensionHistory::query()->create([
+                'name'    => $name,
+                'type'    => static::HISTORY_TYPE_SCRIPT,
+                'version' => $version,
+                'detail'  => $script,
+            ]);
+        });
+    }
+
+    protected function removeDatabaseScript($name, $version, $script)
+    {
+        $updateFile = $this->manager->path($name, 'updates/'.$script);
+
+        $this->updater->packDown($updateFile, function () use ($name, $version, $script) {
+            ExtensionHistory::query()
+                ->where('name', $name)
+                ->where('type', static::HISTORY_TYPE_SCRIPT)
+                ->where('version', $version)
+                ->where('detail', $script)
+                ->delete();
+        });
+    }
+
+    protected function getDatabaseHistory($name)
+    {
+        if ($this->databaseHistory !== null && array_key_exists($name, $this->databaseHistory)) {
+            return $this->databaseHistory[$name];
+        }
+
+        $historyInfo = ExtensionHistory::query()
+            ->where('name', $name)
+            ->orderBy('id')
+            ->get()
+            ->all();
+
+        return $this->databaseHistory[$name] = $historyInfo;
+    }
+
+    protected function getLastHistory($name)
+    {
+        return ExtensionHistory::query()
+            ->where('name', $name)
+            ->orderByDesc('id')
+            ->first();
+    }
+
+    protected function hasDatabaseHistory($name, $version, $script = null)
+    {
+        $historyInfo = $this->getDatabaseHistory($name);
+        if (! $historyInfo) {
+            return false;
+        }
+
+        foreach ($historyInfo as $history) {
+            if ($history->version != $version) {
+                continue;
+            }
+
+            if ($history->type == static::HISTORY_TYPE_COMMENT && ! $script) {
+                return true;
+            }
+
+            if ($history->type == static::HISTORY_TYPE_SCRIPT && $history->detail == $script) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    protected function extractScriptsAndComments($details): array
+    {
+        $details = (array) $details;
+
+        $fileNamePattern = "/^[a-z0-9\_\-\.\/\\\]+\.php$/i";
+
+        $comments = array_values(array_filter($details, function ($detail) use ($fileNamePattern) {
+            return ! preg_match($fileNamePattern, $detail);
+        }));
+
+        $scripts = array_values(array_filter($details, function ($detail) use ($fileNamePattern) {
+            return preg_match($fileNamePattern, $detail);
+        }));
+
+        return [$comments, $scripts];
+    }
+
+    public function getCurrentVersion($extension): string
+    {
+        return $this->getDatabaseVersion($this->manager->getName($extension));
+    }
+
+    public function hasDatabaseVersion($extension, string $version): bool
+    {
+        $name = $this->manager->getName($extension);
+
+        $histories = $this->getDatabaseHistory($name);
+
+        foreach ($histories as $history) {
+            if ($history->version === $version) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    public function getCurrentVersionNote($extension): string
+    {
+        $name = $this->manager->getName($extension);
+
+        $histories = $this->getDatabaseHistory($name);
+
+        $lastHistory = Arr::last(Arr::where($histories, function ($history) {
+            return $history->type === static::HISTORY_TYPE_COMMENT;
+        }));
+
+        return $lastHistory ? $lastHistory->detail : '';
+    }
+}

+ 1 - 3
src/Form/BlockForm.php

@@ -7,9 +7,8 @@ use Dcat\Admin\Form;
 use Dcat\Admin\Widgets\Form as WidgetForm;
 
 /**
- * Class BlockForm
+ * Class BlockForm.
  *
- * @package Dcat\Admin\Form
  *
  * @mixin Form
  */
@@ -157,5 +156,4 @@ HTML;
     public function fillFields(array $data)
     {
     }
-
 }

+ 1 - 1
src/Form/Builder.php

@@ -793,7 +793,7 @@ EOF;
     {
         $html = '';
 
-        foreach($this->hiddenFields() as $field) {
+        foreach ($this->hiddenFields() as $field) {
             $html .= $field->render();
         }
 

+ 5 - 6
src/Form/Concerns/HasEvents.php

@@ -3,8 +3,8 @@
 namespace Dcat\Admin\Form\Concerns;
 
 use Closure;
-use Dcat\Admin\Form\Events;
 use Dcat\Admin\Contracts\UploadField as UploadFieldInterface;
+use Dcat\Admin\Form\Events;
 use Dcat\Admin\Http\JsonResponse;
 use Illuminate\Support\Facades\Event;
 use Symfony\Component\HttpFoundation\File\UploadedFile;
@@ -44,7 +44,7 @@ trait HasEvents
     }
 
     /**
-     * 监听提交事件
+     * 监听提交事件.
      *
      * @param Closure $callback
      *
@@ -155,7 +155,6 @@ trait HasEvents
         return $this;
     }
 
-
     /**
      * 删除文件完成.
      *
@@ -284,7 +283,7 @@ trait HasEvents
     }
 
     /**
-     * 触发文件上传完成事件
+     * 触发文件上传完成事件.
      *
      * @param UploadFieldInterface|\Dcat\Admin\Form\Field $field
      * @param UploadedFile                                $file
@@ -298,7 +297,7 @@ trait HasEvents
     }
 
     /**
-     * 触发文件删除事件
+     * 触发文件删除事件.
      *
      * @param UploadFieldInterface|\Dcat\Admin\Form\Field $field
      * @param UploadedFile                                $file
@@ -312,7 +311,7 @@ trait HasEvents
     }
 
     /**
-     * 触发文件删除完成事件
+     * 触发文件删除完成事件.
      *
      * @param UploadFieldInterface|\Dcat\Admin\Form\Field $field
      * @param UploadedFile                                $file

+ 0 - 2
src/Form/Concerns/HasFiles.php

@@ -167,8 +167,6 @@ trait HasFiles
                 ->status(true)
                 ->send();
         }
-
-        return;
     }
 
     /**

+ 7 - 7
src/Form/Events/Creating.php

@@ -1,7 +1,7 @@
-<?php
-
-namespace Dcat\Admin\Form\Events;
-
-class Creating extends Event
-{
-}
+<?php
+
+namespace Dcat\Admin\Form\Events;
+
+class Creating extends Event
+{
+}

+ 7 - 7
src/Form/Events/Deleted.php

@@ -1,7 +1,7 @@
-<?php
-
-namespace Dcat\Admin\Form\Events;
-
-class Deleted extends Event
-{
-}
+<?php
+
+namespace Dcat\Admin\Form\Events;
+
+class Deleted extends Event
+{
+}

+ 7 - 7
src/Form/Events/Deleting.php

@@ -1,7 +1,7 @@
-<?php
-
-namespace Dcat\Admin\Form\Events;
-
-class Deleting extends Event
-{
-}
+<?php
+
+namespace Dcat\Admin\Form\Events;
+
+class Deleting extends Event
+{
+}

+ 7 - 7
src/Form/Events/Editing.php

@@ -1,7 +1,7 @@
-<?php
-
-namespace Dcat\Admin\Form\Events;
-
-class Editing extends Event
-{
-}
+<?php
+
+namespace Dcat\Admin\Form\Events;
+
+class Editing extends Event
+{
+}

+ 21 - 21
src/Form/Events/Event.php

@@ -1,21 +1,21 @@
-<?php
-
-namespace Dcat\Admin\Form\Events;
-
-use Dcat\Admin\Form;
-
-abstract class Event
-{
-    /**
-     * @var Form
-     */
-    public $form;
-
-    public $payload = [];
-
-    public function __construct(Form $form, array $payload = [])
-    {
-        $this->form = $form;
-        $this->payload = $payload;
-    }
-}
+<?php
+
+namespace Dcat\Admin\Form\Events;
+
+use Dcat\Admin\Form;
+
+abstract class Event
+{
+    /**
+     * @var Form
+     */
+    public $form;
+
+    public $payload = [];
+
+    public function __construct(Form $form, array $payload = [])
+    {
+        $this->form = $form;
+        $this->payload = $payload;
+    }
+}

+ 7 - 7
src/Form/Events/FileDeleted.php

@@ -1,7 +1,7 @@
-<?php
-
-namespace Dcat\Admin\Form\Events;
-
-class FileDeleted extends Event
-{
-}
+<?php
+
+namespace Dcat\Admin\Form\Events;
+
+class FileDeleted extends Event
+{
+}

+ 7 - 7
src/Form/Events/FileDeleting.php

@@ -1,7 +1,7 @@
-<?php
-
-namespace Dcat\Admin\Form\Events;
-
-class FileDeleting extends Event
-{
-}
+<?php
+
+namespace Dcat\Admin\Form\Events;
+
+class FileDeleting extends Event
+{
+}

+ 7 - 7
src/Form/Events/Saved.php

@@ -1,7 +1,7 @@
-<?php
-
-namespace Dcat\Admin\Form\Events;
-
-class Saved extends Event
-{
-}
+<?php
+
+namespace Dcat\Admin\Form\Events;
+
+class Saved extends Event
+{
+}

+ 7 - 7
src/Form/Events/Saving.php

@@ -1,7 +1,7 @@
-<?php
-
-namespace Dcat\Admin\Form\Events;
-
-class Saving extends Event
-{
-}
+<?php
+
+namespace Dcat\Admin\Form\Events;
+
+class Saving extends Event
+{
+}

+ 7 - 7
src/Form/Events/Submitted.php

@@ -1,7 +1,7 @@
-<?php
-
-namespace Dcat\Admin\Form\Events;
-
-class Submitted extends Event
-{
-}
+<?php
+
+namespace Dcat\Admin\Form\Events;
+
+class Submitted extends Event
+{
+}

+ 7 - 7
src/Form/Events/Uploaded.php

@@ -1,7 +1,7 @@
-<?php
-
-namespace Dcat\Admin\Form\Events;
-
-class Uploaded extends Event
-{
-}
+<?php
+
+namespace Dcat\Admin\Form\Events;
+
+class Uploaded extends Event
+{
+}

+ 7 - 7
src/Form/Events/Uploading.php

@@ -1,7 +1,7 @@
-<?php
-
-namespace Dcat\Admin\Form\Events;
-
-class Uploading extends Event
-{
-}
+<?php
+
+namespace Dcat\Admin\Form\Events;
+
+class Uploading extends Event
+{
+}

+ 0 - 1
src/Form/Field/Checkbox.php

@@ -2,7 +2,6 @@
 
 namespace Dcat\Admin\Form\Field;
 
-use Dcat\Admin\Admin;
 use Dcat\Admin\Support\Helper;
 use Dcat\Admin\Widgets\Checkbox as WidgetCheckbox;
 

+ 0 - 1
src/Form/Field/KeyValue.php

@@ -2,7 +2,6 @@
 
 namespace Dcat\Admin\Form\Field;
 
-use Dcat\Admin\Admin;
 use Dcat\Admin\Form\Field;
 use Dcat\Admin\Support\Helper;
 use Illuminate\Support\Arr;

+ 0 - 1
src/Form/Field/ListField.php

@@ -2,7 +2,6 @@
 
 namespace Dcat\Admin\Form\Field;
 
-use Dcat\Admin\Admin;
 use Dcat\Admin\Form\Field;
 use Dcat\Admin\Support\Helper;
 use Illuminate\Support\Arr;

+ 1 - 2
src/Form/Field/Select.php

@@ -2,7 +2,6 @@
 
 namespace Dcat\Admin\Form\Field;
 
-use Dcat\Admin\Admin;
 use Dcat\Admin\Exception\RuntimeException;
 use Dcat\Admin\Form\Field;
 use Dcat\Admin\Support\Helper;
@@ -101,7 +100,7 @@ class Select extends Field
             $field = $this->formatName($field);
         }
 
-        $class = $this->normalizeElementClass($field);;
+        $class = $this->normalizeElementClass($field);
 
         $url = admin_url($sourceUrl);
 

+ 0 - 1
src/Form/Field/Tags.php

@@ -2,7 +2,6 @@
 
 namespace Dcat\Admin\Form\Field;
 
-use Dcat\Admin\Admin;
 use Dcat\Admin\Form\Field;
 use Dcat\Admin\Support\Helper;
 use Illuminate\Contracts\Support\Arrayable;

+ 1 - 1
src/Grid/ComplexHeader.php

@@ -63,7 +63,7 @@ class ComplexHeader extends Widget
     }
 
     /**
-     * 默认隐藏字段
+     * 默认隐藏字段.
      *
      * @return $this
      */

+ 231 - 231
src/Grid/Concerns/CanHidesColumns.php

@@ -1,231 +1,231 @@
-<?php
-
-namespace Dcat\Admin\Grid\Concerns;
-
-use Dcat\Admin\Grid;
-use Dcat\Admin\Grid\Tools\ColumnSelector;
-use Dcat\Admin\Support\Helper;
-use Illuminate\Support\Collection;
-
-trait CanHidesColumns
-{
-    /**
-     * Default columns be hidden.
-     *
-     * @var array
-     */
-    public $hiddenColumns = [];
-
-    /**
-     * Remove column selector on grid.
-     *
-     * @param bool $disable
-     *
-     * @return $this|mixed
-     */
-    public function disableColumnSelector(bool $disable = true)
-    {
-        return $this->option('show_column_selector', ! $disable);
-    }
-
-    /**
-     * @return bool
-     */
-    public function showColumnSelector(bool $show = true)
-    {
-        return $this->disableColumnSelector(! $show);
-    }
-
-    /**
-     * @return bool
-     */
-    public function allowColumnSelector()
-    {
-        return $this->option('show_column_selector');
-    }
-
-    /**
-     * @return string
-     */
-    public function renderColumnSelector()
-    {
-        if (! $this->allowColumnSelector()) {
-            return '';
-        }
-
-        return (new ColumnSelector($this))->render();
-    }
-
-    /**
-     * Setting default shown columns on grid.
-     *
-     * @param array|string $columns
-     *
-     * @return $this
-     */
-    public function hideColumns($columns)
-    {
-        if (func_num_args()) {
-            $columns = (array) $columns;
-        } else {
-            $columns = func_get_args();
-        }
-
-        $this->hiddenColumns = array_merge($this->hiddenColumns, $columns);
-
-        return $this;
-    }
-
-    /**
-     * @return string
-     */
-    public function getColumnSelectorQueryName()
-    {
-        return $this->makeName(ColumnSelector::SELECT_COLUMN_NAME);
-    }
-
-    /**
-     * Get visible columns from request query.
-     *
-     * @return array
-     */
-    public function getVisibleColumnsFromQuery()
-    {
-        if (isset($this->visibleColumnsFromQuery)) {
-            return $this->visibleColumnsFromQuery;
-        }
-
-        $columns = $input = Helper::array($this->request->get($this->getColumnSelectorQueryName()));
-
-        if (! $input && ! $this->hasColumnSelectorRequestInput()) {
-            $columns = $this->getVisibleColumnsFromStorage() ?: array_values(array_diff(
-                $this->getComplexHeaderNames() ?: $this->columnNames, $this->hiddenColumns
-            ));
-        }
-
-        $this->storeVisibleColumns($input);
-
-        return $this->visibleColumnsFromQuery = $columns;
-    }
-
-    protected function formatWithComplexHeaders(array $columns)
-    {
-        if (empty($this->getComplexHeaderNames())) {
-            return $columns;
-        }
-
-        return $this->getComplexHeaders()
-            ->map(function (Grid\ComplexHeader $header) use ($columns) {
-                if (! in_array($header->getName(), $columns, true)) {
-                    return;
-                }
-
-                return $header->getColumnNames() ?: $this->getName();
-            })
-            ->filter()
-            ->flatten()
-            ->toArray();
-    }
-
-    /**
-     * @return mixed
-     */
-    public function getVisibleComplexHeaders()
-    {
-        $visible = $this->getVisibleColumnsFromQuery();
-
-        if (empty($visible)) {
-            return $this->getComplexHeaders();
-        }
-
-        array_push($visible, Grid\Column::SELECT_COLUMN_NAME, Grid\Column::ACTION_COLUMN_NAME);
-
-        return optional($this->getComplexHeaders())->filter(function ($column) use ($visible) {
-            return in_array($column->getName(), $visible);
-        });
-    }
-
-    /**
-     * Get all visible column instances.
-     *
-     * @return Collection|static
-     */
-    public function getVisibleColumns()
-    {
-        $visible = $this->formatWithComplexHeaders(
-            $this->getVisibleColumnsFromQuery()
-        );
-
-        if (empty($visible)) {
-            return $this->columns;
-        }
-
-        array_push($visible, Grid\Column::SELECT_COLUMN_NAME, Grid\Column::ACTION_COLUMN_NAME);
-
-        return $this->columns->filter(function (Grid\Column $column) use ($visible) {
-            return in_array($column->getName(), $visible);
-        });
-    }
-
-    /**
-     * Get all visible column names.
-     *
-     * @return array
-     */
-    public function getVisibleColumnNames()
-    {
-        $visible = $this->formatWithComplexHeaders(
-            $this->getVisibleColumnsFromQuery()
-        );
-
-        if (empty($visible)) {
-            return $this->columnNames;
-        }
-
-        array_push($visible, Grid\Column::SELECT_COLUMN_NAME, Grid\Column::ACTION_COLUMN_NAME);
-
-        return collect($this->columnNames)->filter(function ($column) use ($visible) {
-            return in_array($column, $visible);
-        })->toArray();
-    }
-
-    /**
-     * Get default visible column names.
-     *
-     * @return array
-     */
-    public function getDefaultVisibleColumnNames()
-    {
-        return array_values(
-            array_diff(
-                $this->columnNames,
-                $this->hiddenColumns,
-                [Grid\Column::SELECT_COLUMN_NAME, Grid\Column::ACTION_COLUMN_NAME]
-            )
-        );
-    }
-
-    protected function hasColumnSelectorRequestInput()
-    {
-        return $this->request->has($this->getColumnSelectorQueryName());
-    }
-
-    protected function storeVisibleColumns(array $input)
-    {
-        if (! $this->hasColumnSelectorRequestInput()) {
-            return;
-        }
-
-        session()->put($this->getVisibleColumnsKey(), $input);
-    }
-
-    protected function getVisibleColumnsFromStorage()
-    {
-        return session()->get($this->getVisibleColumnsKey());
-    }
-
-    protected function getVisibleColumnsKey()
-    {
-        return $this->getName().'/'.$this->request->path();
-    }
-}
+<?php
+
+namespace Dcat\Admin\Grid\Concerns;
+
+use Dcat\Admin\Grid;
+use Dcat\Admin\Grid\Tools\ColumnSelector;
+use Dcat\Admin\Support\Helper;
+use Illuminate\Support\Collection;
+
+trait CanHidesColumns
+{
+    /**
+     * Default columns be hidden.
+     *
+     * @var array
+     */
+    public $hiddenColumns = [];
+
+    /**
+     * Remove column selector on grid.
+     *
+     * @param bool $disable
+     *
+     * @return $this|mixed
+     */
+    public function disableColumnSelector(bool $disable = true)
+    {
+        return $this->option('show_column_selector', ! $disable);
+    }
+
+    /**
+     * @return bool
+     */
+    public function showColumnSelector(bool $show = true)
+    {
+        return $this->disableColumnSelector(! $show);
+    }
+
+    /**
+     * @return bool
+     */
+    public function allowColumnSelector()
+    {
+        return $this->option('show_column_selector');
+    }
+
+    /**
+     * @return string
+     */
+    public function renderColumnSelector()
+    {
+        if (! $this->allowColumnSelector()) {
+            return '';
+        }
+
+        return (new ColumnSelector($this))->render();
+    }
+
+    /**
+     * Setting default shown columns on grid.
+     *
+     * @param array|string $columns
+     *
+     * @return $this
+     */
+    public function hideColumns($columns)
+    {
+        if (func_num_args()) {
+            $columns = (array) $columns;
+        } else {
+            $columns = func_get_args();
+        }
+
+        $this->hiddenColumns = array_merge($this->hiddenColumns, $columns);
+
+        return $this;
+    }
+
+    /**
+     * @return string
+     */
+    public function getColumnSelectorQueryName()
+    {
+        return $this->makeName(ColumnSelector::SELECT_COLUMN_NAME);
+    }
+
+    /**
+     * Get visible columns from request query.
+     *
+     * @return array
+     */
+    public function getVisibleColumnsFromQuery()
+    {
+        if (isset($this->visibleColumnsFromQuery)) {
+            return $this->visibleColumnsFromQuery;
+        }
+
+        $columns = $input = Helper::array($this->request->get($this->getColumnSelectorQueryName()));
+
+        if (! $input && ! $this->hasColumnSelectorRequestInput()) {
+            $columns = $this->getVisibleColumnsFromStorage() ?: array_values(array_diff(
+                $this->getComplexHeaderNames() ?: $this->columnNames, $this->hiddenColumns
+            ));
+        }
+
+        $this->storeVisibleColumns($input);
+
+        return $this->visibleColumnsFromQuery = $columns;
+    }
+
+    protected function formatWithComplexHeaders(array $columns)
+    {
+        if (empty($this->getComplexHeaderNames())) {
+            return $columns;
+        }
+
+        return $this->getComplexHeaders()
+            ->map(function (Grid\ComplexHeader $header) use ($columns) {
+                if (! in_array($header->getName(), $columns, true)) {
+                    return;
+                }
+
+                return $header->getColumnNames() ?: $this->getName();
+            })
+            ->filter()
+            ->flatten()
+            ->toArray();
+    }
+
+    /**
+     * @return mixed
+     */
+    public function getVisibleComplexHeaders()
+    {
+        $visible = $this->getVisibleColumnsFromQuery();
+
+        if (empty($visible)) {
+            return $this->getComplexHeaders();
+        }
+
+        array_push($visible, Grid\Column::SELECT_COLUMN_NAME, Grid\Column::ACTION_COLUMN_NAME);
+
+        return optional($this->getComplexHeaders())->filter(function ($column) use ($visible) {
+            return in_array($column->getName(), $visible);
+        });
+    }
+
+    /**
+     * Get all visible column instances.
+     *
+     * @return Collection|static
+     */
+    public function getVisibleColumns()
+    {
+        $visible = $this->formatWithComplexHeaders(
+            $this->getVisibleColumnsFromQuery()
+        );
+
+        if (empty($visible)) {
+            return $this->columns;
+        }
+
+        array_push($visible, Grid\Column::SELECT_COLUMN_NAME, Grid\Column::ACTION_COLUMN_NAME);
+
+        return $this->columns->filter(function (Grid\Column $column) use ($visible) {
+            return in_array($column->getName(), $visible);
+        });
+    }
+
+    /**
+     * Get all visible column names.
+     *
+     * @return array
+     */
+    public function getVisibleColumnNames()
+    {
+        $visible = $this->formatWithComplexHeaders(
+            $this->getVisibleColumnsFromQuery()
+        );
+
+        if (empty($visible)) {
+            return $this->columnNames;
+        }
+
+        array_push($visible, Grid\Column::SELECT_COLUMN_NAME, Grid\Column::ACTION_COLUMN_NAME);
+
+        return collect($this->columnNames)->filter(function ($column) use ($visible) {
+            return in_array($column, $visible);
+        })->toArray();
+    }
+
+    /**
+     * Get default visible column names.
+     *
+     * @return array
+     */
+    public function getDefaultVisibleColumnNames()
+    {
+        return array_values(
+            array_diff(
+                $this->columnNames,
+                $this->hiddenColumns,
+                [Grid\Column::SELECT_COLUMN_NAME, Grid\Column::ACTION_COLUMN_NAME]
+            )
+        );
+    }
+
+    protected function hasColumnSelectorRequestInput()
+    {
+        return $this->request->has($this->getColumnSelectorQueryName());
+    }
+
+    protected function storeVisibleColumns(array $input)
+    {
+        if (! $this->hasColumnSelectorRequestInput()) {
+            return;
+        }
+
+        session()->put($this->getVisibleColumnsKey(), $input);
+    }
+
+    protected function getVisibleColumnsFromStorage()
+    {
+        return session()->get($this->getVisibleColumnsKey());
+    }
+
+    protected function getVisibleColumnsKey()
+    {
+        return $this->getName().'/'.$this->request->path();
+    }
+}

+ 0 - 1
src/Grid/Displayers/DropdownActions.php

@@ -2,7 +2,6 @@
 
 namespace Dcat\Admin\Grid\Displayers;
 
-use Dcat\Admin\Admin;
 use Dcat\Admin\Grid\Actions\Delete;
 use Dcat\Admin\Grid\Actions\Edit;
 use Dcat\Admin\Grid\Actions\QuickEdit;

+ 0 - 1
src/Grid/Filter/Between.php

@@ -2,7 +2,6 @@
 
 namespace Dcat\Admin\Grid\Filter;
 
-use Dcat\Admin\Admin;
 use Dcat\Admin\Grid\Filter\Presenter\DateTime;
 use Illuminate\Support\Arr;
 

+ 0 - 1
src/Grid/Filter/Presenter/DateTime.php

@@ -2,7 +2,6 @@
 
 namespace Dcat\Admin\Grid\Filter\Presenter;
 
-use Dcat\Admin\Admin;
 use Illuminate\Support\Arr;
 
 class DateTime extends Presenter

+ 0 - 2
src/Grid/Model.php

@@ -7,7 +7,6 @@ use Dcat\Admin\Exception\AdminException;
 use Dcat\Admin\Grid;
 use Dcat\Admin\Middleware\Pjax;
 use Dcat\Admin\Repositories\Repository;
-use Dcat\Utils\Backtrace\BacktraceFormatter;
 use Illuminate\Contracts\Support\Arrayable;
 use Illuminate\Database\Eloquent\Relations\Relation;
 use Illuminate\Database\Query\Builder;
@@ -389,7 +388,6 @@ class Model
 
             $data = $data->getCollection();
         } elseif ($data instanceof Collection) {
-
         } elseif ($data instanceof Arrayable || is_array($data)) {
             $data = collect($data);
         }

+ 139 - 139
src/Grid/Tools/ColumnSelector.php

@@ -1,139 +1,139 @@
-<?php
-
-namespace Dcat\Admin\Grid\Tools;
-
-use Dcat\Admin\Admin;
-use Dcat\Admin\Grid;
-use Dcat\Admin\Widgets\Checkbox;
-use Illuminate\Support\Collection;
-
-class ColumnSelector extends AbstractTool
-{
-    const SELECT_COLUMN_NAME = '_columns_';
-
-    /**
-     * @var Grid
-     */
-    protected $grid;
-
-    /**
-     * @var array
-     */
-    protected $ignoredColumns = [
-        Grid\Column::SELECT_COLUMN_NAME,
-        Grid\Column::ACTION_COLUMN_NAME,
-    ];
-
-    /**
-     * Create a new Export button instance.
-     *
-     * @param Grid $grid
-     */
-    public function __construct(Grid $grid)
-    {
-        $this->grid = $grid;
-    }
-
-    /**
-     * {@inheritdoc}
-     *
-     * @return string
-     */
-    public function render()
-    {
-        $show = $this->getVisibleColumnNames();
-        $all = $this->getGridColumns();
-
-        $list = Checkbox::make()
-            ->class('column-select-item')
-            ->options($all)
-            ->check(
-                $this->getGridColumns()->filter(function ($label, $key) use ($show) {
-                    if (empty($show)) {
-                        return true;
-                    }
-
-                    return in_array($key, $show) ? true : false;
-                }
-            )
-            ->keys()
-        );
-
-        $selectAll = Checkbox::make('_all_', [1 => trans('admin.all')])->check(
-            $all->count() === count($show) ? 1 : null
-        );
-
-        return Admin::view('admin::grid.column-selector', [
-            'checkbox'   => $list,
-            'defaults'   => $this->grid->getDefaultVisibleColumnNames(),
-            'selectAll'  => $selectAll,
-            'columnName' => $this->grid->getColumnSelectorQueryName(),
-        ]);
-    }
-
-    /**
-     * @return array
-     */
-    protected function getVisibleColumnNames()
-    {
-        $visible = $this->grid->getVisibleColumnsFromQuery();
-
-        $columns = $this->grid->getComplexHeaderNames() ?: $this->grid->getColumnNames();
-
-        if (! empty($visible)) {
-            array_push($visible, Grid\Column::SELECT_COLUMN_NAME, Grid\Column::ACTION_COLUMN_NAME);
-
-            $columns = collect($columns)->filter(function ($column) use ($visible) {
-                return in_array($column, $visible);
-            })->toArray();
-        }
-
-        return array_filter($columns, function ($v) {
-            return ! in_array($v, [Grid\Column::SELECT_COLUMN_NAME, Grid\Column::ACTION_COLUMN_NAME]);
-        });
-    }
-
-    /**
-     * @return Collection
-     */
-    protected function getGridColumns()
-    {
-        $columns = $this->grid->getComplexHeaders() ?: $this->grid->columns();
-
-        return $columns->map(function ($column) {
-            $name = $column->getName();
-
-            if ($this->isColumnIgnored($name)) {
-                return;
-            }
-
-            return [$name => $column->getLabel()];
-        })->filter()->collapse();
-    }
-
-    /**
-     * Is column ignored in column selector.
-     *
-     * @param string $name
-     *
-     * @return bool
-     */
-    protected function isColumnIgnored($name)
-    {
-        return in_array($name, $this->ignoredColumns);
-    }
-
-    /**
-     * Ignore a column to display in column selector.
-     *
-     * @param string|array $name
-     *
-     * @return $this
-     */
-    public function ignore($name)
-    {
-        $this->ignoredColumns = array_merge($this->ignoredColumns, (array) $name);
-
-        return $this;
-    }
-}
+<?php
+
+namespace Dcat\Admin\Grid\Tools;
+
+use Dcat\Admin\Admin;
+use Dcat\Admin\Grid;
+use Dcat\Admin\Widgets\Checkbox;
+use Illuminate\Support\Collection;
+
+class ColumnSelector extends AbstractTool
+{
+    const SELECT_COLUMN_NAME = '_columns_';
+
+    /**
+     * @var Grid
+     */
+    protected $grid;
+
+    /**
+     * @var array
+     */
+    protected $ignoredColumns = [
+        Grid\Column::SELECT_COLUMN_NAME,
+        Grid\Column::ACTION_COLUMN_NAME,
+    ];
+
+    /**
+     * Create a new Export button instance.
+     *
+     * @param Grid $grid
+     */
+    public function __construct(Grid $grid)
+    {
+        $this->grid = $grid;
+    }
+
+    /**
+     * {@inheritdoc}
+     *
+     * @return string
+     */
+    public function render()
+    {
+        $show = $this->getVisibleColumnNames();
+        $all = $this->getGridColumns();
+
+        $list = Checkbox::make()
+            ->class('column-select-item')
+            ->options($all)
+            ->check(
+                $this->getGridColumns()->filter(function ($label, $key) use ($show) {
+                    if (empty($show)) {
+                        return true;
+                    }
+
+                    return in_array($key, $show) ? true : false;
+                }
+            )
+            ->keys()
+        );
+
+        $selectAll = Checkbox::make('_all_', [1 => trans('admin.all')])->check(
+            $all->count() === count($show) ? 1 : null
+        );
+
+        return Admin::view('admin::grid.column-selector', [
+            'checkbox'   => $list,
+            'defaults'   => $this->grid->getDefaultVisibleColumnNames(),
+            'selectAll'  => $selectAll,
+            'columnName' => $this->grid->getColumnSelectorQueryName(),
+        ]);
+    }
+
+    /**
+     * @return array
+     */
+    protected function getVisibleColumnNames()
+    {
+        $visible = $this->grid->getVisibleColumnsFromQuery();
+
+        $columns = $this->grid->getComplexHeaderNames() ?: $this->grid->getColumnNames();
+
+        if (! empty($visible)) {
+            array_push($visible, Grid\Column::SELECT_COLUMN_NAME, Grid\Column::ACTION_COLUMN_NAME);
+
+            $columns = collect($columns)->filter(function ($column) use ($visible) {
+                return in_array($column, $visible);
+            })->toArray();
+        }
+
+        return array_filter($columns, function ($v) {
+            return ! in_array($v, [Grid\Column::SELECT_COLUMN_NAME, Grid\Column::ACTION_COLUMN_NAME]);
+        });
+    }
+
+    /**
+     * @return Collection
+     */
+    protected function getGridColumns()
+    {
+        $columns = $this->grid->getComplexHeaders() ?: $this->grid->columns();
+
+        return $columns->map(function ($column) {
+            $name = $column->getName();
+
+            if ($this->isColumnIgnored($name)) {
+                return;
+            }
+
+            return [$name => $column->getLabel()];
+        })->filter()->collapse();
+    }
+
+    /**
+     * Is column ignored in column selector.
+     *
+     * @param string $name
+     *
+     * @return bool
+     */
+    protected function isColumnIgnored($name)
+    {
+        return in_array($name, $this->ignoredColumns);
+    }
+
+    /**
+     * Ignore a column to display in column selector.
+     *
+     * @param string|array $name
+     *
+     * @return $this
+     */
+    public function ignore($name)
+    {
+        $this->ignoredColumns = array_merge($this->ignoredColumns, (array) $name);
+
+        return $this;
+    }
+}

+ 24 - 24
src/Http/Actions/Extensions/Disable.php

@@ -1,24 +1,24 @@
-<?php
-
-namespace Dcat\Admin\Http\Actions\Extensions;
-
-use Dcat\Admin\Admin;
-use Dcat\Admin\Grid\RowAction;
-
-class Disable extends RowAction
-{
-    public function title()
-    {
-        return sprintf('<span class="text-80">%s</span>', trans('admin.disable'));
-    }
-
-    public function handle()
-    {
-        Admin::extension()->enable($this->getKey(), false);
-
-        return $this
-            ->response()
-            ->success(trans('admin.update_succeeded'))
-            ->refresh();
-    }
-}
+<?php
+
+namespace Dcat\Admin\Http\Actions\Extensions;
+
+use Dcat\Admin\Admin;
+use Dcat\Admin\Grid\RowAction;
+
+class Disable extends RowAction
+{
+    public function title()
+    {
+        return sprintf('<span class="text-80">%s</span>', trans('admin.disable'));
+    }
+
+    public function handle()
+    {
+        Admin::extension()->enable($this->getKey(), false);
+
+        return $this
+            ->response()
+            ->success(trans('admin.update_succeeded'))
+            ->refresh();
+    }
+}

+ 24 - 24
src/Http/Actions/Extensions/Enable.php

@@ -1,24 +1,24 @@
-<?php
-
-namespace Dcat\Admin\Http\Actions\Extensions;
-
-use Dcat\Admin\Admin;
-use Dcat\Admin\Grid\RowAction;
-
-class Enable extends RowAction
-{
-    public function title()
-    {
-        return sprintf('<b>%s</b>', trans('admin.enable'));
-    }
-
-    public function handle()
-    {
-        Admin::extension()->enable($this->getKey());
-
-        return $this
-            ->response()
-            ->success(trans('admin.update_succeeded'))
-            ->refresh();
-    }
-}
+<?php
+
+namespace Dcat\Admin\Http\Actions\Extensions;
+
+use Dcat\Admin\Admin;
+use Dcat\Admin\Grid\RowAction;
+
+class Enable extends RowAction
+{
+    public function title()
+    {
+        return sprintf('<b>%s</b>', trans('admin.enable'));
+    }
+
+    public function handle()
+    {
+        Admin::extension()->enable($this->getKey());
+
+        return $this
+            ->response()
+            ->success(trans('admin.update_succeeded'))
+            ->refresh();
+    }
+}

+ 21 - 21
src/Http/Actions/Extensions/InstallFromLocal.php

@@ -1,21 +1,21 @@
-<?php
-
-namespace Dcat\Admin\Http\Actions\Extensions;
-
-use Dcat\Admin\Http\Forms\InstallFromLocal as InstallFromLocalForm;
-use Dcat\Admin\Grid\Tools\AbstractTool;
-use Dcat\Admin\Widgets\Modal;
-
-class InstallFromLocal extends AbstractTool
-{
-    protected $style = 'btn btn-primary';
-
-    public function html()
-    {
-        return Modal::make()
-            ->lg()
-            ->title($title = trans('admin.install_from_local'))
-            ->body(InstallFromLocalForm::make())
-            ->button("<button class='btn btn-primary'><i class=\"feather icon-folder\"></i> &nbsp;{$title}</button> &nbsp;");
-    }
-}
+<?php
+
+namespace Dcat\Admin\Http\Actions\Extensions;
+
+use Dcat\Admin\Grid\Tools\AbstractTool;
+use Dcat\Admin\Http\Forms\InstallFromLocal as InstallFromLocalForm;
+use Dcat\Admin\Widgets\Modal;
+
+class InstallFromLocal extends AbstractTool
+{
+    protected $style = 'btn btn-primary';
+
+    public function html()
+    {
+        return Modal::make()
+            ->lg()
+            ->title($title = trans('admin.install_from_local'))
+            ->body(InstallFromLocalForm::make())
+            ->button("<button class='btn btn-primary'><i class=\"feather icon-folder\"></i> &nbsp;{$title}</button> &nbsp;");
+    }
+}

+ 20 - 20
src/Http/Actions/Extensions/Marketplace.php

@@ -1,20 +1,20 @@
-<?php
-
-namespace Dcat\Admin\Http\Actions\Extensions;
-
-use Dcat\Admin\Grid\Tools\AbstractTool;
-
-class Marketplace extends AbstractTool
-{
-    protected $style = 'btn btn-primary';
-
-    public function title()
-    {
-        return '<i class="feather icon-shopping-cart"></i> &nbsp;'.trans('admin.marketplace');
-    }
-
-    public function html()
-    {
-        return parent::html().'&nbsp;';
-    }
-}
+<?php
+
+namespace Dcat\Admin\Http\Actions\Extensions;
+
+use Dcat\Admin\Grid\Tools\AbstractTool;
+
+class Marketplace extends AbstractTool
+{
+    protected $style = 'btn btn-primary';
+
+    public function title()
+    {
+        return '<i class="feather icon-shopping-cart"></i> &nbsp;'.trans('admin.marketplace');
+    }
+
+    public function html()
+    {
+        return parent::html().'&nbsp;';
+    }
+}

+ 35 - 35
src/Http/Actions/Extensions/Uninstall.php

@@ -1,35 +1,35 @@
-<?php
-
-namespace Dcat\Admin\Http\Actions\Extensions;
-
-use Dcat\Admin\Admin;
-use Dcat\Admin\Grid\RowAction;
-
-class Uninstall extends RowAction
-{
-    public function title()
-    {
-        $label = trans('admin.uninstall');
-
-        return "<span class='text-danger'>{$label}</span>";
-    }
-
-    public function confirm()
-    {
-        return [trans('admin.confirm_uninstall'), $this->getKey()];
-    }
-
-    public function handle()
-    {
-        $manager = Admin::extension()
-            ->updateManager()
-            ->rollback($this->getKey());
-
-        Admin::extension()->get($this->getKey())->uninstall();
-
-        return $this
-            ->response()
-            ->success(implode('<br>', $manager->notes))
-            ->refresh();
-    }
-}
+<?php
+
+namespace Dcat\Admin\Http\Actions\Extensions;
+
+use Dcat\Admin\Admin;
+use Dcat\Admin\Grid\RowAction;
+
+class Uninstall extends RowAction
+{
+    public function title()
+    {
+        $label = trans('admin.uninstall');
+
+        return "<span class='text-danger'>{$label}</span>";
+    }
+
+    public function confirm()
+    {
+        return [trans('admin.confirm_uninstall'), $this->getKey()];
+    }
+
+    public function handle()
+    {
+        $manager = Admin::extension()
+            ->updateManager()
+            ->rollback($this->getKey());
+
+        Admin::extension()->get($this->getKey())->uninstall();
+
+        return $this
+            ->response()
+            ->success(implode('<br>', $manager->notes))
+            ->refresh();
+    }
+}

+ 28 - 28
src/Http/Actions/Extensions/Update.php

@@ -1,28 +1,28 @@
-<?php
-
-namespace Dcat\Admin\Http\Actions\Extensions;
-
-use Dcat\Admin\Admin;
-use Dcat\Admin\Grid\RowAction;
-
-class Update extends RowAction
-{
-    public function title()
-    {
-        $replace = ['version' => $this->row->extension->getLocalLatestVersion()];
-
-        return sprintf('<b>%s</b>', trans('admin.upgrade_to_version', $replace));
-    }
-
-    public function handle()
-    {
-        $manager = Admin::extension()
-            ->updateManager()
-            ->update($this->getKey());
-
-        return $this
-            ->response()
-            ->success(implode('<br>', $manager->notes))
-            ->refresh();
-    }
-}
+<?php
+
+namespace Dcat\Admin\Http\Actions\Extensions;
+
+use Dcat\Admin\Admin;
+use Dcat\Admin\Grid\RowAction;
+
+class Update extends RowAction
+{
+    public function title()
+    {
+        $replace = ['version' => $this->row->extension->getLocalLatestVersion()];
+
+        return sprintf('<b>%s</b>', trans('admin.upgrade_to_version', $replace));
+    }
+
+    public function handle()
+    {
+        $manager = Admin::extension()
+            ->updateManager()
+            ->update($this->getKey());
+
+        return $this
+            ->response()
+            ->success(implode('<br>', $manager->notes))
+            ->refresh();
+    }
+}

+ 1 - 1
src/Http/Controllers/AuthController.php

@@ -4,8 +4,8 @@ namespace Dcat\Admin\Http\Controllers;
 
 use Dcat\Admin\Admin;
 use Dcat\Admin\Form;
-use Dcat\Admin\Layout\Content;
 use Dcat\Admin\Http\Repositories\Administrator;
+use Dcat\Admin\Layout\Content;
 use Dcat\Admin\Traits\HasFormResponse;
 use Illuminate\Auth\GuardHelpers;
 use Illuminate\Http\Request;

+ 2 - 3
src/Http/Controllers/ExtensionController.php

@@ -2,14 +2,13 @@
 
 namespace Dcat\Admin\Http\Controllers;
 
-use Dcat\Admin\Extend\ServiceProvider;
 use Dcat\Admin\Form;
 use Dcat\Admin\Grid;
 use Dcat\Admin\Http\Actions\Extensions\InstallFromLocal;
 use Dcat\Admin\Http\Actions\Extensions\Marketplace;
 use Dcat\Admin\Http\Displayers\Extensions;
-use Dcat\Admin\Layout\Content;
 use Dcat\Admin\Http\Repositories\Extension;
+use Dcat\Admin\Layout\Content;
 use Dcat\Admin\Support\Helper;
 use Dcat\Admin\Support\StringOutput;
 use Illuminate\Routing\Controller;
@@ -65,7 +64,7 @@ class ExtensionController extends Controller
 
             $grid->tools([
                 new Marketplace(),
-                new InstallFromLocal()
+                new InstallFromLocal(),
             ]);
 
             $grid->quickCreate(function (Grid\Tools\QuickCreate $create) {

+ 1 - 1
src/Http/Controllers/MenuController.php

@@ -3,10 +3,10 @@
 namespace Dcat\Admin\Http\Controllers;
 
 use Dcat\Admin\Form;
+use Dcat\Admin\Http\Repositories\Menu;
 use Dcat\Admin\Layout\Column;
 use Dcat\Admin\Layout\Content;
 use Dcat\Admin\Layout\Row;
-use Dcat\Admin\Http\Repositories\Menu;
 use Dcat\Admin\Tree;
 use Dcat\Admin\Widgets\Box;
 use Dcat\Admin\Widgets\Form as WidgetForm;

+ 1 - 1
src/Http/Controllers/PermissionController.php

@@ -4,8 +4,8 @@ namespace Dcat\Admin\Http\Controllers;
 
 use Dcat\Admin\Admin;
 use Dcat\Admin\Form;
-use Dcat\Admin\Layout\Content;
 use Dcat\Admin\Http\Repositories\Permission;
+use Dcat\Admin\Layout\Content;
 use Dcat\Admin\Tree;
 use Illuminate\Support\Str;
 

+ 1 - 1
src/Http/Controllers/UserController.php

@@ -5,8 +5,8 @@ namespace Dcat\Admin\Http\Controllers;
 use Dcat\Admin\Auth\Permission;
 use Dcat\Admin\Form;
 use Dcat\Admin\Grid;
-use Dcat\Admin\Models\Administrator as AdministratorModel;
 use Dcat\Admin\Http\Repositories\Administrator;
+use Dcat\Admin\Models\Administrator as AdministratorModel;
 use Dcat\Admin\Show;
 use Dcat\Admin\Support\Helper;
 use Dcat\Admin\Widgets\Tree;

+ 49 - 49
src/Http/Displayers/Extensions/Description.php

@@ -1,49 +1,49 @@
-<?php
-
-namespace Dcat\Admin\Http\Displayers\Extensions;
-
-use Dcat\Admin\Admin;
-use Dcat\Admin\Grid\Displayers\AbstractDisplayer;
-use Dcat\Admin\Http\Actions\Extensions\Update;
-use Dcat\Admin\Widgets\Modal;
-
-class Description extends AbstractDisplayer
-{
-    public function display()
-    {
-        return Admin::view('admin::grid.displayer.extensions.description', [
-            'value' => $this->value,
-            'row'   => $this->row,
-            'settingAction' => $this->resolveSettingForm(),
-            'updateAction' => $this->resolveAction(Update::class),
-        ]);
-    }
-
-    protected function resolveSettingForm()
-    {
-        $extension = Admin::extension()->get($this->getKey());
-
-        if (! method_exists($extension, 'settingForm')) {
-            return;
-        }
-
-        $label = trans('admin.setting');
-
-        return Modal::make()
-            ->lg()
-            ->title(trans('admin.setting').' - '.$this->getKey())
-            ->body($extension->settingForm())
-            ->button($label);
-    }
-
-    protected function resolveAction($action)
-    {
-        $action = new $action();
-
-        $action->setGrid($this->grid);
-        $action->setColumn($this->column);
-        $action->setRow($this->row);
-
-        return $action->render();
-    }
-}
+<?php
+
+namespace Dcat\Admin\Http\Displayers\Extensions;
+
+use Dcat\Admin\Admin;
+use Dcat\Admin\Grid\Displayers\AbstractDisplayer;
+use Dcat\Admin\Http\Actions\Extensions\Update;
+use Dcat\Admin\Widgets\Modal;
+
+class Description extends AbstractDisplayer
+{
+    public function display()
+    {
+        return Admin::view('admin::grid.displayer.extensions.description', [
+            'value' => $this->value,
+            'row'   => $this->row,
+            'settingAction' => $this->resolveSettingForm(),
+            'updateAction' => $this->resolveAction(Update::class),
+        ]);
+    }
+
+    protected function resolveSettingForm()
+    {
+        $extension = Admin::extension()->get($this->getKey());
+
+        if (! method_exists($extension, 'settingForm')) {
+            return;
+        }
+
+        $label = trans('admin.setting');
+
+        return Modal::make()
+            ->lg()
+            ->title(trans('admin.setting').' - '.$this->getKey())
+            ->body($extension->settingForm())
+            ->button($label);
+    }
+
+    protected function resolveAction($action)
+    {
+        $action = new $action();
+
+        $action->setGrid($this->grid);
+        $action->setColumn($this->column);
+        $action->setRow($this->row);
+
+        return $action->render();
+    }
+}

+ 36 - 36
src/Http/Displayers/Extensions/Name.php

@@ -1,36 +1,36 @@
-<?php
-
-namespace Dcat\Admin\Http\Displayers\Extensions;
-
-use Dcat\Admin\Admin;
-use Dcat\Admin\Grid\Displayers\AbstractDisplayer;
-use Dcat\Admin\Http\Actions\Extensions\Disable;
-use Dcat\Admin\Http\Actions\Extensions\Enable;
-use Dcat\Admin\Http\Actions\Extensions\Uninstall;
-use Illuminate\Support\Str;
-
-class Name extends AbstractDisplayer
-{
-    public function display()
-    {
-        return Admin::view('admin::grid.displayer.extensions.name', [
-            'value'           => $this->value,
-            'row'             => $this->row,
-            'enableAction'    => $this->resolveAction(Enable::class),
-            'disableAction'   => $this->resolveAction(Disable::class),
-            'uninstallAction' => $this->resolveAction(Uninstall::class),
-            'linkIcon'        => Str::contains($this->row->homepage, 'github.com') ? 'icon-github' : 'icon-link',
-        ]);
-    }
-
-    protected function resolveAction($action)
-    {
-        $action = new $action();
-
-        $action->setGrid($this->grid);
-        $action->setColumn($this->column);
-        $action->setRow($this->row);
-
-        return $action->render();
-    }
-}
+<?php
+
+namespace Dcat\Admin\Http\Displayers\Extensions;
+
+use Dcat\Admin\Admin;
+use Dcat\Admin\Grid\Displayers\AbstractDisplayer;
+use Dcat\Admin\Http\Actions\Extensions\Disable;
+use Dcat\Admin\Http\Actions\Extensions\Enable;
+use Dcat\Admin\Http\Actions\Extensions\Uninstall;
+use Illuminate\Support\Str;
+
+class Name extends AbstractDisplayer
+{
+    public function display()
+    {
+        return Admin::view('admin::grid.displayer.extensions.name', [
+            'value'           => $this->value,
+            'row'             => $this->row,
+            'enableAction'    => $this->resolveAction(Enable::class),
+            'disableAction'   => $this->resolveAction(Disable::class),
+            'uninstallAction' => $this->resolveAction(Uninstall::class),
+            'linkIcon'        => Str::contains($this->row->homepage, 'github.com') ? 'icon-github' : 'icon-link',
+        ]);
+    }
+
+    protected function resolveAction($action)
+    {
+        $action = new $action();
+
+        $action->setGrid($this->grid);
+        $action->setColumn($this->column);
+        $action->setRow($this->row);
+
+        return $action->render();
+    }
+}

+ 84 - 84
src/Http/Forms/InstallFromLocal.php

@@ -1,84 +1,84 @@
-<?php
-
-namespace Dcat\Admin\Http\Forms;
-
-use Dcat\Admin\Admin;
-use Dcat\Admin\Contracts\LazyRenderable;
-use Dcat\Admin\Exception\RuntimeException;
-use Dcat\Admin\Traits\LazyWidget;
-use Dcat\Admin\Widgets\Form;
-
-class InstallFromLocal extends Form implements LazyRenderable
-{
-    use LazyWidget;
-
-    public function handle(array $input)
-    {
-        $file = $input['extension'];
-
-        if (! $file) {
-            return $this->response()->error('Invalid arguments.');
-        }
-
-        try {
-            $path = $this->getFilePath($file);
-
-            $manager = Admin::extension();
-
-            $allNames = $manager->all()->keys()->toArray();
-
-            $manager->extract($path);
-
-            $manager->load();
-
-            $newAllNames = $manager->all()->keys()->toArray();
-
-            $diff = array_diff($newAllNames, $allNames);
-
-            if (! $diff) {
-                return $this->response()->error(trans('admin.invalid_extension_package'));
-            }
-
-            $manager
-                ->updateManager()
-                ->update(current($diff));
-
-            return $this->response()
-                ->success(implode('<br>', $manager->updateManager()->notes))
-                ->refresh();
-        } catch (\Throwable $e) {
-            Admin::reportException($e);
-
-            return $this->response()->error($e->getMessage());
-        } finally {
-            if (! empty($path)) {
-                @unlink($path);
-            }
-        }
-    }
-
-    public function form()
-    {
-        $this->file('extension')
-            ->required()
-            ->disk($this->disk())
-            ->accept('zip', 'application/zip')
-            ->autoUpload();
-    }
-
-    protected function getFilePath($file)
-    {
-        $root = config("filesystems.disks.{$this->disk()}.root");
-
-        if (! $root) {
-            throw new RuntimeException(sprintf('Missing \'root\' for disk [%s].', $this->disk()));
-        }
-
-        return rtrim($root, '/').'/'.$file;
-    }
-
-    protected function disk()
-    {
-        return config('admin.extension.disk') ?: 'local';
-    }
-}
+<?php
+
+namespace Dcat\Admin\Http\Forms;
+
+use Dcat\Admin\Admin;
+use Dcat\Admin\Contracts\LazyRenderable;
+use Dcat\Admin\Exception\RuntimeException;
+use Dcat\Admin\Traits\LazyWidget;
+use Dcat\Admin\Widgets\Form;
+
+class InstallFromLocal extends Form implements LazyRenderable
+{
+    use LazyWidget;
+
+    public function handle(array $input)
+    {
+        $file = $input['extension'];
+
+        if (! $file) {
+            return $this->response()->error('Invalid arguments.');
+        }
+
+        try {
+            $path = $this->getFilePath($file);
+
+            $manager = Admin::extension();
+
+            $allNames = $manager->all()->keys()->toArray();
+
+            $manager->extract($path);
+
+            $manager->load();
+
+            $newAllNames = $manager->all()->keys()->toArray();
+
+            $diff = array_diff($newAllNames, $allNames);
+
+            if (! $diff) {
+                return $this->response()->error(trans('admin.invalid_extension_package'));
+            }
+
+            $manager
+                ->updateManager()
+                ->update(current($diff));
+
+            return $this->response()
+                ->success(implode('<br>', $manager->updateManager()->notes))
+                ->refresh();
+        } catch (\Throwable $e) {
+            Admin::reportException($e);
+
+            return $this->response()->error($e->getMessage());
+        } finally {
+            if (! empty($path)) {
+                @unlink($path);
+            }
+        }
+    }
+
+    public function form()
+    {
+        $this->file('extension')
+            ->required()
+            ->disk($this->disk())
+            ->accept('zip', 'application/zip')
+            ->autoUpload();
+    }
+
+    protected function getFilePath($file)
+    {
+        $root = config("filesystems.disks.{$this->disk()}.root");
+
+        if (! $root) {
+            throw new RuntimeException(sprintf('Missing \'root\' for disk [%s].', $this->disk()));
+        }
+
+        return rtrim($root, '/').'/'.$file;
+    }
+
+    protected function disk()
+    {
+        return config('admin.extension.disk') ?: 'local';
+    }
+}

+ 393 - 393
src/Http/JsonResponse.php

@@ -1,393 +1,393 @@
-<?php
-
-namespace Dcat\Admin\Http;
-
-use Dcat\Admin\Exception\AdminException;
-use Dcat\Admin\Support\Helper;
-use Illuminate\Contracts\Validation\Validator;
-use Illuminate\Support\MessageBag;
-use Illuminate\Support\Str;
-use Illuminate\Validation\ValidationException;
-
-/**
- * Class JsonResponse
- *
- * @method $this redirectIf($condition, ?string $url)
- * @method $this locationIf($condition, ?string $url)
- * @method $this refreshIf($condition)
- * @method $this downloadIf($condition, ?string $url)
- * @method $this scriptIf($condition, ?string $script)
- * @method $this alertIf($condition, bool $alert = true)
- * @method $this htmlIf($condition, $html)
- * @method $this dataIf($condition, array $data)
- * @method $this optionsIf($condition, array $data)
- * @method $this withValidationIf($condition, $errors)
- * @method $this withExceptionIf($condition, \Throwable $e)
- */
-class JsonResponse
-{
-    protected $status = true;
-    protected $statusCode = 200;
-    protected $exception;
-    protected $data = [];
-    protected $html;
-    protected $options = [];
-
-    /**
-     * 设置请求结果是否成功.
-     *
-     * @param bool $status
-     *
-     * @return $this
-     */
-    public function status(bool $status)
-    {
-        $this->status = $status;
-
-        return $this;
-    }
-
-    /**
-     * 设置 HTTP 状态码.
-     *
-     * @param int $statusCode
-     *
-     * @return $this
-     */
-    public function statusCode(int $statusCode)
-    {
-        $this->statusCode = $statusCode;
-
-        return $this;
-    }
-
-    /**
-     * 设置提示信息.
-     *
-     * @param string $message
-     *
-     * @return $this
-     */
-    public function message(?string $message)
-    {
-        $this->data['message'] = $message;
-
-        return $this;
-    }
-
-    /**
-     * 显示 成功 提示弹窗.
-     *
-     * @param string $message
-     *
-     * @return $this
-     */
-    public function success(?string $message)
-    {
-        return $this->show('success', $message);
-    }
-
-    /**
-     * @param string $message
-     *
-     * @return $this
-     */
-    public function info(?string $message)
-    {
-        return $this->show('info', $message);
-    }
-
-    /**
-     * @param string $message
-     *
-     * @return $this
-     */
-    public function warning(?string $message)
-    {
-        return $this->show('warning', $message);
-    }
-
-    /**
-     * 显示 错误 信息弹窗.
-     *
-     * @param string $message
-     * @param bool   $alert
-     *
-     * @return $this
-     */
-    public function error(?string $message)
-    {
-        $this->status(false);
-
-        return $this->show('error', $message);
-    }
-
-    /**
-     * 设置 toastr 显示时长.
-     *
-     * @param $seconds
-     *
-     * @return $this
-     */
-    public function timeout($seconds)
-    {
-        return $this->data(['timeout' => $seconds]);
-    }
-
-    /**
-     * 显示确认弹窗.
-     *
-     * @param bool $alert
-     *
-     * @return $this
-     */
-    public function alert(bool $alert = true)
-    {
-        return $this->data(['alert' => $alert]);
-    }
-
-    /**
-     * 显示弹窗描述信息.
-     *
-     * @param string $detail
-     *
-     * @return $this
-     */
-    public function detail(?string $detail)
-    {
-        return $this->data(['detail' => $detail]);
-    }
-
-    /**
-     * 显示弹窗信息.
-     *
-     * @param string $type
-     * @param string $message
-     *
-     * @return $this
-     */
-    protected function show(?string $type, ?string $message = null)
-    {
-        if ($message) {
-            $this->message($message);
-        }
-
-        return $this->data(['type' => $type]);
-    }
-
-    /**
-     * 跳转.
-     *
-     * @param string $url
-     *
-     * @return $this
-     */
-    public function redirect(?string $url)
-    {
-        return $this->then(['action' => 'redirect', 'value' => admin_url($url)]);
-    }
-
-    /**
-     * @param string|null $url
-     *
-     * @return $this
-     */
-    public function redirectToIntended(?string $url)
-    {
-        $path = session()->pull('url.intended');
-
-        return $this->redirect($path ?: $url);
-    }
-
-    /**
-     * Location 跳转.
-     *
-     * @param string $location
-     *
-     * @return $this
-     */
-    public function location(?string $location)
-    {
-        return $this->then(['action' => 'location', 'value' => admin_url($location)]);
-    }
-
-    /**
-     * @param string|null $url
-     *
-     * @return $this
-     */
-    public function locationToIntended(?string $url)
-    {
-        $path = session()->pull('url.intended');
-
-        return $this->location($path ?: $url);
-    }
-
-    /**
-     * 下载.
-     *
-     * @param string $url
-     *
-     * @return $this
-     */
-    public function download($url)
-    {
-        return $this->then(['action' => 'download', 'value' => admin_url($url)]);
-    }
-
-    /**
-     * 刷新页面.
-     *
-     * @return $this
-     */
-    public function refresh()
-    {
-        return $this->then(['action' => 'refresh', 'value' => true]);
-    }
-
-    /**
-     * 执行JS代码.
-     *
-     * @param string $script
-     *
-     * @return $this
-     */
-    public function script($script)
-    {
-        return $this->then(['action' => 'script', 'value' => $script]);
-    }
-
-    /**
-     * @param array $value
-     *
-     * @return $this
-     */
-    protected function then(array $value)
-    {
-        $this->data['then'] = $value;
-
-        return $this;
-    }
-
-    /**
-     * 设置返回数据.
-     *
-     * @param array $value
-     *
-     * @return $this
-     */
-    public function data(array $value)
-    {
-        $this->data = array_merge($this->data, $value);
-
-        return $this;
-    }
-
-    /**
-     * 返回 HTML.
-     *
-     * @param string $html
-     *
-     * @return $this
-     */
-    public function html($html)
-    {
-        $this->html = $html;
-
-        return $this;
-    }
-
-    /**
-     * 设置其他字段.
-     *
-     * @param array $options
-     *
-     * @return $this
-     */
-    public function options(array $options)
-    {
-        $this->options = array_merge($this->options, $options);
-
-        return $this;
-    }
-
-    /**
-     * 设置字段验证错误信息.
-     *
-     * @param $errors
-     *
-     * @return $this
-     */
-    public function withValidation($errors)
-    {
-        if ($errors instanceof Validator) {
-            $errors = $errors->errors();
-        }
-
-        if ($errors instanceof MessageBag) {
-            $errors = $errors->getMessages();
-        }
-
-        return $this
-            ->status(false)
-            ->statusCode(422)
-            ->options(['errors' => $errors]);
-    }
-
-    /**
-     * 响应异常.
-     *
-     * @param \Throwable $exception
-     *
-     * @return $this
-     */
-    public function withException(\Throwable $exception)
-    {
-        if ($exception instanceof ValidationException) {
-            return $this->withValidation($exception->errors());
-        }
-
-        return $this
-            ->status(false)
-            ->error(
-                sprintf('[%s] %s', get_class($exception), $exception->getMessage())
-            );
-    }
-
-    /**
-     * @return \Illuminate\Http\JsonResponse
-     */
-    public function send()
-    {
-        $data = ['status' => $this->status, 'data' => $this->data];
-
-        if ($this->html) {
-            $data['html'] = Helper::render($this->html);
-        }
-
-        return response()->json($this->options + $data, $this->statusCode);
-    }
-
-    public function __call($method, $arguments)
-    {
-        if (Str::endsWith($method, 'If')) {
-            if (array_shift($arguments)) {
-                $method = Str::replaceLast('If', '', $method);
-
-                return $this->$method(...$arguments);
-            }
-        }
-
-        throw new AdminException(sprintf('Call to undefined method "%s"', $method));
-    }
-
-    /**
-     * @param mixed ...$params
-     *
-     * @return $this
-     */
-    public static function make(...$params)
-    {
-        return new static(...$params);
-    }
-}
+<?php
+
+namespace Dcat\Admin\Http;
+
+use Dcat\Admin\Exception\AdminException;
+use Dcat\Admin\Support\Helper;
+use Illuminate\Contracts\Validation\Validator;
+use Illuminate\Support\MessageBag;
+use Illuminate\Support\Str;
+use Illuminate\Validation\ValidationException;
+
+/**
+ * Class JsonResponse.
+ *
+ * @method $this redirectIf($condition, ?string $url)
+ * @method $this locationIf($condition, ?string $url)
+ * @method $this refreshIf($condition)
+ * @method $this downloadIf($condition, ?string $url)
+ * @method $this scriptIf($condition, ?string $script)
+ * @method $this alertIf($condition, bool $alert = true)
+ * @method $this htmlIf($condition, $html)
+ * @method $this dataIf($condition, array $data)
+ * @method $this optionsIf($condition, array $data)
+ * @method $this withValidationIf($condition, $errors)
+ * @method $this withExceptionIf($condition, \Throwable $e)
+ */
+class JsonResponse
+{
+    protected $status = true;
+    protected $statusCode = 200;
+    protected $exception;
+    protected $data = [];
+    protected $html;
+    protected $options = [];
+
+    /**
+     * 设置请求结果是否成功.
+     *
+     * @param bool $status
+     *
+     * @return $this
+     */
+    public function status(bool $status)
+    {
+        $this->status = $status;
+
+        return $this;
+    }
+
+    /**
+     * 设置 HTTP 状态码.
+     *
+     * @param int $statusCode
+     *
+     * @return $this
+     */
+    public function statusCode(int $statusCode)
+    {
+        $this->statusCode = $statusCode;
+
+        return $this;
+    }
+
+    /**
+     * 设置提示信息.
+     *
+     * @param string $message
+     *
+     * @return $this
+     */
+    public function message(?string $message)
+    {
+        $this->data['message'] = $message;
+
+        return $this;
+    }
+
+    /**
+     * 显示 成功 提示弹窗.
+     *
+     * @param string $message
+     *
+     * @return $this
+     */
+    public function success(?string $message)
+    {
+        return $this->show('success', $message);
+    }
+
+    /**
+     * @param string $message
+     *
+     * @return $this
+     */
+    public function info(?string $message)
+    {
+        return $this->show('info', $message);
+    }
+
+    /**
+     * @param string $message
+     *
+     * @return $this
+     */
+    public function warning(?string $message)
+    {
+        return $this->show('warning', $message);
+    }
+
+    /**
+     * 显示 错误 信息弹窗.
+     *
+     * @param string $message
+     * @param bool   $alert
+     *
+     * @return $this
+     */
+    public function error(?string $message)
+    {
+        $this->status(false);
+
+        return $this->show('error', $message);
+    }
+
+    /**
+     * 设置 toastr 显示时长.
+     *
+     * @param $seconds
+     *
+     * @return $this
+     */
+    public function timeout($seconds)
+    {
+        return $this->data(['timeout' => $seconds]);
+    }
+
+    /**
+     * 显示确认弹窗.
+     *
+     * @param bool $alert
+     *
+     * @return $this
+     */
+    public function alert(bool $alert = true)
+    {
+        return $this->data(['alert' => $alert]);
+    }
+
+    /**
+     * 显示弹窗描述信息.
+     *
+     * @param string $detail
+     *
+     * @return $this
+     */
+    public function detail(?string $detail)
+    {
+        return $this->data(['detail' => $detail]);
+    }
+
+    /**
+     * 显示弹窗信息.
+     *
+     * @param string $type
+     * @param string $message
+     *
+     * @return $this
+     */
+    protected function show(?string $type, ?string $message = null)
+    {
+        if ($message) {
+            $this->message($message);
+        }
+
+        return $this->data(['type' => $type]);
+    }
+
+    /**
+     * 跳转.
+     *
+     * @param string $url
+     *
+     * @return $this
+     */
+    public function redirect(?string $url)
+    {
+        return $this->then(['action' => 'redirect', 'value' => admin_url($url)]);
+    }
+
+    /**
+     * @param string|null $url
+     *
+     * @return $this
+     */
+    public function redirectToIntended(?string $url)
+    {
+        $path = session()->pull('url.intended');
+
+        return $this->redirect($path ?: $url);
+    }
+
+    /**
+     * Location 跳转.
+     *
+     * @param string $location
+     *
+     * @return $this
+     */
+    public function location(?string $location)
+    {
+        return $this->then(['action' => 'location', 'value' => admin_url($location)]);
+    }
+
+    /**
+     * @param string|null $url
+     *
+     * @return $this
+     */
+    public function locationToIntended(?string $url)
+    {
+        $path = session()->pull('url.intended');
+
+        return $this->location($path ?: $url);
+    }
+
+    /**
+     * 下载.
+     *
+     * @param string $url
+     *
+     * @return $this
+     */
+    public function download($url)
+    {
+        return $this->then(['action' => 'download', 'value' => admin_url($url)]);
+    }
+
+    /**
+     * 刷新页面.
+     *
+     * @return $this
+     */
+    public function refresh()
+    {
+        return $this->then(['action' => 'refresh', 'value' => true]);
+    }
+
+    /**
+     * 执行JS代码.
+     *
+     * @param string $script
+     *
+     * @return $this
+     */
+    public function script($script)
+    {
+        return $this->then(['action' => 'script', 'value' => $script]);
+    }
+
+    /**
+     * @param array $value
+     *
+     * @return $this
+     */
+    protected function then(array $value)
+    {
+        $this->data['then'] = $value;
+
+        return $this;
+    }
+
+    /**
+     * 设置返回数据.
+     *
+     * @param array $value
+     *
+     * @return $this
+     */
+    public function data(array $value)
+    {
+        $this->data = array_merge($this->data, $value);
+
+        return $this;
+    }
+
+    /**
+     * 返回 HTML.
+     *
+     * @param string $html
+     *
+     * @return $this
+     */
+    public function html($html)
+    {
+        $this->html = $html;
+
+        return $this;
+    }
+
+    /**
+     * 设置其他字段.
+     *
+     * @param array $options
+     *
+     * @return $this
+     */
+    public function options(array $options)
+    {
+        $this->options = array_merge($this->options, $options);
+
+        return $this;
+    }
+
+    /**
+     * 设置字段验证错误信息.
+     *
+     * @param $errors
+     *
+     * @return $this
+     */
+    public function withValidation($errors)
+    {
+        if ($errors instanceof Validator) {
+            $errors = $errors->errors();
+        }
+
+        if ($errors instanceof MessageBag) {
+            $errors = $errors->getMessages();
+        }
+
+        return $this
+            ->status(false)
+            ->statusCode(422)
+            ->options(['errors' => $errors]);
+    }
+
+    /**
+     * 响应异常.
+     *
+     * @param \Throwable $exception
+     *
+     * @return $this
+     */
+    public function withException(\Throwable $exception)
+    {
+        if ($exception instanceof ValidationException) {
+            return $this->withValidation($exception->errors());
+        }
+
+        return $this
+            ->status(false)
+            ->error(
+                sprintf('[%s] %s', get_class($exception), $exception->getMessage())
+            );
+    }
+
+    /**
+     * @return \Illuminate\Http\JsonResponse
+     */
+    public function send()
+    {
+        $data = ['status' => $this->status, 'data' => $this->data];
+
+        if ($this->html) {
+            $data['html'] = Helper::render($this->html);
+        }
+
+        return response()->json($this->options + $data, $this->statusCode);
+    }
+
+    public function __call($method, $arguments)
+    {
+        if (Str::endsWith($method, 'If')) {
+            if (array_shift($arguments)) {
+                $method = Str::replaceLast('If', '', $method);
+
+                return $this->$method(...$arguments);
+            }
+        }
+
+        throw new AdminException(sprintf('Call to undefined method "%s"', $method));
+    }
+
+    /**
+     * @param mixed ...$params
+     *
+     * @return $this
+     */
+    public static function make(...$params)
+    {
+        return new static(...$params);
+    }
+}

+ 2 - 2
src/Layout/Asset.php

@@ -476,10 +476,10 @@ class Asset
     }
 
     /**
-     * 判断别名是否存在
+     * 判断别名是否存在.
      *
      * @param $value
-     * 
+     *
      * @return bool
      */
     public function hasAlias($value)

+ 21 - 21
src/Models/Extension.php

@@ -1,21 +1,21 @@
-<?php
-
-namespace Dcat\Admin\Models;
-
-use Illuminate\Database\Eloquent\Model;
-
-class Extension extends Model
-{
-    protected $table = 'admin_extensions';
-
-    protected $fillable = ['name', 'is_enabled', 'version', 'options'];
-
-    public function __construct(array $attributes = [])
-    {
-        $connection = config('admin.database.connection') ?: config('database.default');
-
-        $this->setConnection($connection);
-
-        parent::__construct($attributes);
-    }
-}
+<?php
+
+namespace Dcat\Admin\Models;
+
+use Illuminate\Database\Eloquent\Model;
+
+class Extension extends Model
+{
+    protected $table = 'admin_extensions';
+
+    protected $fillable = ['name', 'is_enabled', 'version', 'options'];
+
+    public function __construct(array $attributes = [])
+    {
+        $connection = config('admin.database.connection') ?: config('database.default');
+
+        $this->setConnection($connection);
+
+        parent::__construct($attributes);
+    }
+}

+ 21 - 21
src/Models/ExtensionHistory.php

@@ -1,21 +1,21 @@
-<?php
-
-namespace Dcat\Admin\Models;
-
-use Illuminate\Database\Eloquent\Model;
-
-class ExtensionHistory extends Model
-{
-    protected $table = 'admin_extension_histories';
-
-    protected $fillable = ['name', 'type', 'version', 'detail'];
-
-    public function __construct(array $attributes = [])
-    {
-        $connection = config('admin.database.connection') ?: config('database.default');
-
-        $this->setConnection($connection);
-
-        parent::__construct($attributes);
-    }
-}
+<?php
+
+namespace Dcat\Admin\Models;
+
+use Illuminate\Database\Eloquent\Model;
+
+class ExtensionHistory extends Model
+{
+    protected $table = 'admin_extension_histories';
+
+    protected $fillable = ['name', 'type', 'version', 'detail'];
+
+    public function __construct(array $attributes = [])
+    {
+        $connection = config('admin.database.connection') ?: config('database.default');
+
+        $this->setConnection($connection);
+
+        parent::__construct($attributes);
+    }
+}

+ 22 - 22
src/Models/Setting.php

@@ -1,22 +1,22 @@
-<?php
-
-namespace Dcat\Admin\Models;
-
-use Illuminate\Database\Eloquent\Model;
-
-class Setting extends Model
-{
-    protected $table = 'admin_settings';
-    protected $primaryKey = 'slug';
-    public $incrementing = false;
-    protected $fillable = ['slug', 'value'];
-
-    public function __construct(array $attributes = [])
-    {
-        $connection = config('admin.database.connection') ?: config('database.default');
-
-        $this->setConnection($connection);
-
-        parent::__construct($attributes);
-    }
-}
+<?php
+
+namespace Dcat\Admin\Models;
+
+use Illuminate\Database\Eloquent\Model;
+
+class Setting extends Model
+{
+    protected $table = 'admin_settings';
+    protected $primaryKey = 'slug';
+    public $incrementing = false;
+    protected $fillable = ['slug', 'value'];
+
+    public function __construct(array $attributes = [])
+    {
+        $connection = config('admin.database.connection') ?: config('database.default');
+
+        $this->setConnection($connection);
+
+        parent::__construct($attributes);
+    }
+}

+ 0 - 1
src/Show/Field.php

@@ -3,7 +3,6 @@
 namespace Dcat\Admin\Show;
 
 use Dcat\Admin\Admin;
-use Dcat\Admin\Exception\RuntimeException;
 use Dcat\Admin\Show;
 use Dcat\Admin\Support\Helper;
 use Dcat\Admin\Traits\HasBuilderEvents;

+ 34 - 34
src/Support/Context.php

@@ -1,34 +1,34 @@
-<?php
-
-namespace Dcat\Admin\Support;
-
-use Dcat\EasyExcel\Support\Arr;
-use Illuminate\Support\Fluent;
-
-/**
- * Class Context
- *
- * @property string $favicon
- * @property string $metaTitle
- * @property string $pjaxContainerId
- * @property array|null $html
- * @property array|null $ignoreQueries
- * @property array|null $jsVariables
- */
-class Context extends Fluent
-{
-    public function get($key, $default = null)
-    {
-        return Arr::get($this->attributes, $key, $default);
-    }
-
-    public function forget($keys)
-    {
-        Arr::forget($this->attributes, $keys);
-    }
-
-    public function flush()
-    {
-        $this->attributes = [];
-    }
-}
+<?php
+
+namespace Dcat\Admin\Support;
+
+use Dcat\EasyExcel\Support\Arr;
+use Illuminate\Support\Fluent;
+
+/**
+ * Class Context.
+ *
+ * @property string $favicon
+ * @property string $metaTitle
+ * @property string $pjaxContainerId
+ * @property array|null $html
+ * @property array|null $ignoreQueries
+ * @property array|null $jsVariables
+ */
+class Context extends Fluent
+{
+    public function get($key, $default = null)
+    {
+        return Arr::get($this->attributes, $key, $default);
+    }
+
+    public function forget($keys)
+    {
+        Arr::forget($this->attributes, $keys);
+    }
+
+    public function flush()
+    {
+        $this->attributes = [];
+    }
+}

+ 180 - 182
src/Support/DatabaseUpdater.php

@@ -1,182 +1,180 @@
-<?php
-
-namespace Dcat\Admin\Support;
-
-use Dcat\Admin\Exception\AdminException;
-use Illuminate\Database\Migrations\Migration;
-use Illuminate\Database\Seeder;
-use Illuminate\Database\Eloquent\Model;
-use Illuminate\Support\Facades\DB;
-
-/**
- * Database updater
- *
- * Executes database migration and seed scripts based on their filename.
- *
- * @author Alexey Bobkov, Samuel Georges
- */
-class DatabaseUpdater
-{
-    /**
-     * Sets up a migration or seed file.
-     */
-    public function setUp($file, \Closure $callback = null)
-    {
-        $object = $this->resolve($file);
-
-        if ($object === null) {
-            return false;
-        }
-
-        $this->isValidScript($object);
-
-        Model::unguard();
-
-        $this->transaction(function () use ($object, $callback) {
-            if ($object instanceof Migration) {
-                $object->up();
-            }
-            elseif ($object instanceof Seeder) {
-                $object->run();
-            }
-
-            $callback && $callback();
-        });
-
-        Model::reguard();
-
-        return true;
-    }
-
-    /**
-     * Packs down a migration or seed file.
-     */
-    public function packDown($file, \Closure $callback = null)
-    {
-        $object = $this->resolve($file);
-
-        if ($object === null) {
-            return false;
-        }
-
-        $this->isValidScript($object);
-
-        Model::unguard();
-
-        $this->transaction(function () use ($object, $callback) {
-            if ($object instanceof Migration) {
-                $object->down();
-            }
-
-            $callback && $callback();
-        });
-
-        Model::reguard();
-
-        return true;
-    }
-
-    /**
-     * Resolve a migration instance from a file.
-     * @param  string  $file
-     * @return object
-     */
-    public function resolve($file)
-    {
-        if (! is_file($file)) {
-            return;
-        }
-
-        require_once $file;
-
-        if ($class = $this->getClassFromFile($file)) {
-            return new $class;
-        }
-    }
-
-    /**
-     * Checks if the object is a valid update script.
-     */
-    protected function isValidScript($object)
-    {
-        if ($object instanceof Migration) {
-            return true;
-        }
-        elseif ($object instanceof Seeder) {
-            return true;
-        }
-
-        throw new AdminException(sprintf(
-            'Database script [%s] must inherit %s or %s classes',
-            get_class($object),
-            Migration::class,
-            Seeder::class
-        ));
-    }
-
-    /**
-     * Extracts the namespace and class name from a file.
-     * @param string $file
-     * @return string
-     */
-    public function getClassFromFile($file)
-    {
-        $fileParser = fopen($file, 'r');
-        $class = $namespace = $buffer = '';
-        $i = 0;
-
-        while (! $class) {
-            if (feof($fileParser)) {
-                break;
-            }
-
-            $buffer .= fread($fileParser, 512);
-
-            // Prefix and suffix string to prevent unterminated comment warning
-            $tokens = token_get_all('/**/' . $buffer . '/**/');
-
-            if (strpos($buffer, '{') === false) {
-                continue;
-            }
-
-            for (; $i < count($tokens); $i++) {
-                /*
-                 * Namespace opening
-                 */
-                if ($tokens[$i][0] === T_NAMESPACE) {
-                    for ($j = $i + 1; $j < count($tokens); $j++) {
-                        if ($tokens[$j] === ';') {
-                            break;
-                        }
-
-                        $namespace .= is_array($tokens[$j]) ? $tokens[$j][1] : $tokens[$j];
-                    }
-                }
-
-                /*
-                 * Class opening
-                 */
-                if ($tokens[$i][0] === T_CLASS && $tokens[$i-1][1] !== '::') {
-                    $class = $tokens[$i+2][1];
-                    break;
-                }
-            }
-        }
-
-        if (!strlen(trim($namespace)) && !strlen(trim($class))) {
-            return false;
-        }
-
-        return trim($namespace) . '\\' . trim($class);
-    }
-
-    public function transaction($callback)
-    {
-        return DB::connection($this->connection())->transaction($callback);
-    }
-
-    public function connection()
-    {
-        return config('admin.database.connection') ?: config('database.default');
-    }
-}
+<?php
+
+namespace Dcat\Admin\Support;
+
+use Dcat\Admin\Exception\AdminException;
+use Illuminate\Database\Eloquent\Model;
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Seeder;
+use Illuminate\Support\Facades\DB;
+
+/**
+ * Database updater.
+ *
+ * Executes database migration and seed scripts based on their filename.
+ *
+ * @author Alexey Bobkov, Samuel Georges
+ */
+class DatabaseUpdater
+{
+    /**
+     * Sets up a migration or seed file.
+     */
+    public function setUp($file, \Closure $callback = null)
+    {
+        $object = $this->resolve($file);
+
+        if ($object === null) {
+            return false;
+        }
+
+        $this->isValidScript($object);
+
+        Model::unguard();
+
+        $this->transaction(function () use ($object, $callback) {
+            if ($object instanceof Migration) {
+                $object->up();
+            } elseif ($object instanceof Seeder) {
+                $object->run();
+            }
+
+            $callback && $callback();
+        });
+
+        Model::reguard();
+
+        return true;
+    }
+
+    /**
+     * Packs down a migration or seed file.
+     */
+    public function packDown($file, \Closure $callback = null)
+    {
+        $object = $this->resolve($file);
+
+        if ($object === null) {
+            return false;
+        }
+
+        $this->isValidScript($object);
+
+        Model::unguard();
+
+        $this->transaction(function () use ($object, $callback) {
+            if ($object instanceof Migration) {
+                $object->down();
+            }
+
+            $callback && $callback();
+        });
+
+        Model::reguard();
+
+        return true;
+    }
+
+    /**
+     * Resolve a migration instance from a file.
+     * @param  string  $file
+     * @return object
+     */
+    public function resolve($file)
+    {
+        if (! is_file($file)) {
+            return;
+        }
+
+        require_once $file;
+
+        if ($class = $this->getClassFromFile($file)) {
+            return new $class;
+        }
+    }
+
+    /**
+     * Checks if the object is a valid update script.
+     */
+    protected function isValidScript($object)
+    {
+        if ($object instanceof Migration) {
+            return true;
+        } elseif ($object instanceof Seeder) {
+            return true;
+        }
+
+        throw new AdminException(sprintf(
+            'Database script [%s] must inherit %s or %s classes',
+            get_class($object),
+            Migration::class,
+            Seeder::class
+        ));
+    }
+
+    /**
+     * Extracts the namespace and class name from a file.
+     * @param string $file
+     * @return string
+     */
+    public function getClassFromFile($file)
+    {
+        $fileParser = fopen($file, 'r');
+        $class = $namespace = $buffer = '';
+        $i = 0;
+
+        while (! $class) {
+            if (feof($fileParser)) {
+                break;
+            }
+
+            $buffer .= fread($fileParser, 512);
+
+            // Prefix and suffix string to prevent unterminated comment warning
+            $tokens = token_get_all('/**/'.$buffer.'/**/');
+
+            if (strpos($buffer, '{') === false) {
+                continue;
+            }
+
+            for (; $i < count($tokens); $i++) {
+                /*
+                 * Namespace opening
+                 */
+                if ($tokens[$i][0] === T_NAMESPACE) {
+                    for ($j = $i + 1; $j < count($tokens); $j++) {
+                        if ($tokens[$j] === ';') {
+                            break;
+                        }
+
+                        $namespace .= is_array($tokens[$j]) ? $tokens[$j][1] : $tokens[$j];
+                    }
+                }
+
+                /*
+                 * Class opening
+                 */
+                if ($tokens[$i][0] === T_CLASS && $tokens[$i - 1][1] !== '::') {
+                    $class = $tokens[$i + 2][1];
+                    break;
+                }
+            }
+        }
+
+        if (! strlen(trim($namespace)) && ! strlen(trim($class))) {
+            return false;
+        }
+
+        return trim($namespace).'\\'.trim($class);
+    }
+
+    public function transaction($callback)
+    {
+        return DB::connection($this->connection())->transaction($callback);
+    }
+
+    public function connection()
+    {
+        return config('admin.database.connection') ?: config('database.default');
+    }
+}

+ 90 - 90
src/Support/Setting.php

@@ -1,90 +1,90 @@
-<?php
-
-namespace Dcat\Admin\Support;
-
-use Dcat\Admin\Admin;
-use Dcat\Admin\Models\Setting as Model;
-use Illuminate\Database\QueryException;
-use Illuminate\Support\Arr;
-use Illuminate\Support\Fluent;
-
-class Setting extends Fluent
-{
-    /**
-     * 获取配置.
-     *
-     * @param string $key
-     * @param null $default
-     *
-     * @return mixed
-     */
-    public function get($key, $default = null)
-    {
-        return Arr::get($this->attributes, $key, $default);
-    }
-
-    /**
-     * 设置配置信息.
-     *
-     * @param array $data
-     *
-     * @return $this
-     */
-    public function set($key, $value = null)
-    {
-        $data = is_array($key) ? $key : [$key => $value];
-
-        foreach ($data as $key => $value) {
-            Arr::set($this->attributes, $key, $value);
-        }
-
-        return $this;
-    }
-
-    /**
-     * 保存配置到数据库
-     *
-     * @param array $data
-     *
-     * @return $this
-     */
-    public function save(array $data = [])
-    {
-        if ($data) {
-            $this->set($data);
-        }
-
-        foreach ($this->attributes as $key => $value) {
-            if (is_array($value)) {
-                $value = json_encode($value);
-            }
-
-            $model = Model::query()
-                ->where('slug', $key)
-                ->first() ?: new Model();
-
-            $model->fill([
-                'slug'  => $key,
-                'value' => (string) $value,
-            ])->save();
-        }
-
-        return $this;
-    }
-
-    /**
-     * @return static
-     */
-    public static function fromDatabase()
-    {
-        $values = [];
-
-        try {
-            $values = Model::pluck('value', 'slug')->toArray();
-        } catch (QueryException $e) {
-            Admin::reportException($e);
-        }
-
-        return new static($values);
-    }
-}
+<?php
+
+namespace Dcat\Admin\Support;
+
+use Dcat\Admin\Admin;
+use Dcat\Admin\Models\Setting as Model;
+use Illuminate\Database\QueryException;
+use Illuminate\Support\Arr;
+use Illuminate\Support\Fluent;
+
+class Setting extends Fluent
+{
+    /**
+     * 获取配置.
+     *
+     * @param string $key
+     * @param null $default
+     *
+     * @return mixed
+     */
+    public function get($key, $default = null)
+    {
+        return Arr::get($this->attributes, $key, $default);
+    }
+
+    /**
+     * 设置配置信息.
+     *
+     * @param array $data
+     *
+     * @return $this
+     */
+    public function set($key, $value = null)
+    {
+        $data = is_array($key) ? $key : [$key => $value];
+
+        foreach ($data as $key => $value) {
+            Arr::set($this->attributes, $key, $value);
+        }
+
+        return $this;
+    }
+
+    /**
+     * 保存配置到数据库.
+     *
+     * @param array $data
+     *
+     * @return $this
+     */
+    public function save(array $data = [])
+    {
+        if ($data) {
+            $this->set($data);
+        }
+
+        foreach ($this->attributes as $key => $value) {
+            if (is_array($value)) {
+                $value = json_encode($value);
+            }
+
+            $model = Model::query()
+                ->where('slug', $key)
+                ->first() ?: new Model();
+
+            $model->fill([
+                'slug'  => $key,
+                'value' => (string) $value,
+            ])->save();
+        }
+
+        return $this;
+    }
+
+    /**
+     * @return static
+     */
+    public static function fromDatabase()
+    {
+        $values = [];
+
+        try {
+            $values = Model::pluck('value', 'slug')->toArray();
+        } catch (QueryException $e) {
+            Admin::reportException($e);
+        }
+
+        return new static($values);
+    }
+}

+ 250 - 254
src/Support/Zip.php

@@ -1,254 +1,250 @@
-<?php
-
-namespace Dcat\Admin\Support;
-
-/**
- * Zip helper
- *
- * @package october\filesystem
- * @author Alexey Bobkov, Samuel Georges
- *
- * Usage:
- *
- *   Zip::make('file.zip', '/some/path/*.php');
- *
- *   Zip::make('file.zip', function($zip) {
- *
- *       // Add all PHP files and directories
- *       $zip->add('/some/path/*.php');
- *
- *       // Do not include subdirectories, one level only
- *       $zip->add('/non/recursive/*', ['recursive' => false]);
- *
- *       // Add multiple paths
- *       $zip->add([
- *           '/collection/of/paths/*',
- *           '/a/single/file.php'
- *       ]);
- *
- *       // Add all INI files to a zip folder "config"
- *       $zip->folder('/config', '/path/to/config/*.ini');
- *
- *       // Add multiple paths to a zip folder "images"
- *       $zip->folder('/images', function($zip) {
- *           $zip->add('/my/gifs/*.gif', );
- *           $zip->add('/photo/reel/*.{png,jpg}', );
- *       });
- *
- *       // Remove these files/folders from the zip
- *       $zip->remove([
- *           '.htaccess',
- *           'config.php',
- *           'some/folder'
- *       ]);
- *
- *   });
- *
- *   Zip::extract('file.zip', '/destination/path');
- *
- */
-
-use ZipArchive;
-
-class Zip extends ZipArchive
-{
-    /**
-     * @var string Folder prefix
-     */
-    protected $folderPrefix = '';
-
-    /**
-     * Extract an existing zip file.
-     * @param  string $source Path for the existing zip
-     * @param  string $destination Path to extract the zip files
-     * @param  array  $options
-     * @return bool
-     */
-    public static function extract($source, $destination, $options = [])
-    {
-        extract(array_merge([
-            'mask' => 0777
-        ], $options));
-
-        if (file_exists($destination) || mkdir($destination, $mask, true)) {
-            $zip = new ZipArchive;
-            if ($zip->open($source) === true) {
-                $zip->extractTo($destination);
-                $zip->close();
-                return true;
-            }
-        }
-
-        return false;
-    }
-
-    /**
-     * Creates a new empty zip file.
-     * @param  string $destination Path for the new zip
-     * @param  mixed  $source
-     * @param  array  $options
-     * @return self
-     */
-    public static function make($destination, $source, $options = [])
-    {
-        $zip = new self;
-        $zip->open($destination, ZIPARCHIVE::CREATE | ZipArchive::OVERWRITE);
-
-        if (is_string($source)) {
-            $zip->add($source, $options);
-        }
-        elseif (is_callable($source)) {
-            $source($zip);
-        }
-        elseif (is_array($source)) {
-            foreach ($source as $_source) {
-                $zip->add($_source, $options);
-            }
-        }
-
-        $zip->close();
-        return $zip;
-    }
-
-    /**
-     * Includes a source to the Zip
-     * @param mixed $source
-     * @param array $options
-     * @return self
-     */
-    public function add($source, $options = [])
-    {
-        /*
-         * A directory has been supplied, convert it to a useful glob
-         *
-         * The wildcard for including hidden files:
-         * - isn't hidden with an '.'
-         * - is hidden with a '.' but is followed by a non '.' character
-         * - starts with '..' but has at least one character after it
-         */
-        if (is_dir($source)) {
-            $includeHidden = isset($options['includeHidden']) && $options['includeHidden'];
-            $wildcard = $includeHidden ? '{*,.[!.]*,..?*}' : '*';
-            $source = implode('/', [dirname($source), basename($source), $wildcard]);
-        }
-
-        extract(array_merge([
-            'recursive' => true,
-            'includeHidden' => false,
-            'basedir' => dirname($source),
-            'baseglob' => basename($source)
-        ], $options));
-
-        if (is_file($source)) {
-            $files = [$source];
-            $recursive = false;
-        }
-        else {
-            $files = glob($source, GLOB_BRACE);
-            $folders = glob(dirname($source) . '/*', GLOB_ONLYDIR);
-        }
-
-        foreach ($files as $file) {
-            if (!is_file($file)) {
-                continue;
-            }
-
-            $localpath = $this->removePathPrefix($basedir.'/', dirname($file).'/');
-            $localfile = $this->folderPrefix . $localpath . basename($file);
-            $this->addFile($file, $localfile);
-        }
-
-        if (!$recursive) {
-            return $this;
-        }
-
-        foreach ($folders as $folder) {
-            if (!is_dir($folder)) {
-                continue;
-            }
-
-            $localpath = $this->folderPrefix . $this->removePathPrefix($basedir.'/', $folder.'/');
-            $this->addEmptyDir($localpath);
-            $this->add($folder.'/'.$baseglob, array_merge($options, ['basedir' => $basedir]));
-        }
-
-        return $this;
-    }
-
-    /**
-     * Creates a new folder inside the Zip and adds source files (optional)
-     * @param  string $name Folder name
-     * @param  mixed  $source
-     * @return self
-     */
-    public function folder($name, $source = null)
-    {
-        $prefix = $this->folderPrefix;
-        $this->addEmptyDir($prefix . $name);
-        if ($source === null) {
-            return $this;
-        }
-
-        $this->folderPrefix = $prefix . $name . '/';
-
-        if (is_string($source)) {
-            $this->add($source);
-        }
-        elseif (is_callable($source)) {
-            $source($this);
-        }
-        elseif (is_array($source)) {
-            foreach ($source as $_source) {
-                $this->add($_source);
-            }
-        }
-
-        $this->folderPrefix = $prefix;
-        return $this;
-    }
-
-    /**
-     * Removes a file or folder from the zip collection.
-     * Does not support wildcards.
-     * @param  string $source
-     * @return self
-     */
-    public function remove($source)
-    {
-        if (is_array($source)) {
-            foreach ($source as $_source) {
-                $this->remove($_source);
-            }
-        }
-
-        if (!is_string($source)) {
-            return $this;
-        }
-
-        if (substr($source, 0, 1) == '/') {
-            $source = substr($source, 1);
-        }
-
-        for ($i = 0; $i < $this->numFiles; $i++) {
-            $stats = $this->statIndex($i);
-            if (substr($stats['name'], 0, strlen($source)) == $source) {
-                $this->deleteIndex($i);
-            }
-        }
-
-        return $this;
-    }
-
-    /**
-     * Removes a prefix from a path.
-     * @param  string $prefix /var/sites/
-     * @param  string $path /var/sites/moo/cow/
-     * @return string moo/cow/
-     */
-    protected function removePathPrefix($prefix, $path)
-    {
-        return (strpos($path, $prefix) === 0)
-            ? substr($path, strlen($prefix))
-            : $path;
-    }
-}
+<?php
+
+namespace Dcat\Admin\Support;
+
+/**
+ * Zip helper.
+ *
+ * @author Alexey Bobkov, Samuel Georges
+ *
+ * Usage:
+ *
+ *   Zip::make('file.zip', '/some/path/*.php');
+ *
+ *   Zip::make('file.zip', function($zip) {
+ *
+ *       // Add all PHP files and directories
+ *       $zip->add('/some/path/*.php');
+ *
+ *       // Do not include subdirectories, one level only
+ *       $zip->add('/non/recursive/*', ['recursive' => false]);
+ *
+ *       // Add multiple paths
+ *       $zip->add([
+ *           '/collection/of/paths/*',
+ *           '/a/single/file.php'
+ *       ]);
+ *
+ *       // Add all INI files to a zip folder "config"
+ *       $zip->folder('/config', '/path/to/config/*.ini');
+ *
+ *       // Add multiple paths to a zip folder "images"
+ *       $zip->folder('/images', function($zip) {
+ *           $zip->add('/my/gifs/*.gif', );
+ *           $zip->add('/photo/reel/*.{png,jpg}', );
+ *       });
+ *
+ *       // Remove these files/folders from the zip
+ *       $zip->remove([
+ *           '.htaccess',
+ *           'config.php',
+ *           'some/folder'
+ *       ]);
+ *
+ *   });
+ *
+ *   Zip::extract('file.zip', '/destination/path');
+ */
+
+use ZipArchive;
+
+class Zip extends ZipArchive
+{
+    /**
+     * @var string Folder prefix
+     */
+    protected $folderPrefix = '';
+
+    /**
+     * Extract an existing zip file.
+     * @param  string $source Path for the existing zip
+     * @param  string $destination Path to extract the zip files
+     * @param  array  $options
+     * @return bool
+     */
+    public static function extract($source, $destination, $options = [])
+    {
+        extract(array_merge([
+            'mask' => 0777,
+        ], $options));
+
+        if (file_exists($destination) || mkdir($destination, $mask, true)) {
+            $zip = new ZipArchive;
+            if ($zip->open($source) === true) {
+                $zip->extractTo($destination);
+                $zip->close();
+
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * Creates a new empty zip file.
+     * @param  string $destination Path for the new zip
+     * @param  mixed  $source
+     * @param  array  $options
+     * @return self
+     */
+    public static function make($destination, $source, $options = [])
+    {
+        $zip = new self;
+        $zip->open($destination, ZIPARCHIVE::CREATE | ZipArchive::OVERWRITE);
+
+        if (is_string($source)) {
+            $zip->add($source, $options);
+        } elseif (is_callable($source)) {
+            $source($zip);
+        } elseif (is_array($source)) {
+            foreach ($source as $_source) {
+                $zip->add($_source, $options);
+            }
+        }
+
+        $zip->close();
+
+        return $zip;
+    }
+
+    /**
+     * Includes a source to the Zip.
+     * @param mixed $source
+     * @param array $options
+     * @return self
+     */
+    public function add($source, $options = [])
+    {
+        /*
+         * A directory has been supplied, convert it to a useful glob
+         *
+         * The wildcard for including hidden files:
+         * - isn't hidden with an '.'
+         * - is hidden with a '.' but is followed by a non '.' character
+         * - starts with '..' but has at least one character after it
+         */
+        if (is_dir($source)) {
+            $includeHidden = isset($options['includeHidden']) && $options['includeHidden'];
+            $wildcard = $includeHidden ? '{*,.[!.]*,..?*}' : '*';
+            $source = implode('/', [dirname($source), basename($source), $wildcard]);
+        }
+
+        extract(array_merge([
+            'recursive' => true,
+            'includeHidden' => false,
+            'basedir' => dirname($source),
+            'baseglob' => basename($source),
+        ], $options));
+
+        if (is_file($source)) {
+            $files = [$source];
+            $recursive = false;
+        } else {
+            $files = glob($source, GLOB_BRACE);
+            $folders = glob(dirname($source).'/*', GLOB_ONLYDIR);
+        }
+
+        foreach ($files as $file) {
+            if (! is_file($file)) {
+                continue;
+            }
+
+            $localpath = $this->removePathPrefix($basedir.'/', dirname($file).'/');
+            $localfile = $this->folderPrefix.$localpath.basename($file);
+            $this->addFile($file, $localfile);
+        }
+
+        if (! $recursive) {
+            return $this;
+        }
+
+        foreach ($folders as $folder) {
+            if (! is_dir($folder)) {
+                continue;
+            }
+
+            $localpath = $this->folderPrefix.$this->removePathPrefix($basedir.'/', $folder.'/');
+            $this->addEmptyDir($localpath);
+            $this->add($folder.'/'.$baseglob, array_merge($options, ['basedir' => $basedir]));
+        }
+
+        return $this;
+    }
+
+    /**
+     * Creates a new folder inside the Zip and adds source files (optional).
+     * @param  string $name Folder name
+     * @param  mixed  $source
+     * @return self
+     */
+    public function folder($name, $source = null)
+    {
+        $prefix = $this->folderPrefix;
+        $this->addEmptyDir($prefix.$name);
+        if ($source === null) {
+            return $this;
+        }
+
+        $this->folderPrefix = $prefix.$name.'/';
+
+        if (is_string($source)) {
+            $this->add($source);
+        } elseif (is_callable($source)) {
+            $source($this);
+        } elseif (is_array($source)) {
+            foreach ($source as $_source) {
+                $this->add($_source);
+            }
+        }
+
+        $this->folderPrefix = $prefix;
+
+        return $this;
+    }
+
+    /**
+     * Removes a file or folder from the zip collection.
+     * Does not support wildcards.
+     * @param  string $source
+     * @return self
+     */
+    public function remove($source)
+    {
+        if (is_array($source)) {
+            foreach ($source as $_source) {
+                $this->remove($_source);
+            }
+        }
+
+        if (! is_string($source)) {
+            return $this;
+        }
+
+        if (substr($source, 0, 1) == '/') {
+            $source = substr($source, 1);
+        }
+
+        for ($i = 0; $i < $this->numFiles; $i++) {
+            $stats = $this->statIndex($i);
+            if (substr($stats['name'], 0, strlen($source)) == $source) {
+                $this->deleteIndex($i);
+            }
+        }
+
+        return $this;
+    }
+
+    /**
+     * Removes a prefix from a path.
+     * @param  string $prefix /var/sites/
+     * @param  string $path /var/sites/moo/cow/
+     * @return string moo/cow/
+     */
+    protected function removePathPrefix($prefix, $path)
+    {
+        return (strpos($path, $prefix) === 0)
+            ? substr($path, strlen($prefix))
+            : $path;
+    }
+}

+ 183 - 183
src/Traits/HasHtml.php

@@ -1,183 +1,183 @@
-<?php
-
-namespace Dcat\Admin\Traits;
-
-use Dcat\Admin\Support\Helper;
-use DOMElement;
-use DOMDocument;
-
-trait HasHtml
-{
-    protected static $shouldResolveTags = ['style', 'script', 'template'];
-
-    /**
-     * @param string|array $content
-     *
-     * @return null|string
-     */
-    public static function html($content = null)
-    {
-        $html = static::context()->html ?: [];
-
-        if ($content === null) {
-            return implode('', array_unique($html));
-        }
-
-        static::context()->html = array_merge(
-            $html,
-            array_map([Helper::class, 'render'], (array) $content)
-        );
-    }
-
-    /**
-     * @param string $view
-     * @param array  $data
-     *
-     * @return string
-     *
-     * @throws \Throwable
-     */
-    public static function view(string $view, array $data = [])
-    {
-        return static::resolveHtml(view($view, $data))['html'];
-    }
-
-    /**
-     * @param string|\Illuminate\Contracts\Support\Renderable $content
-     * @param array                                           $data
-     * @param array                                           $options
-     *
-     * @throws \Throwable
-     *
-     * @return array ['html' => $html, 'script' => $script]
-     */
-    public static function resolveHtml($content, array $options = []): array
-    {
-        $dom = static::getDOMDocument(Helper::render($content));
-
-        $head = static::resolveElement($dom->getElementsByTagName('head')->item(0) ?: null);
-        $body = static::resolveElement($dom->getElementsByTagName('body')->item(0) ?: null);
-
-        $script = $head['script'].$body['script'];
-
-        $runScript = $options['runScript'] ?? true;
-        if ($runScript) {
-            static::script($script);
-
-            $script = '';
-        }
-
-        return ['html' => $head['html'].$body['html'], 'script' => $script];
-    }
-
-    /**
-     * @param string $html
-     *
-     * @throws \Throwable
-     *
-     * @return DOMDocument
-     */
-    protected static function getDOMDocument(string $html)
-    {
-        $dom = new DOMDocument();
-
-        libxml_use_internal_errors(true);
-
-        $dom->loadHTML('<?xml encoding="utf-8" ?>'.$html);
-
-        libxml_use_internal_errors(false);
-
-        return $dom;
-    }
-
-    /**
-     * @param DOMElement $element
-     *
-     * @return void|string
-     */
-    protected static function resolve(DOMElement $element)
-    {
-        $method = 'resolve'.ucfirst($element->tagName);
-
-        return static::{$method}($element);
-    }
-
-    /**
-     * @param DOMElement $element
-     *
-     * @return string|void
-     */
-    protected static function resolveScript(DOMElement $element)
-    {
-        if ($element->hasAttribute('src')) {
-            static::js($element->getAttribute('src'));
-
-            return;
-        }
-
-        if (! empty($script = trim($element->nodeValue))) {
-            if ($require = $element->getAttribute('require')) {
-                static::asset()->require(explode(',', $require));
-            }
-
-            $script = "(function () {{$script}\n})();";
-
-            if ($element->hasAttribute('once')) {
-                return static::script($script);
-            }
-
-            return $script;
-        }
-    }
-
-    /**
-     * @param DOMElement $element
-     *
-     * @return void
-     */
-    protected static function resolveStyle(DOMElement $element)
-    {
-        if (! empty(trim($element->nodeValue))) {
-            static::style($element->nodeValue);
-        }
-    }
-
-    /**
-     * @param DOMElement $element
-     *
-     * @return void
-     */
-    protected static function resolveTemplate(DOMElement $element)
-    {
-        $html = '';
-        foreach ($element->childNodes as $childNode) {
-            $html .= $element->ownerDocument->saveHTML($childNode);
-        }
-
-        $html && static::html($html);
-    }
-
-    protected static function resolveElement(?DOMElement $element)
-    {
-        $html = $script = '';
-
-        if (! $element) {
-            return ['html' => $html, 'script' => $script];
-        }
-
-        foreach ($element->childNodes as $child) {
-            if (
-                $child instanceof DOMElement
-                && in_array($child->tagName, static::$shouldResolveTags, true)
-            ) {
-                $script .= static::resolve($child);
-
-                continue;
-            }
-
-            $html .= trim($element->ownerDocument->saveHTML($child));
-        }
-
-        return ['html' => $html, 'script' => $script];
-    }
-}
+<?php
+
+namespace Dcat\Admin\Traits;
+
+use Dcat\Admin\Support\Helper;
+use DOMDocument;
+use DOMElement;
+
+trait HasHtml
+{
+    protected static $shouldResolveTags = ['style', 'script', 'template'];
+
+    /**
+     * @param string|array $content
+     *
+     * @return null|string
+     */
+    public static function html($content = null)
+    {
+        $html = static::context()->html ?: [];
+
+        if ($content === null) {
+            return implode('', array_unique($html));
+        }
+
+        static::context()->html = array_merge(
+            $html,
+            array_map([Helper::class, 'render'], (array) $content)
+        );
+    }
+
+    /**
+     * @param string $view
+     * @param array  $data
+     *
+     * @return string
+     *
+     * @throws \Throwable
+     */
+    public static function view(string $view, array $data = [])
+    {
+        return static::resolveHtml(view($view, $data))['html'];
+    }
+
+    /**
+     * @param string|\Illuminate\Contracts\Support\Renderable $content
+     * @param array                                           $data
+     * @param array                                           $options
+     *
+     * @throws \Throwable
+     *
+     * @return array ['html' => $html, 'script' => $script]
+     */
+    public static function resolveHtml($content, array $options = []): array
+    {
+        $dom = static::getDOMDocument(Helper::render($content));
+
+        $head = static::resolveElement($dom->getElementsByTagName('head')->item(0) ?: null);
+        $body = static::resolveElement($dom->getElementsByTagName('body')->item(0) ?: null);
+
+        $script = $head['script'].$body['script'];
+
+        $runScript = $options['runScript'] ?? true;
+        if ($runScript) {
+            static::script($script);
+
+            $script = '';
+        }
+
+        return ['html' => $head['html'].$body['html'], 'script' => $script];
+    }
+
+    /**
+     * @param string $html
+     *
+     * @throws \Throwable
+     *
+     * @return DOMDocument
+     */
+    protected static function getDOMDocument(string $html)
+    {
+        $dom = new DOMDocument();
+
+        libxml_use_internal_errors(true);
+
+        $dom->loadHTML('<?xml encoding="utf-8" ?>'.$html);
+
+        libxml_use_internal_errors(false);
+
+        return $dom;
+    }
+
+    /**
+     * @param DOMElement $element
+     *
+     * @return void|string
+     */
+    protected static function resolve(DOMElement $element)
+    {
+        $method = 'resolve'.ucfirst($element->tagName);
+
+        return static::{$method}($element);
+    }
+
+    /**
+     * @param DOMElement $element
+     *
+     * @return string|void
+     */
+    protected static function resolveScript(DOMElement $element)
+    {
+        if ($element->hasAttribute('src')) {
+            static::js($element->getAttribute('src'));
+
+            return;
+        }
+
+        if (! empty($script = trim($element->nodeValue))) {
+            if ($require = $element->getAttribute('require')) {
+                static::asset()->require(explode(',', $require));
+            }
+
+            $script = "(function () {{$script}\n})();";
+
+            if ($element->hasAttribute('once')) {
+                return static::script($script);
+            }
+
+            return $script;
+        }
+    }
+
+    /**
+     * @param DOMElement $element
+     *
+     * @return void
+     */
+    protected static function resolveStyle(DOMElement $element)
+    {
+        if (! empty(trim($element->nodeValue))) {
+            static::style($element->nodeValue);
+        }
+    }
+
+    /**
+     * @param DOMElement $element
+     *
+     * @return void
+     */
+    protected static function resolveTemplate(DOMElement $element)
+    {
+        $html = '';
+        foreach ($element->childNodes as $childNode) {
+            $html .= $element->ownerDocument->saveHTML($childNode);
+        }
+
+        $html && static::html($html);
+    }
+
+    protected static function resolveElement(?DOMElement $element)
+    {
+        $html = $script = '';
+
+        if (! $element) {
+            return ['html' => $html, 'script' => $script];
+        }
+
+        foreach ($element->childNodes as $child) {
+            if (
+                $child instanceof DOMElement
+                && in_array($child->tagName, static::$shouldResolveTags, true)
+            ) {
+                $script .= static::resolve($child);
+
+                continue;
+            }
+
+            $html .= trim($element->ownerDocument->saveHTML($child));
+        }
+
+        return ['html' => $html, 'script' => $script];
+    }
+}

+ 39 - 39
src/Traits/HasVariables.php

@@ -1,39 +1,39 @@
-<?php
-
-namespace Dcat\Admin\Traits;
-
-/**
- * @method array defaultVariables()
- */
-trait HasVariables
-{
-    protected $variables = [];
-
-    /**
-     * 获取所有变量.
-     *
-     * @return array
-     */
-    public function variables()
-    {
-        if (! method_exists($this, 'defaultVariables')) {
-            return $this->variables;
-        }
-
-        return array_merge($this->defaultVariables(), $this->variables);
-    }
-
-    /**
-     * 设置变量.
-     *
-     * @param array $variables
-     *
-     * @return $this
-     */
-    public function addVariables(array $variables = [])
-    {
-        $this->variables = array_merge($this->variables, $variables);
-
-        return $this;
-    }
-}
+<?php
+
+namespace Dcat\Admin\Traits;
+
+/**
+ * @method array defaultVariables()
+ */
+trait HasVariables
+{
+    protected $variables = [];
+
+    /**
+     * 获取所有变量.
+     *
+     * @return array
+     */
+    public function variables()
+    {
+        if (! method_exists($this, 'defaultVariables')) {
+            return $this->variables;
+        }
+
+        return array_merge($this->defaultVariables(), $this->variables);
+    }
+
+    /**
+     * 设置变量.
+     *
+     * @param array $variables
+     *
+     * @return $this
+     */
+    public function addVariables(array $variables = [])
+    {
+        $this->variables = array_merge($this->variables, $variables);
+
+        return $this;
+    }
+}

+ 1 - 1
src/Tree.php

@@ -9,8 +9,8 @@ use Dcat\Admin\Repositories\EloquentRepository;
 use Dcat\Admin\Support\Helper;
 use Dcat\Admin\Traits\HasBuilderEvents;
 use Dcat\Admin\Traits\HasVariables;
-use Dcat\Admin\Tree\Actions;
 use Dcat\Admin\Tree\AbstractTool;
+use Dcat\Admin\Tree\Actions;
 use Dcat\Admin\Tree\Tools;
 use Illuminate\Contracts\Support\Htmlable;
 use Illuminate\Contracts\Support\Renderable;

+ 157 - 157
src/Tree/Actions.php

@@ -1,157 +1,157 @@
-<?php
-
-namespace Dcat\Admin\Tree;
-
-use Dcat\Admin\Support\Helper;
-use Dcat\Admin\Tree;
-use Illuminate\Contracts\Support\Renderable;
-
-class Actions implements Renderable
-{
-    /**
-     * @var Tree
-     */
-    protected $parent;
-
-    /**
-     * @var \Illuminate\Database\Eloquent\Model
-     */
-    public $row;
-
-    /**
-     * @var array
-     */
-    protected $appends = [];
-
-    /**
-     * @var array
-     */
-    protected $prepends = [];
-
-    /**
-     * @var array
-     */
-    protected $actions = [
-        'delete'    => true,
-        'quickEdit' => true,
-        'edit'      => false,
-    ];
-
-    /**
-     * @var array
-     */
-    protected $defaultActions = [
-        'edit'      => Tree\Actions\Edit::class,
-        'quickEdit' => Tree\Actions\QuickEdit::class,
-        'delete'    => Tree\Actions\Delete::class,
-    ];
-
-    /**
-     * @param string|Renderable|\Dcat\Admin\Actions\Action|\Illuminate\Contracts\Support\Htmlable $action
-     *
-     * @return $this
-     */
-    public function append($action)
-    {
-        $this->prepareAction($action);
-
-        array_push($this->appends, $action);
-
-        return $this;
-    }
-
-    /**
-     * @param string|Renderable|\Dcat\Admin\Actions\Action|\Illuminate\Contracts\Support\Htmlable $action
-     *
-     * @return $this
-     */
-    public function prepend($action)
-    {
-        $this->prepareAction($action);
-
-        array_unshift($this->prepends, $action);
-
-        return $this;
-    }
-
-    public function getKey()
-    {
-        return $this->row->{$this->getParent()->getKeyName()};
-    }
-
-    public function disableQuickEdit(bool $value = true)
-    {
-        $this->actions['quickEdit'] = ! $value;
-
-        return $this;
-    }
-
-    public function disableEdit(bool $value = true)
-    {
-        $this->actions['edit'] = ! $value;
-
-        return $this;
-    }
-
-    public function disableDelete(bool $value = true)
-    {
-        $this->actions['delete'] = ! $value;
-
-        return $this;
-    }
-
-    public function render()
-    {
-        $this->prependDefaultActions();
-
-        $toString = [Helper::class, 'render'];
-
-        $prepends = array_map($toString, $this->prepends);
-        $appends = array_map($toString, $this->appends);
-
-        return implode('', array_merge($prepends, $appends));
-    }
-
-    protected function prepareAction($action)
-    {
-        if ($action instanceof RowAction) {
-            $action->setParent($this);
-            $action->setRow($this->row);
-        }
-    }
-
-    protected function prependDefaultActions()
-    {
-        foreach ($this->actions as $action => $enable) {
-            if (! $enable) {
-                continue;
-            }
-
-            $action = new $this->defaultActions[$action]();
-
-            $this->prepareAction($action);
-
-            $this->prepend($action);
-        }
-    }
-
-    public function getParent()
-    {
-        return $this->parent;
-    }
-
-    public function setParent(Tree $tree)
-    {
-        $this->parent = $tree;
-    }
-
-    public function getRow()
-    {
-        return $this->row;
-    }
-
-    public function setRow($row)
-    {
-        $this->row = $row;
-    }
-}
+<?php
+
+namespace Dcat\Admin\Tree;
+
+use Dcat\Admin\Support\Helper;
+use Dcat\Admin\Tree;
+use Illuminate\Contracts\Support\Renderable;
+
+class Actions implements Renderable
+{
+    /**
+     * @var Tree
+     */
+    protected $parent;
+
+    /**
+     * @var \Illuminate\Database\Eloquent\Model
+     */
+    public $row;
+
+    /**
+     * @var array
+     */
+    protected $appends = [];
+
+    /**
+     * @var array
+     */
+    protected $prepends = [];
+
+    /**
+     * @var array
+     */
+    protected $actions = [
+        'delete'    => true,
+        'quickEdit' => true,
+        'edit'      => false,
+    ];
+
+    /**
+     * @var array
+     */
+    protected $defaultActions = [
+        'edit'      => Tree\Actions\Edit::class,
+        'quickEdit' => Tree\Actions\QuickEdit::class,
+        'delete'    => Tree\Actions\Delete::class,
+    ];
+
+    /**
+     * @param string|Renderable|\Dcat\Admin\Actions\Action|\Illuminate\Contracts\Support\Htmlable $action
+     *
+     * @return $this
+     */
+    public function append($action)
+    {
+        $this->prepareAction($action);
+
+        array_push($this->appends, $action);
+
+        return $this;
+    }
+
+    /**
+     * @param string|Renderable|\Dcat\Admin\Actions\Action|\Illuminate\Contracts\Support\Htmlable $action
+     *
+     * @return $this
+     */
+    public function prepend($action)
+    {
+        $this->prepareAction($action);
+
+        array_unshift($this->prepends, $action);
+
+        return $this;
+    }
+
+    public function getKey()
+    {
+        return $this->row->{$this->getParent()->getKeyName()};
+    }
+
+    public function disableQuickEdit(bool $value = true)
+    {
+        $this->actions['quickEdit'] = ! $value;
+
+        return $this;
+    }
+
+    public function disableEdit(bool $value = true)
+    {
+        $this->actions['edit'] = ! $value;
+
+        return $this;
+    }
+
+    public function disableDelete(bool $value = true)
+    {
+        $this->actions['delete'] = ! $value;
+
+        return $this;
+    }
+
+    public function render()
+    {
+        $this->prependDefaultActions();
+
+        $toString = [Helper::class, 'render'];
+
+        $prepends = array_map($toString, $this->prepends);
+        $appends = array_map($toString, $this->appends);
+
+        return implode('', array_merge($prepends, $appends));
+    }
+
+    protected function prepareAction($action)
+    {
+        if ($action instanceof RowAction) {
+            $action->setParent($this);
+            $action->setRow($this->row);
+        }
+    }
+
+    protected function prependDefaultActions()
+    {
+        foreach ($this->actions as $action => $enable) {
+            if (! $enable) {
+                continue;
+            }
+
+            $action = new $this->defaultActions[$action]();
+
+            $this->prepareAction($action);
+
+            $this->prepend($action);
+        }
+    }
+
+    public function getParent()
+    {
+        return $this->parent;
+    }
+
+    public function setParent(Tree $tree)
+    {
+        $this->parent = $tree;
+    }
+
+    public function getRow()
+    {
+        return $this->row;
+    }
+
+    public function setRow($row)
+    {
+        $this->row = $row;
+    }
+}

+ 15 - 15
src/Tree/Actions/Delete.php

@@ -1,15 +1,15 @@
-<?php
-
-namespace Dcat\Admin\Tree\Actions;
-
-use Dcat\Admin\Tree\RowAction;
-
-class Delete extends RowAction
-{
-    public function html()
-    {
-        return <<<HTML
-<a href="javascript:void(0);" data-message="ID - {$this->getKey()}" data-url="{$this->resource()}/{$this->getKey()}" data-action="delete"><i class="feather icon-trash"></i>&nbsp;</a>
-HTML;
-    }
-}
+<?php
+
+namespace Dcat\Admin\Tree\Actions;
+
+use Dcat\Admin\Tree\RowAction;
+
+class Delete extends RowAction
+{
+    public function html()
+    {
+        return <<<HTML
+<a href="javascript:void(0);" data-message="ID - {$this->getKey()}" data-url="{$this->resource()}/{$this->getKey()}" data-action="delete"><i class="feather icon-trash"></i>&nbsp;</a>
+HTML;
+    }
+}

+ 15 - 15
src/Tree/Actions/Edit.php

@@ -1,15 +1,15 @@
-<?php
-
-namespace Dcat\Admin\Tree\Actions;
-
-use Dcat\Admin\Tree\RowAction;
-
-class Edit extends RowAction
-{
-    public function html()
-    {
-        return <<<HTML
-<a href="{$this->resource()}/{$this->getKey()}/edit"><i class="feather icon-edit-1"></i>&nbsp;</a>
-HTML;
-    }
-}
+<?php
+
+namespace Dcat\Admin\Tree\Actions;
+
+use Dcat\Admin\Tree\RowAction;
+
+class Edit extends RowAction
+{
+    public function html()
+    {
+        return <<<HTML
+<a href="{$this->resource()}/{$this->getKey()}/edit"><i class="feather icon-edit-1"></i>&nbsp;</a>
+HTML;
+    }
+}

+ 25 - 25
src/Tree/Actions/QuickEdit.php

@@ -1,25 +1,25 @@
-<?php
-
-namespace Dcat\Admin\Tree\Actions;
-
-use Dcat\Admin\Form;
-use Dcat\Admin\Tree\RowAction;
-
-class QuickEdit extends RowAction
-{
-    protected $dialogFormDimensions = ['700px', '670px'];
-
-    public function html()
-    {
-        [$width, $height] = $this->dialogFormDimensions;
-
-        Form::dialog(trans('admin.edit'))
-            ->click('.tree-quick-edit')
-            ->success('Dcat.reload()')
-            ->dimensions($width, $height);
-
-        return <<<HTML
-<a href="javascript:void(0);" data-url="{$this->resource()}/{$this->getKey()}/edit" class="tree-quick-edit"><i class="feather icon-edit"></i>&nbsp;</a>
-HTML;
-    }
-}
+<?php
+
+namespace Dcat\Admin\Tree\Actions;
+
+use Dcat\Admin\Form;
+use Dcat\Admin\Tree\RowAction;
+
+class QuickEdit extends RowAction
+{
+    protected $dialogFormDimensions = ['700px', '670px'];
+
+    public function html()
+    {
+        [$width, $height] = $this->dialogFormDimensions;
+
+        Form::dialog(trans('admin.edit'))
+            ->click('.tree-quick-edit')
+            ->success('Dcat.reload()')
+            ->dimensions($width, $height);
+
+        return <<<HTML
+<a href="javascript:void(0);" data-url="{$this->resource()}/{$this->getKey()}/edit" class="tree-quick-edit"><i class="feather icon-edit"></i>&nbsp;</a>
+HTML;
+    }
+}

+ 65 - 65
src/Tree/RowAction.php

@@ -1,65 +1,65 @@
-<?php
-
-namespace Dcat\Admin\Tree;
-
-use Dcat\Admin\Actions\Action;
-
-class RowAction extends Action
-{
-    /**
-     * @var \Dcat\Admin\Tree\Actions;
-     */
-    protected $actions;
-
-    /**
-     * @var \Illuminate\Database\Eloquent\Model
-     */
-    protected $row;
-
-    public $selectorPrefix = '.tree-row-action-';
-
-    /**
-     * 获取主键值.
-     *
-     * @return array|mixed|string
-     */
-    public function getKey()
-    {
-        return $this->row->{$this->actions->getParent()->getKeyName()};
-    }
-
-    /**
-     * 获取行数据.
-     *
-     * @return \Illuminate\Database\Eloquent\Model
-     */
-    public function getRow()
-    {
-        return $this->row;
-    }
-
-    /**
-     * 获取资源路径.
-     *
-     * @return string
-     */
-    public function resource()
-    {
-        return $this->actions->getParent()->resource();
-    }
-
-    public function getActions()
-    {
-        return $this->actions;
-    }
-
-    public function setParent(Actions $actions)
-    {
-        $this->actions = $actions;
-    }
-
-    public function setRow($row)
-    {
-        $this->row = $row;
-    }
-}
+<?php
+
+namespace Dcat\Admin\Tree;
+
+use Dcat\Admin\Actions\Action;
+
+class RowAction extends Action
+{
+    /**
+     * @var \Dcat\Admin\Tree\Actions;
+     */
+    protected $actions;
+
+    /**
+     * @var \Illuminate\Database\Eloquent\Model
+     */
+    protected $row;
+
+    public $selectorPrefix = '.tree-row-action-';
+
+    /**
+     * 获取主键值.
+     *
+     * @return array|mixed|string
+     */
+    public function getKey()
+    {
+        return $this->row->{$this->actions->getParent()->getKeyName()};
+    }
+
+    /**
+     * 获取行数据.
+     *
+     * @return \Illuminate\Database\Eloquent\Model
+     */
+    public function getRow()
+    {
+        return $this->row;
+    }
+
+    /**
+     * 获取资源路径.
+     *
+     * @return string
+     */
+    public function resource()
+    {
+        return $this->actions->getParent()->resource();
+    }
+
+    public function getActions()
+    {
+        return $this->actions;
+    }
+
+    public function setParent(Actions $actions)
+    {
+        $this->actions = $actions;
+    }
+
+    public function setRow($row)
+    {
+        $this->row = $row;
+    }
+}

+ 0 - 1
src/Widgets/DarkModeSwitcher.php

@@ -2,7 +2,6 @@
 
 namespace Dcat\Admin\Widgets;
 
-use Dcat\Admin\Admin;
 use Illuminate\Contracts\Support\Renderable;
 use Illuminate\Support\Str;
 

+ 1 - 1
src/Widgets/Form.php

@@ -619,7 +619,7 @@ class Form implements Renderable
             $buttons .= "<button type=\"reset\" class=\"btn btn-white pull-left\"><i class=\"feather icon-rotate-ccw\"></i> {$reset}</button>";
         }
 
-        if(! empty($this->buttons['submit'])) {
+        if (! empty($this->buttons['submit'])) {
             $submit = $this->getSubmitButtonLabel();
 
             $buttons .= "<button type=\"submit\" class=\"btn btn-primary pull-right\"><i class=\"feather icon-save\"></i> {$submit}</button>";