From cdaad2f40ec96fd98e6320638854c69b90bfe847 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Mon, 22 Nov 2021 18:30:58 +0000 Subject: [PATCH 1/2] Support custom commands via logical theme system Added initial work to support registering commands through the logical theme system. Includes docs changes and example. Not yet covered via testing. --- app/Console/Kernel.php | 10 ++++++++++ app/Theming/ThemeService.php | 22 ++++++++++++++++++++++ dev/docs/logical-theme-system.md | 26 ++++++++++++++++++++++++++ 3 files changed, 58 insertions(+) diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index 11c8018c8..02c8c00e6 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -2,8 +2,11 @@ namespace BookStack\Console; +use BookStack\Facades\Theme; +use BookStack\Theming\ThemeService; use Illuminate\Console\Scheduling\Schedule; use Illuminate\Foundation\Console\Kernel as ConsoleKernel; +use Symfony\Component\Console\Command\Command; class Kernel extends ConsoleKernel { @@ -35,6 +38,13 @@ class Kernel extends ConsoleKernel */ protected function commands() { + // Default framework command loading from 'Commands' directory $this->load(__DIR__ . '/Commands'); + + // Load any user commands that have been registered via the theme system. + $themeService = $this->app->make(ThemeService::class); + foreach ($themeService->getRegisteredCommands() as $command) { + $this->registerCommand($command); + } } } diff --git a/app/Theming/ThemeService.php b/app/Theming/ThemeService.php index 602abaf1c..f095c7a8e 100644 --- a/app/Theming/ThemeService.php +++ b/app/Theming/ThemeService.php @@ -3,11 +3,17 @@ namespace BookStack\Theming; use BookStack\Auth\Access\SocialAuthService; +use Symfony\Component\Console\Command\Command; class ThemeService { protected $listeners = []; + /** + * @var Command[] + */ + protected $commands = []; + /** * Listen to a given custom theme event, * setting up the action to be ran when the event occurs. @@ -43,6 +49,22 @@ class ThemeService return null; } + /** + * Register a new custom artisan command to be available. + */ + public function registerCommand(Command $command) + { + $this->commands[] = $command; + } + + /** + * Get the custom commands that have been registered. + */ + public function getRegisteredCommands(): array + { + return $this->commands; + } + /** * Read any actions from the set theme path if the 'functions.php' file exists. */ diff --git a/dev/docs/logical-theme-system.md b/dev/docs/logical-theme-system.md index b950d7df9..4d6ed719b 100644 --- a/dev/docs/logical-theme-system.md +++ b/dev/docs/logical-theme-system.md @@ -77,6 +77,32 @@ Theme::listen(ThemeEvents::APP_BOOT, function($app) { }); ``` +## Custom Commands + +The logical theme system supports adding custom [artisan commands](https://laravel.com/docs/8.x/artisan) to BookStack. These can be registered in your `functions.php` file by calling `Theme::registerCommand($command)`, where `$command` is an instance of `\Symfony\Component\Console\Command\Command`. + +Below is an example of registering a command that could then be ran using `php artisan bookstack:meow` on the command line. + +```php +line('Meow there!'); + } +} + +Theme::registerCommand(new MeowCommand); +``` + ## Custom Socialite Service Example The below shows an example of adding a custom reddit socialite service to BookStack. From cb30c258df2215ba73364cc6df9f3741f603d6a5 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Mon, 22 Nov 2021 19:03:04 +0000 Subject: [PATCH 2/2] Added test for logical-theme-system command registration Changed how the command registration was handled due to complications of action order found during testing. Now the theme service will resolve and directly register the command on the Kernel instead of them being fetched from the ThemeService from within Kernel. More direct, Seems to work. --- app/Console/Kernel.php | 10 ---------- app/Theming/ThemeService.php | 18 ++++-------------- tests/ThemeTest.php | 19 +++++++++++++++++++ 3 files changed, 23 insertions(+), 24 deletions(-) diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index 02c8c00e6..11c8018c8 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -2,11 +2,8 @@ namespace BookStack\Console; -use BookStack\Facades\Theme; -use BookStack\Theming\ThemeService; use Illuminate\Console\Scheduling\Schedule; use Illuminate\Foundation\Console\Kernel as ConsoleKernel; -use Symfony\Component\Console\Command\Command; class Kernel extends ConsoleKernel { @@ -38,13 +35,6 @@ class Kernel extends ConsoleKernel */ protected function commands() { - // Default framework command loading from 'Commands' directory $this->load(__DIR__ . '/Commands'); - - // Load any user commands that have been registered via the theme system. - $themeService = $this->app->make(ThemeService::class); - foreach ($themeService->getRegisteredCommands() as $command) { - $this->registerCommand($command); - } } } diff --git a/app/Theming/ThemeService.php b/app/Theming/ThemeService.php index f095c7a8e..f0f8f033c 100644 --- a/app/Theming/ThemeService.php +++ b/app/Theming/ThemeService.php @@ -3,17 +3,13 @@ namespace BookStack\Theming; use BookStack\Auth\Access\SocialAuthService; +use Illuminate\Contracts\Console\Kernel; use Symfony\Component\Console\Command\Command; class ThemeService { protected $listeners = []; - /** - * @var Command[] - */ - protected $commands = []; - /** * Listen to a given custom theme event, * setting up the action to be ran when the event occurs. @@ -54,15 +50,9 @@ class ThemeService */ public function registerCommand(Command $command) { - $this->commands[] = $command; - } - - /** - * Get the custom commands that have been registered. - */ - public function getRegisteredCommands(): array - { - return $this->commands; + /** @var \Illuminate\Foundation\Console\Kernel $consoleKernel */ + $consoleKernel = app()->make(Kernel::class); + $consoleKernel->registerCommand($command); } /** diff --git a/tests/ThemeTest.php b/tests/ThemeTest.php index 9aa7873b0..f04250bff 100644 --- a/tests/ThemeTest.php +++ b/tests/ThemeTest.php @@ -7,8 +7,10 @@ use BookStack\Entities\Models\Page; use BookStack\Entities\Tools\PageContent; use BookStack\Facades\Theme; use BookStack\Theming\ThemeEvents; +use Illuminate\Console\Command; use Illuminate\Http\Request; use Illuminate\Http\Response; +use Illuminate\Support\Facades\Artisan; use Illuminate\Support\Facades\File; use League\CommonMark\ConfigurableEnvironmentInterface; @@ -206,6 +208,16 @@ class ThemeTest extends TestCase $this->assertStringContainsString('donkey=donut', $redirect); } + public function test_register_command_allows_provided_command_to_be_usable_via_artisan() + { + Theme::registerCommand(new MyCustomCommand); + + Artisan::call('bookstack:test-custom-command', []); + $output = Artisan::output(); + + $this->assertStringContainsString('Command ran!', $output); + } + protected function usingThemeFolder(callable $callback) { // Create a folder and configure a theme @@ -220,3 +232,10 @@ class ThemeTest extends TestCase File::deleteDirectory($themeFolderPath); } } + +class MyCustomCommand extends Command { + protected $signature = 'bookstack:test-custom-command'; + public function handle() { + $this->line('Command ran!'); + } +} \ No newline at end of file