diff --git a/src/BackpackServiceProvider.php b/src/BackpackServiceProvider.php index c3119fc4a6..1e97b800ec 100644 --- a/src/BackpackServiceProvider.php +++ b/src/BackpackServiceProvider.php @@ -91,6 +91,14 @@ public function register() return new DatabaseSchema(); }); + $this->app->scoped('operation-hook', function ($app) { + return new \Backpack\CRUD\app\Library\CrudPanel\Hooks\OperationHooks(); + }); + + $this->app->scoped('panel-hook', function ($app) { + return new \Backpack\CRUD\app\Library\CrudPanel\Hooks\PanelHooks(); + }); + $this->app->singleton('BackpackViewNamespaces', function ($app) { return new ViewNamespaces(); }); diff --git a/src/app/Http/Controllers/CrudController.php b/src/app/Http/Controllers/CrudController.php index cc929b75ac..244625442d 100644 --- a/src/app/Http/Controllers/CrudController.php +++ b/src/app/Http/Controllers/CrudController.php @@ -3,6 +3,10 @@ namespace Backpack\CRUD\app\Http\Controllers; use Backpack\CRUD\app\Library\Attributes\DeprecatedIgnoreOnRuntime; +use Backpack\CRUD\app\Library\CrudPanel\Hooks\Contracts\OperationHook; +use Backpack\CRUD\app\Library\CrudPanel\Hooks\Contracts\PanelHook; +use Backpack\CRUD\app\Library\CrudPanel\Hooks\OperationHooks; +use Backpack\CRUD\app\Library\CrudPanel\Hooks\PanelHooks; use Illuminate\Foundation\Bus\DispatchesJobs; use Illuminate\Foundation\Validation\ValidatesRequests; use Illuminate\Routing\Controller; @@ -40,8 +44,14 @@ public function __construct() $this->crud->setRequest($request); + PanelHook::run(PanelHooks::BEFORE_SETUP_DEFAULTS, [$this]); $this->setupDefaults(); + PanelHook::run(PanelHooks::AFTER_SETUP_DEFAULTS, [$this]); + + PanelHook::run(PanelHooks::BEFORE_CONTROLLER_SETUP, [$this]); $this->setup(); + PanelHook::run(PanelHooks::AFTER_CONTROLLER_SETUP, [$this]); + $this->setupConfigurationForCurrentOperation(); return $next($request); @@ -116,13 +126,22 @@ protected function setupConfigurationForCurrentOperation() * you'd like the defaults to be applied before anything you write. That way, anything you * write is done after the default, so you can remove default settings, etc; */ - $this->crud->applyConfigurationFromSettings($operationName); + if (! OperationHook::has(OperationHooks::SETUP_OPERATION_FROM_CONFIG, $operationName)) { + OperationHook::register(OperationHooks::SETUP_OPERATION_FROM_CONFIG, $operationName, function () use ($operationName) { + return 'backpack.operations.'.$operationName; + }); + } + $this->crud->loadDefaultOperationSettingsFromConfig(OperationHook::run(OperationHooks::SETUP_OPERATION_FROM_CONFIG, $operationName, [$this])); + + OperationHook::run(OperationHooks::BEFORE_OPERATION_SETUP, $operationName, [$this]); /* * THEN, run the corresponding setupXxxOperation if it exists. */ if (method_exists($this, $setupClassName)) { $this->{$setupClassName}(); } + + OperationHook::run(OperationHooks::AFTER_OPERATION_SETUP, $operationName, [$this]); } } diff --git a/src/app/Http/Controllers/Operations/Concerns/HasForm.php b/src/app/Http/Controllers/Operations/Concerns/HasForm.php index 1e38e83dba..9f4a57f5d8 100644 --- a/src/app/Http/Controllers/Operations/Concerns/HasForm.php +++ b/src/app/Http/Controllers/Operations/Concerns/HasForm.php @@ -2,6 +2,8 @@ namespace Backpack\CRUD\app\Http\Controllers\Operations\Concerns; +use Backpack\CRUD\app\Library\CrudPanel\Hooks\Contracts\OperationHook; +use Backpack\CRUD\app\Library\CrudPanel\Hooks\OperationHooks; use Illuminate\Support\Facades\Route; use Illuminate\Support\Str; @@ -38,17 +40,11 @@ protected function formDefaults(string $operationName, string $buttonStack = 'li // Access $this->crud->allowAccess($operationName); - // Config - $this->crud->operation($operationName, function () use ($operationName) { - // if the backpack.operations.{operationName} config exists, use that one - // otherwise, use the generic backpack.operations.form config - if (config()->has('backpack.operations.'.$operationName)) { - $this->crud->loadDefaultOperationSettingsFromConfig(); - } else { - $this->crud->loadDefaultOperationSettingsFromConfig('backpack.operations.form'); - } - - // add a reasonable "save and back" save action + OperationHook::register(OperationHooks::SETUP_OPERATION_FROM_CONFIG, $operationName, function () use ($operationName) { + return config()->has('backpack.operations.'.$operationName) ? 'backpack.operations.'.$operationName : 'backpack.operations.form'; + }); + + OperationHook::register(OperationHooks::BEFORE_OPERATION_SETUP, $operationName, function () use ($operationName) { $this->crud->addSaveAction([ 'name' => 'save_and_back', 'visible' => function ($crud) use ($operationName) { @@ -61,8 +57,7 @@ protected function formDefaults(string $operationName, string $buttonStack = 'li ]); }); - // Default Button - $this->crud->operation(['list', 'show'], function () use ($operationName, $buttonStack, $buttonMeta) { + OperationHook::register(OperationHooks::BEFORE_OPERATION_SETUP, ['list', 'show'], function () use ($operationName, $buttonStack, $buttonMeta) { $this->crud->button($operationName)->view('crud::buttons.quick')->stack($buttonStack)->meta($buttonMeta); }); } diff --git a/src/app/Http/Controllers/Operations/CreateOperation.php b/src/app/Http/Controllers/Operations/CreateOperation.php index 58ca954733..774d72e273 100644 --- a/src/app/Http/Controllers/Operations/CreateOperation.php +++ b/src/app/Http/Controllers/Operations/CreateOperation.php @@ -2,6 +2,8 @@ namespace Backpack\CRUD\app\Http\Controllers\Operations; +use Backpack\CRUD\app\Library\CrudPanel\Hooks\Contracts\OperationHook; +use Backpack\CRUD\app\Library\CrudPanel\Hooks\OperationHooks; use Illuminate\Support\Facades\Route; trait CreateOperation @@ -35,12 +37,11 @@ protected function setupCreateDefaults() { $this->crud->allowAccess('create'); - $this->crud->operation('create', function () { - $this->crud->loadDefaultOperationSettingsFromConfig(); + OperationHook::register(OperationHooks::BEFORE_OPERATION_SETUP, 'create', function () { $this->crud->setupDefaultSaveActions(); }); - $this->crud->operation('list', function () { + OperationHook::register(OperationHooks::BEFORE_OPERATION_SETUP, 'list', function () { $this->crud->addButton('top', 'create', 'view', 'crud::buttons.create'); }); } diff --git a/src/app/Library/CrudPanel/Hooks/Contracts/OperationHook.php b/src/app/Library/CrudPanel/Hooks/Contracts/OperationHook.php new file mode 100644 index 0000000000..b24067addc --- /dev/null +++ b/src/app/Library/CrudPanel/Hooks/Contracts/OperationHook.php @@ -0,0 +1,20 @@ +hooks[$operation][$hook][] = $callback; + } + } + + public function run(string $hook, string|array $operations, array $parameters): void + { + $operations = is_array($operations) ? $operations : [$operations]; + foreach ($operations as $operation) { + if (isset($this->hooks[$operation][$hook])) { + foreach ($this->hooks[$operation][$hook] as $callback) { + $callback(...$parameters); + } + } + } + } + + public function has(string $hook, string $operation): bool + { + return isset($this->hooks[$operation][$hook]); + } +} diff --git a/src/app/Library/CrudPanel/Hooks/PanelHooks.php b/src/app/Library/CrudPanel/Hooks/PanelHooks.php new file mode 100644 index 0000000000..b85d54a3e4 --- /dev/null +++ b/src/app/Library/CrudPanel/Hooks/PanelHooks.php @@ -0,0 +1,34 @@ +hooks[$hook][] = $callback; + } + + public function run(string $hook, array $parameters): void + { + if (isset($this->hooks[$hook])) { + foreach ($this->hooks[$hook] as $callback) { + $callback(...$parameters); + } + } + } + + public function has(string $hook): bool + { + return isset($this->hooks[$hook]); + } +} diff --git a/src/app/Library/CrudPanel/Traits/Operations.php b/src/app/Library/CrudPanel/Traits/Operations.php index 3a3c94c395..10fc6b75ed 100644 --- a/src/app/Library/CrudPanel/Traits/Operations.php +++ b/src/app/Library/CrudPanel/Traits/Operations.php @@ -2,6 +2,9 @@ namespace Backpack\CRUD\app\Library\CrudPanel\Traits; +use Backpack\CRUD\app\Library\CrudPanel\Hooks\Contracts\OperationHook; +use Backpack\CRUD\app\Library\CrudPanel\Hooks\OperationHooks; + trait Operations { /* @@ -59,31 +62,30 @@ public function setCurrentOperation($operation_name) * @param string|array $operation Operation name in string form * @param bool|\Closure $closure Code that calls CrudPanel methods. * @return void + * + * @deprecated use OperationHook::register(OperationHooks::BEFORE_OPERATION_SETUP, $operation, $closure) instead */ public function operation($operations, $closure = false) { - return $this->configureOperation($operations, $closure); + OperationHook::register(OperationHooks::BEFORE_OPERATION_SETUP, $operations, $closure); } /** * Store a closure which configures a certain operation inside settings. - * Allc configurations are put inside that operation's namespace. + * All configurations are put inside that operation's namespace. * Ex: show.configuration. * * @param string|array $operation Operation name in string form * @param bool|\Closure $closure Code that calls CrudPanel methods. * @return void + * + * @deprecated use OperationHook::register(OperationHooks::BEFORE_OPERATION_SETUP, $operation, $closure) instead */ public function configureOperation($operations, $closure = false) { $operations = (array) $operations; - foreach ($operations as $operation) { - $configuration = (array) $this->get($operation.'.configuration'); - $configuration[] = $closure; - - $this->set($operation.'.configuration', $configuration); - } + OperationHook::register(OperationHooks::BEFORE_OPERATION_SETUP, $operations, $closure); } /** @@ -93,22 +95,13 @@ public function configureOperation($operations, $closure = false) * * @param string|array $operations [description] * @return void + * + * @deprecated use OperationHook::register(OperationHooks::BEFORE_OPERATION_SETUP, $operation, $closure) instead */ public function applyConfigurationFromSettings($operations) { $operations = (array) $operations; - foreach ($operations as $operation) { - $configuration = (array) $this->get($operation.'.configuration'); - - if (count($configuration)) { - foreach ($configuration as $closure) { - if (is_callable($closure)) { - // apply the closure - ($closure)(); - } - } - } - } + OperationHook::run(OperationHooks::BEFORE_OPERATION_SETUP, $operations, []); } }