Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion docs/en/appendices/5-4-migration-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,19 @@ version is reported as `unknown`), the header is omitted.
Events being registered in either `Application::events()` or `Plugin::events()`
now work in both web and CLI contexts. It is therefore highly recommended to
move your event listeners from the `config/bootstrap.php` file to the
`events()` method in your `Application` or `Plugin` class.
`eventListeners()` method in your `Application` or `Plugin` class. Use the
`events()` method when you need custom registration logic or anonymous
listeners.
See [Application and Plugin Events](../core-libraries/events#registering-event-listeners) for more details.

`Application::eventListeners()` and `Plugin::eventListeners()` were added to
register event listener classes declaratively. These listeners are resolved
through the application's dependency injection container, so they can use
constructor-injected dependencies.

`EventAwareApplicationInterface::pluginEvents()` has been deprecated. Plugin
events are now registered while each plugin is bootstrapped.

### I18n

- `Number::parseFloat()` now returns `null` instead of `0.0` when parsing
Expand Down
81 changes: 76 additions & 5 deletions docs/en/core-libraries/events.md
Original file line number Diff line number Diff line change
Expand Up @@ -298,16 +298,86 @@ As you can see in the above code, the `on()` function will accept instances
of the `EventListener` interface. Internally, the event manager will use
`implementedEvents()` to attach the correct callbacks.

::: info Added in version 5.1.0
The `events` hook was added to the `BaseApplication` as well as the `BasePlugin` class
::: info Added in version 5.4.0
The `eventListeners` hook was added to `BaseApplication` and `BasePlugin`.
:::

As of CakePHP 5.1 it is recommended to register event listeners by adding them via the `events` hook in your application or plugin class:
As of CakePHP 5.4, applications and plugins can register listener classes with
the `eventListeners()` hook. Listener classes are resolved through the
application's dependency injection container before they are attached to the
global event manager. This lets listeners declare constructor dependencies:

```php
namespace App;

use App\Event\UserStatistic;
use Cake\Http\BaseApplication;

class Application extends BaseApplication
{
// The rest of your Application class

/**
* @return list<class-string<\Cake\Event\EventListenerInterface>>
*/
public function eventListeners(): array
{
return [
UserStatistic::class,
];
}
}
```

Plugins can define event listeners the same way in their plugin class:

```php
namespace ContactManager;

use Cake\Core\BasePlugin;
use ContactManager\Event\UserStatistic;

class ContactManagerPlugin extends BasePlugin
{
/**
* @return list<class-string<\Cake\Event\EventListenerInterface>>
*/
public function eventListeners(): array
{
return [
UserStatistic::class,
];
}
}
```

If your listener has constructor dependencies, register the listener and its
dependencies in `Application::services()` or `Plugin::services()`:

```php
use App\Event\UserStatistic;
use App\Service\StatisticsClient;
use Cake\Core\ContainerInterface;

public function services(ContainerInterface $container): void
{
$container->addShared(StatisticsClient::class);
$container->addShared(UserStatistic::class)
->addArgument(StatisticsClient::class);
}
```

::: info Added in version 5.1.0
The `events` hook was added to the `BaseApplication` as well as the `BasePlugin` class.
:::

Use the `events()` hook in your application or plugin class when you need
imperative registration logic, or want to register anonymous functions:

```php
namespace App;

use Cake\Event\EventInterface;
use Cake\Event\EventManagerInterface;
use Cake\Http\BaseApplication;

Expand All @@ -317,8 +387,9 @@ class Application extends BaseApplication

public function events(EventManagerInterface $eventManager): EventManagerInterface
{
$statistics = new UserStatistic();
$eventManager->on($statistics);
$eventManager->on('Order.afterPlace', function (EventInterface $event): void {
// Code to update statistics
});

return $eventManager;
}
Expand Down
13 changes: 8 additions & 5 deletions docs/en/development/application.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,17 @@ methods:

- `bootstrap` Used to load [configuration files](../development/configuration), define constants and other global functions.
By default, this will include **config/bootstrap.php**. This is the ideal place
to load [Plugins](../plugins) and global [event listeners](../core-libraries/events).
to load [Plugins](../plugins) and application configuration.
- `routes` Used to load [routes](../development/routing). By default, this
will include **config/routes.php**.
- `middleware` Used to add [middleware](../controllers/middleware) to your application.
- `console` Used to add [console commands](../console-commands) to your
application. By default, this will automatically discover console commands in
your application and all plugins.
- `eventListeners` Used to register global [event listener](../core-libraries/events)
classes with the application's event manager.
- `events` Used to register global [events](../core-libraries/events) that
require custom registration logic.

## Bootstrapping your Application

Expand All @@ -49,8 +53,7 @@ sections there are better ways you add custom logic to your application.

In addition to the **config/bootstrap.php** file which should be used to
configure low-level concerns of your application, you can also use the
`Application::bootstrap()` hook method to load/initialize plugins, and attach
global event listeners:
`Application::bootstrap()` hook method to load/initialize plugins:

```php
// in src/Application.php
Expand Down Expand Up @@ -84,6 +87,6 @@ class Application extends BaseApplication
}
```

Loading plugins and events in `Application::bootstrap()` makes
[Integration Testing](../development/testing#integration-testing) easier as events and routes will be re-processed on
Loading plugins in `Application::bootstrap()` makes
[Integration Testing](../development/testing#integration-testing) easier as routes will be re-processed on
each test method.
25 changes: 25 additions & 0 deletions docs/en/plugins.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,10 @@ appropriate parts of your application. The hooks are:
collection.
- `services` Used to register application container services. This is a good
opportunity to setup additional objects that need access to the container.
- `eventListeners` Used to register global event listener classes with the
application's event manager.
- `events` Used to register global events that require custom registration
logic.

By default, all plugins hooks are enabled. You can disable hooks by using the
related options of the `plugin load` command:
Expand Down Expand Up @@ -311,6 +315,7 @@ use Cake\Core\BasePlugin;
use Cake\Core\ContainerInterface;
use Cake\Core\PluginApplicationInterface;
use Cake\Console\CommandCollection;
use Cake\Event\EventManagerInterface;
use Cake\Http\MiddlewareQueue;
use Cake\Routing\RouteBuilder;

Expand Down Expand Up @@ -369,6 +374,26 @@ class ContactManagerPlugin extends BasePlugin
{
// Add your services here
}

/**
* @return list<class-string<\Cake\Event\EventListenerInterface>>
*/
public function eventListeners(): array
{
return [
// Add your event listeners here.
];
}

/**
* @inheritDoc
*/
public function events(EventManagerInterface $eventManager): EventManagerInterface
{
// Add custom event registration logic here.

return $eventManager;
}
}
```

Expand Down