Http flow in Spiral is based on PSR7 implementation of http requests and response, framework utilizes Zend implementation of such protocol as internal backbone.
PSR7 makes dispatcher compatible with other frameworks, middlewares and response generators. However, on internal level spiral uses IoC scoping of active request and response which provides ability to use PSR-7 functionality in a more friendly way.
Spiral does not provide instance of "global" application request available in any place of application, instead of that it opens so called "request scope" and creates container binding ServerRequestInterface
and "request" shortcut to access incoming request in controllers, request filters and services executed inside such scope. Once request performed and response is generated scope are closed and no instance of global request available anymore.
Due http dispatcher can be created in any environment it is possible to start application or nested request with custom instance of ServerRequestInterface
at any moment. Use dispatcher method "perform" to execute given request.
Spiral will hide instance of ResponseInterface
passed into perform method, hoverer you can always get such object by asking for ResponseInterface
dependency in your code. Let's try to alter set of headers generated by controller action:
protected function indexAction(ResponseInterface $response)
{
return $response->withHeader('Header', 'Some Value');
}
In addition to that, spiral allows you to return strings and arrays from your actions and endpoints (see below), such data will be written into current response body.
Technically, since both response and request are available via container you can count your Controllers as middleware:
public function myAction(ServerRequestInterface $request, ResponseInterface $response)
{
}
Before request and response can be accessed inside controllers and other application services it will be passed thought set of Http Middlewares which can apply custom logic to filter request/response or even halt execution if some condition met (see CsrfFilter
middleware).
After every middleware processed, an "endpoint" will be called.
By default, http endpoint is Router
instance which will send requests to appropriate controller/action using routing.
Feel free to replace default endpoint to implement your own routing mechanism or alter application behaviour.
Responses generated by endpoints will be passed back, thought every middleware in reverse order (for example to add necessary headers) and then returned from HttpDispatcher->perform()
method or automatically dispatched to client. Most of listed operations performed inside MiddlewarePipeline
class.
IoC scoping works well not only for PSR-7 classes but also for auth, cookies and other middlewares.
For example, instance of \Spiral\Auth\ContextInterface
will be accessible ONLY inside AuthMiddleware
which gives you power
to create own domain logic without direct association with PSR-7 classes.
HttpDispatcher has 3 notable methods we would like to check due they define our application backbone flow.
Method perform
can be counted as blackbox accepting ServerRequestInterface
as input and providing ResponseInterface
as result (you can also provide your own instance of ResponseInterface
as second argument, in opposite case Http will create response by it's own), internally every request will be passed thought set of middlewares (see above) as send to http endpoint (in default scenario this is http Router
).
$response = $http->perform($request);
Dispatch method used to send generated response back to client, it utilizes zend EmitterInterface
which provides you ability to change way how responses send to client browser or even store response in memory.
It's not necessary that application will stop after response were dispatched.
Start delegates application control to a given dispatcher, in case of http method will automatically create ServerRequestInterface
and send response to user.