diff --git a/Changelog.md b/Changelog.md index dcde0f4..061c450 100644 --- a/Changelog.md +++ b/Changelog.md @@ -2,6 +2,11 @@ ## 1.X Series +### Unreleased +##### 2024-XX-YY + +- Added the controller hooks feature + ### 1.14.0 ##### 2024-01-08 diff --git a/docs/controllers.md b/docs/controllers.md index f933c09..a52c24a 100644 --- a/docs/controllers.md +++ b/docs/controllers.md @@ -1,11 +1,69 @@ # Controllers -A box can ship with predefined controllers, and they can be used directly or via routes. +A module can ship with controllers which can be used directly or via predefined routes. + +## Hooking Into Data Injection + +> This feature is available since version 1.15 + +If you are developing a package you can allow the host application to modify the data injected into the views, +by making the controller hookable. + +This can be very useful if the application has knowledge and access to data that the package is not aware of. + +To do this: + +1. Add the `HasControllerHooks` trait to your controller; +2. Pass the view data through the `processViewData()` method. + +```php +// Controller code in your package: +use \Konekt\Concord\Hooks\HasControllerHooks; + +class ChannelController +{ + use HasControllerHooks; + + public function create() + { + return view('vanilo::channel.create', $this->processViewData(__METHOD__, [ + 'countries' => Countries::pluck('name', 'id'), + 'currencies' => Currencies::choices(), + 'domains' => [], + ])); + } + + public function edit(Channel $channel) + { + return view('vanilo::channel.edit', $this->processViewData(__METHOD__, [ + 'channel' => $channel, + 'countries' => Countries::pluck('name', 'id'), + 'currencies' => Currencies::choices(), + 'domains' => [], + ])); + } +} +``` + +Having the controller prepared this way, the application can modify the data passed to the view. + +The example below will populate the `domains` variable that gets injected into the view with data: + +```php +// Application code, most commonly the AppServiceProvider::boot() method: +ChannelController::hookInto('create', 'edit') + ->viewDataInjection(function (array $viewData): array { + $viewData['domains'] = tenant()->domains->pluck('domain', 'domain')->toArray(); + + return $viewData; + }); +``` + +The hook will be called both in the create and the edit actions. ## Using Custom Action -> **NOTE:** This is nothing Concord specific, Laravel provides these -> possibilities out of the box. +> **NOTE:** This solution is not Concord-specific, Laravel provides these possibilities out of the box. In case an app wants to extend a boxes controller AND wants to use the boxes built in routes, it should do the following thing: @@ -16,6 +74,7 @@ You can put this code either in your app's `RouteServiceProvider` or the `AppServiceProvider` (or any service provider you prefer). **Example:** + ```php //app/Providers/RouteServiceProvider.php namespace App\Providers; @@ -45,7 +104,9 @@ class RouteServiceProvider extends ServiceProvider // [...] } ``` + *The Custom Controller:* + ```php //app/Http/Controllers/Admin/OrderController.php namespace App\Http\Controllers\Admin; diff --git a/src/Hooks/ControllerHook.php b/src/Hooks/ControllerHook.php new file mode 100644 index 0000000..47d1761 --- /dev/null +++ b/src/Hooks/ControllerHook.php @@ -0,0 +1,31 @@ +injectionCallback = $callback; + } + + public function onInject(array $viewData): array + { + return call_user_func($this->injectionCallback, $viewData); + } +} diff --git a/src/Hooks/HasControllerHooks.php b/src/Hooks/HasControllerHooks.php new file mode 100644 index 0000000..bc9dac5 --- /dev/null +++ b/src/Hooks/HasControllerHooks.php @@ -0,0 +1,44 @@ +onInject($result); + } + + return $result; + } +}