diff --git a/src/Console/CommandRunner.php b/src/Console/CommandRunner.php index 6118b7df7e7..64c2d50d09b 100644 --- a/src/Console/CommandRunner.php +++ b/src/Console/CommandRunner.php @@ -183,6 +183,8 @@ public function run(array $argv, ConsoleIo $io = null) * Application bootstrap wrapper. * * Calls `bootstrap()` and `events()` if application implements `EventApplicationInterface`. + * After the application is bootstrapped and events are attached, plugins are bootstrapped + * and have their events attached. * * @return void */ @@ -195,6 +197,7 @@ protected function bootstrap() } if ($this->app instanceof PluginApplicationInterface) { $this->app->pluginBootstrap(); + $this->app->pluginEvents(); } } diff --git a/src/Core/PluginApp.php b/src/Core/PluginApp.php index 793b5f40c8c..50065662669 100644 --- a/src/Core/PluginApp.php +++ b/src/Core/PluginApp.php @@ -32,6 +32,13 @@ class PluginApp implements PluginInterface */ protected $bootstrapEnabled = true; + /** + * Are events enabled. + * + * @var bool + */ + protected $eventsEnabled = true; + /** * Load routes or not * @@ -255,4 +262,11 @@ public function middleware($middleware) { return $middleware; } + + /** + * {@inheritdoc} + */ + public function events($events) + { + } } diff --git a/src/Core/PluginApplicationInterface.php b/src/Core/PluginApplicationInterface.php index 8b2cd423b07..e2de96e435b 100644 --- a/src/Core/PluginApplicationInterface.php +++ b/src/Core/PluginApplicationInterface.php @@ -58,4 +58,11 @@ public function pluginMiddleware($middleware); * @return \Cake\Console\CommandCollection */ public function pluginConsole($commands); + + /** + * Run events hook for plugins + * + * @return void + */ + public function pluginEvents(); } diff --git a/src/Core/PluginInterface.php b/src/Core/PluginInterface.php index 97b77430c0f..c57cd06e356 100644 --- a/src/Core/PluginInterface.php +++ b/src/Core/PluginInterface.php @@ -18,9 +18,9 @@ interface PluginInterface { /** - * The list of valid hooks + * List of valid hooks. */ - const VALID_HOOKS = ['routes', 'bootstrap', 'console', 'middleware']; + const VALID_HOOKS = ['routes', 'bootstrap', 'console', 'middleware', 'events']; /** * Get the name of this plugin. @@ -60,7 +60,7 @@ public function getClassPath(); public function bootstrap(); /** - * Add a plugins console commands + * Add console commands for the plugin. * * @param \Cake\Console\CommandCollection $commands The command collection to update * @return \Cake\Console\CommandCollection @@ -68,7 +68,7 @@ public function bootstrap(); public function console($commands); /** - * Add a plugins middleware + * Add middleware for the plugin. * * @param \Cake\Http\MiddlewareQueue $middleware The middleware queue to update. * @return \Cake\Http\MiddlewareQueue @@ -76,13 +76,21 @@ public function console($commands); public function middleware($middleware); /** - * Add a routes + * Add routes for the plugin. * * @param \Cake\Routing\RouteBuilder $routes The route builder to update. * @return \Cake\Routing\RouteBuilder */ public function routes($routes); + /** + * Add events for the plugin. + * + * @param \Cake\Event\EventManager $events The application's event manager + * @return void + */ + public function events($events); + /** * Disables the named hook * diff --git a/src/Http/BaseApplication.php b/src/Http/BaseApplication.php index 46d36a7547b..7bf436567f1 100644 --- a/src/Http/BaseApplication.php +++ b/src/Http/BaseApplication.php @@ -78,6 +78,18 @@ public function __construct($configDir, EventManagerInterface $eventManager = nu */ abstract public function middleware($middleware); + /** + * {@inheritDoc} + */ + public function pluginEvents() + { + $events = $this->getEventManager(); + + foreach ($this->plugins->with('events') as $plugin) { + $plugin->events($events); + } + } + /** * {@inheritDoc} */ diff --git a/src/Http/Server.php b/src/Http/Server.php index f2dfab7fd59..30c15ce7aca 100644 --- a/src/Http/Server.php +++ b/src/Http/Server.php @@ -103,6 +103,8 @@ public function run(ServerRequestInterface $request = null, ResponseInterface $r * Application bootstrap wrapper. * * Calls `bootstrap()` and `events()` if application implements `EventApplicationInterface`. + * After the application is bootstrapped and events are attached, plugins are bootstrapped + * and have their events attached. * * @return void */ @@ -115,6 +117,7 @@ protected function bootstrap() } if ($this->app instanceof PluginApplicationInterface) { $this->app->pluginBootstrap(); + $this->app->pluginEvents(); } } diff --git a/tests/TestCase/Console/CommandRunnerTest.php b/tests/TestCase/Console/CommandRunnerTest.php index 9e922b0ef51..30501d4cf8e 100644 --- a/tests/TestCase/Console/CommandRunnerTest.php +++ b/tests/TestCase/Console/CommandRunnerTest.php @@ -394,14 +394,16 @@ public function testRunTriggersBuildCommandsEvent() public function testRunCallsPluginHookMethods() { $app = $this->getMockBuilder(BaseApplication::class) - ->setMethods(['middleware', 'bootstrap', 'pluginBootstrap', 'pluginConsole']) + ->setMethods(['middleware', 'bootstrap', 'pluginBootstrap', 'pluginEvents', 'pluginConsole']) ->setConstructorArgs([$this->config]) ->getMock(); - $app->expects($this->once()) - ->method('pluginBootstrap'); + + $app->expects($this->at(0))->method('bootstrap'); + $app->expects($this->at(1))->method('pluginBootstrap'); + $app->expects($this->at(2))->method('pluginEvents'); $commands = new CommandCollection(); - $app->expects($this->once()) + $app->expects($this->at(3)) ->method('pluginConsole') ->with($this->isinstanceOf(CommandCollection::class)) ->will($this->returnCallback(function ($commands) { diff --git a/tests/TestCase/Core/PluginAppTest.php b/tests/TestCase/Core/PluginAppTest.php index 35650b0efc8..515e4f3e108 100644 --- a/tests/TestCase/Core/PluginAppTest.php +++ b/tests/TestCase/Core/PluginAppTest.php @@ -16,6 +16,7 @@ use Cake\Console\CommandCollection; use Cake\Core\Plugin; use Cake\Core\PluginApp; +use Cake\Event\EventManager; use Cake\Http\MiddlewareQueue; use Cake\TestSuite\TestCase; use Company\TestPluginThree\Plugin as TestPluginThree; @@ -85,6 +86,13 @@ public function testConsole() $this->assertSame($commands, $plugin->console($commands)); } + public function testEvents() + { + $plugin = new PluginApp(); + $events = new EventManager(); + $this->assertNull($plugin->events($events)); + } + public function testConstructorArguments() { $plugin = new PluginApp([ diff --git a/tests/TestCase/Http/ServerTest.php b/tests/TestCase/Http/ServerTest.php index 994f742c47e..f05c6eccfe4 100644 --- a/tests/TestCase/Http/ServerTest.php +++ b/tests/TestCase/Http/ServerTest.php @@ -121,12 +121,14 @@ public function testRunCallingPluginHooks() $request = $request->withHeader('X-pass', 'request header'); $app = $this->getMockBuilder(MiddlewareApplication::class) - ->setMethods(['pluginBootstrap', 'pluginMiddleware']) + ->setMethods(['pluginBootstrap', 'pluginEvents', 'pluginMiddleware']) ->setConstructorArgs([$this->config]) ->getMock(); - $app->expects($this->once()) + $app->expects($this->at(0)) ->method('pluginBootstrap'); - $app->expects($this->once()) + $app->expects($this->at(1)) + ->method('pluginBootstrap'); + $app->expects($this->at(2)) ->method('pluginMiddleware') ->with($this->isInstanceOf(MiddlewareQueue::class)) ->will($this->returnCallback(function ($middleware) {