Bootstrapping
This chapter outlines the bootstrapping mechanism Flow uses on each request to initialize vital parts of the framework and the application. It explains the built-in request handlers which effectively control the boot sequence and demonstrates how custom request handlers can be developed and registered.
The Flow Application Context
Each request, no matter if it runs from the command line or through HTTP, runs in a specific application context. Flow provides exactly three built-in contexts:
Development
(default) - used for developmentProduction
- should be used for a live siteTesting
- is used for functional tests
The context Flow runs in is specified through the environment variable
FLOW_CONTEXT
. It can be set per command at the command line or be part of the
web server configuration:
# run the Flow CLI commands in production context
FLOW_CONTEXT=Production ./flow help
# In your Apache configuration, you usually use:
SetEnv FLOW_CONTEXT Production
Custom Contexts
In certain situations, more specific contexts are desirable:
a staging system may run in a Production context, but requires a different set of credentials than the production server.
developers working on a project may need different application specific settings but prefer to maintain all configuration files in a common Git repository.
By defining custom contexts which inherit from one of the three base contexts, more specific configuration sets can be realized.
While it is not possible to add new “top-level” contexts at the same level like
Production and Testing, you can create arbitrary sub-contexts, just by
specifying them like <MainContext>/<SubContext>
.
For a staging environment a custom context Production/Staging
may provide the
necessary settings while the Production/Live
context is used on the live instance.
Each sub context inherits the configuration from the parent context, which is explained in full detail inside the Configuration chapter.
Note
This even works recursively, so if you have a multiple-server staging setup, you could use the context Production/Staging/Server1 and Production/Staging/Server2 if both staging servers needed different configuration.
Boot Sequence
There are basically two types of requests which are handled by a Flow application:
command line requests are passed to the
flow.php
script which resides in theScripts
folder of the Flow packageHTTP requests are first taken care of by the
index.php
script in the publicWeb
directory.
Both scripts set certain environment variables and then instantiate and run the
Neos\Flow\Core\Bootstrap
class.
The bootstrap’s run()
method initializes the bare minimum needed for any
kind of operation. When it did that, it determines the actual request
handler which takes over the control of the further boot sequence and
handling the request.
public function run()
{
Scripts::initializeClassLoader($this);
Scripts::initializeSignalSlot($this);
Scripts::initializePackageManagement($this);
$this->activeRequestHandler = $this->resolveRequestHandler();
$this->activeRequestHandler->handleRequest();
}
The request handler in charge executes a sequence of steps which need to be
taken for initializing Flow for the purpose defined by the specialized
request handler. Flow’s Bootstrap
class provides convenience methods for
building such a sequence and the result can be customized by adding further
or removing unnecessary steps.
After initialization, the request handler takes the necessary steps to handle
the request, does or does not echo a response and finally exits the
application. Control is not returned to the bootstrap again, but a request
handler should call the bootstrap’s shutdown()
method in order to cleanly
shut down important parts of the framework.
Run Levels
There are two pre-defined levels to which Flow can be initialized:
compiletime brings Flow into a state which allows for code generation and other low-level tasks which can only be done while Flow is not yet fully ready for serving user requests. Compile time has only limited support for Dependency Injection and lacks support for many other functions such as Aspect-Oriented Programming and Security.
runtime brings Flow into a state which is fully capable of handling user requests and is optimized for speed. No changes to any of the code caches or configuration related to code is allowed during runtime.
The bootstrap’s methods buildCompiletimeSequence()
and
buildRuntimeSequence()
conveniently build a sequence which brings Flow
into either state on invocation.
Request Handlers
A request handler is in charge of executing the boot sequence and ultimately
answering the request it was designed for. It must implement the
\Neos\Flow\Core\RequestHandlerInterface
interface which,
among others, contains the following methods:
public function handleRequest();
public function canHandleRequest();
public function getPriority();
On trying to find a suitable request handler, the bootstrap asks each
registered request handler if it can handle the current request
using canHandleRequest()
– and if it can,
how eager it is to do so through getPriority()
. It then passes control to the
request handler which is most capable of responding to the request by
calling handleRequest()
.
Request handlers must first be registered in order to be considered during the
resolving phase. Registration is done in the Package
class of the package
containing the request handler:
class Package extends BasePackage
{
public function boot(\Neos\Flow\Core\Bootstrap $bootstrap): void
{
$bootstrap->registerRequestHandler(new \Acme\Foo\BarRequestHandler($bootstrap));
}
}
Tip
The Flow package contains meaningful working examples for registration of
request handlers and building boot sequences. A good starting point is
the \Neos\Flow\Package
class where the request handlers are
registered.