Application Lifecycle
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.
Application lifecycle
The overall lifecycle is managed in the UserFrosting/System/UserFrosting class and proceeds as follows:
- Create the dependency injection container.
- Register basic system services, such as the locator service, Sprinkle manager, and the lifecycle event dispatcher.
- Load the list of Sprinkles from
sprinkles.json, and register each Sprinkle's bootstrapper class (if it exists) with the event dispatcher. - Fire the
onSprinklesInitializedevent. - Add each Sprinkle's resources (assets, config, templates, routes, etc) to the locator service.
- Fire the
onSprinklesAddResourcesevent. - Register each Sprinkle's service provider (if it exists).
- Fire the
onSprinklesRegisterServicesevent. Note that this is the point where thecoreSprinkle sets values for PHP settings such aslog_errors,display_errors,error_reporting, andtimezonefrom the UF configuration files, and where the customShutdownHandleris set up. - Load the Slim application settings from the
configservice, and create the Slim application instance. - Fire the
onAppInitializeevent. - Load the route definitions in each Sprinkle's
routes/directory. - Fire the
onAddGlobalMiddlewareevent. This is where thecoreSprinkle sets up the global CSRF middleware. - Invoke the
runmethod on the Slim application.
Bootstrapper classes
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.
Sample bootstrapper class
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.
For more information on event dispatching, subscribing, and listening, check out the Symfony documentation.