Every time UserFrosting is booted up to handle a request, it goes through its application lifecycle. This process includes loading the resources and services in your Sprinkles, setting up the Slim application, registering middleware, and setting up your routes.
At each stage in this process, events are triggered that you can hook into via a Bootstrapper class in your Sprinkle.
The overall lifecycle is managed in the UserFrosting/System/UserFrosting
class and proceeds as follows:
sprinkles.json
, and register each Sprinkle's bootstrapper class (if it exists) with the event dispatcher.onSprinklesInitialized
event.onSprinklesAddResources
event.onSprinklesRegisterServices
event. Note that this is the point where the core
Sprinkle sets values for PHP settings such as log_errors
, display_errors
, error_reporting
, and timezone
from the UF configuration files, and where the custom ShutdownHandler
is set up.config
service, and create the Slim application instance.onAppInitialize
event.routes/
directory.onAddGlobalMiddleware
event. This is where the core
Sprinkle sets up the global CSRF middleware.run
method on the Slim application.At the base level of each Sprinkle, you may optionally define a bootstrapper class. This is a class where you can hook into any of the five events mentioned above: onSprinklesInitialized
, onSprinklesAddResources
, onSprinklesRegisterServices
, onAppInitialize
, and onAddGlobalMiddleware
. The name of the class must be the same as the name of the Sprinkle directory, but in StudlyCaps. The class itself must extend the base UserFrosting\System\Sprinkle\Sprinkle
class.
Bootstrapper classes are basically implementations of Symfony's EventSubscriberInterface
, and they subscribe to the event dispatcher that is created in step 2 of the application lifecycle.
To add a listener for an event, simply create a method of the same name as the event in your bootstrapper class. The method should take one parameter - an Event
object that contains any additional information the dispatcher chooses to include with the event. In the case of the onAppInitialize
and onAddGlobalMiddleware
events, this object will contain a reference to the Slim application that can be accessed from the Event's getApp
method.
You should also add your listener to a static getSubscribedEvents
method, which returns a list of events mapped to a list containing the listener method and the associated priority integer. You can control the order in which listeners in each bootstrapper class are executed, by setting this integer to a higher number. For each event, Sprinkles that assign a higher number to the corresponding listener method will cause that method to be executed earlier than Sprinkles that assigned a lower number to the event.
As an example, consider the following bootstrapper class, which hooks into the onAddGlobalMiddleware
and onSprinklesInitialized
events:
namespace UserFrosting\Sprinkle\Site;
use RocketTheme\Toolbox\Event\Event;
use UserFrosting\Sprinkle\Site\SomeRandomStaticClass;
use UserFrosting\System\Sprinkle\Sprinkle;
class Site extends Sprinkle
{
/**
* Defines which events in the UF lifecycle our Sprinkle should hook into.
*/
public static function getSubscribedEvents()
{
return [
'onAddGlobalMiddleware' => ['onAddGlobalMiddleware', 0],
'onSprinklesInitialized' => ['onSprinklesInitialized', 0]
];
}
/**
* Add custom global middleware.
*/
public function onAddGlobalMiddleware(Event $event)
{
// Assume `myMiddleware` is a service that returns an instance of your middleware class,
// and that you have defined this in your Sprinkle's service provider.
$app = $event->getApp();
$app->add($this->ci->myMiddleware);
}
/**
* Set static references to DI container in necessary classes.
*/
public function onSprinklesInitialized()
{
// Set container for SomeRandomStaticClass
SomeRandomStaticClass::$ci = $this->ci;
}
}
Notice that the base Sprinkle
class has access to the application dependency injection container via $this->ci
. This allows you to invoke other services, or even use the entire container, in your listener methods.