- Notifications
You must be signed in to change notification settings - Fork192
Refactor: extract middleware marshaling, routing, and app running#543
Refactor: extract middleware marshaling, routing, and app running#543
Uh oh!
There was an error while loading.Please reload this page.
Conversation
| namespaceZend\Expressive; | ||
| usePsr\Http\Server\MiddlewareInterface; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
MiddlewareInterface is not used.
src/Container/ApplicationFactory.php Outdated
| $app =newApplication($router,$container,$delegate,$emitter); | ||
| $response =$container->has(ResponseInterface::class) | ||
| ?$container->get(ResponseInterface::class) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
ResponseInterface needs import.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Done.
| useInterop\Http\Server\MiddlewareInterface; | ||
| useInterop\Http\Server\RequestHandlerInterface; | ||
| usePsr\Container\ContainerInterface; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
ContainerInterface not used.
| usePsr\Http\Message\ServerRequestInterface; | ||
| usePsr\Http\Server\MiddlewareInterface; | ||
| usePsr\Http\Server\RequestHandlerInterface; | ||
| useZend\Expressive\MarshalMiddlewareTrait; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
MarshalMiddlewareTrait doesn't exist.
| usePsr\Http\Server\RequestHandlerInterface; | ||
| useZend\Expressive\MarshalMiddlewareTrait; | ||
| useZend\Expressive\Router\RouteResult; | ||
| useZend\Expressive\Router\RouterInterface; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
RouterInterface isn't used.
composer.json Outdated
| "http-interop/http-server-middleware":"^1.0.1", | ||
| "psr/container":"^1.0", | ||
| "psr/http-message":"^1.0.1", | ||
| "psr/http-server-middleware":"^1.0.0", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Usually we use just^1.0.
src/Application.php Outdated
| { | ||
| return$this->route($path,$middleware, ['POST'],$name); | ||
| try { | ||
| $request =$request ?: ServerRequestFactory::fromGlobals(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
One space before= please
src/Application.php Outdated
| /** | ||
| * @param callable|string $middleware Middleware (or middleware service name) to associate with route. | ||
| * @param null|string $name The name of the route. | ||
| * @param string|array|callable|MiddlewareInterface $middleware Middleware |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
As I've suggested in another place order of types -null|(simple types in alphabetical order)|(complex types in alphabetical order) - so here we should havearray|callable|string|MiddlewareInterface.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
I would argue for the following order:
null- all other scalar types, in alphabetical order
- complex built-in types (
array,callable,resource) in alphabetical order - instance types, in alphabetical order
So, clearly we have differing opinions, and we'll need to make a decision. In the meantime, this is not the main point of this PR at this time; I need feedback onarchitecture anddesign.
| * @copyright Copyright (c) 2018 Zend Technologies USA Inc. (https://www.zend.com) | ||
| * @license https://github.com/zendframework/zend-expressive/blob/master/LICENSE.md New BSD License | ||
| */ | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
No new line before strict_type declaration please.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
@webimpress let's try reducing noise over CS by moving these discussions to the CS checks repo instead 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
I'm also little bit unhappy with this type of comments. Because the first comments are always related to the coding standard. After thenoise, there are often no other comments. CS is important, but code formatting should not have the first place in this and other discussions. (imo)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Coding Standard Police 😉
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
This is why we need proper CS for zf and then we are not going to have these comments at all. Sorry, I'm adding comments about everything I can see at the beginning because otherwise (it happened already couple times) it could be merged without fixing...
froschdesignJan 26, 2018 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
@webimpress
Sorry, my comment was not only for you. It was a hint to:zendframework/zend-coding-standard/pull/1
ping@weierophinney
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Sorry guys, actually I was wrong... Probably we should keep the line. See my comments there:
zendframework/zend-expressive-aurarouter#30 (comment)
| { | ||
| publicfunction__invoke(ContainerInterface$container) :DispatchMiddleware | ||
| { | ||
| returnnewDispatchMiddleware(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Do we need that factory? Isn't itinvokable?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Itis invokable, but it may not always be. Additionally, having it here simplifies how we refer to it when writing configuration for different container types.
| } | ||
| /** | ||
| * @var mixed $service The actual service created by the container. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
@param instead of@var please
src/MiddlewareFactory.php Outdated
| return$this->pipeline(...$middleware); | ||
| } | ||
| if ((!is_string($middleware) ||empty($middleware))) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
remove one pair of parentheses and the second part can be just! $middleware
src/MiddlewareFactory.php Outdated
| { | ||
| if (!$this->container) { | ||
| thrownewException\ContainerNotRegisteredException(sprintf( | ||
| 'Cannot marshal middleware by service name "%s"; no container registered', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Maybe it should be moved to the static method in the exception?
src/MiddlewareFactory.php Outdated
| publicfunction__construct(ContainerInterface$container =null) | ||
| { | ||
| $this->container =$container ?newMiddlewareContainer($container) :null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
For better testability we should passMiddlewareContainer as param instead of creating one in the constructor.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
It makes usability harder, however, as developers who are creating an instance on the fly now need to do the following:
$factory =newMiddlewareFactory(newMiddlewareContainer($app->getContainer()));
Additionally, the above example I present would fail with anE_FATAL if$app->getContainer() returnsnull (which is possible currently), which means it technically needs to become:
$factory =newMiddlewareFactory($app->getContainer() ?newMiddlewareContainer($app->getContainer()) :null);
which is not user friendly at all. (FTR, if the middleware in a specification or a pipeline resolves to an constructor-less class, a callable, or aMiddlewareInterface instance, the factory can still do its work; it's only if a service name is used that the container becomes necessary. At that point, it raises an exception when a container is missing.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
I've since changed this to accept only aMiddlewareContainer instance.
| <?php | ||
| /** | ||
| * @see https://github.com/zendframework/zend-expressive for the canonical source repository | ||
| * @copyright Copyright (c) 2016-2017 Zend Technologies USA Inc. (https://www.zend.com) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
2018 only, please
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
This file was renamed fromNotFoundHandler; date range is correct.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Did you usegit mv to rename the file? We are loosing the connection between new and old file, it looks like new file...
Shouldn't we update year range as the file is updated (renamed)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
best way is to move file 100% unchanged, and then edit it in another commit as git does not really have "move" type of change. Simple diff might not detect it anyway as it uses similarity threshold. It is more for a 3-way merge benefit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
... or use PhpStorm :D
It keeps track of moved files (most of the time) so you can move and edit it in the same commit. Not sure how to do that in git. But as PhpStorm can do it, it must be doable with git as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
I did agit mv, but then also added the new file in the same commit, which is why this happened.
Note to self: be more granular in commits.
michalbundyra commentedJan 26, 2018
Do we need it? Maybe we should just register these type of middlewares as invokable in container? |
src/MiddlewareFactory.php Outdated
| * | ||
| * @param string|array|MiddlewareInterface $middleware | ||
| */ | ||
| publicfunctionpath(string$path,$middleware) :PathMiddlewareDecorator |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Maybe the same way we should add methodhost?
I'm looking again through the code, and it doesn't to be right, imho. Looks like we can do the same things in multiple ways now, and it's confusing. I think we should deliver simple interface for devs. Need a bit more time to think about it...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
I'm considering removing thepath() method, as the same can be accomplished with the following:
usefunctionZend\Stratigility\path;$app->pipe(path('/api',$factory->prepare($middleware));
If we keep the methods down to only those needed for preparing middleware of different types (prepare(),callable(),lazy()) and pipelines (pipeline()), we can use these with any of the various decorator classes and/or their related utility functions. That means we can add new decorators and utility functions in Stratigility or Expressive, and they're automatically supported.
weierophinney commentedJan 29, 2018 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
Ideally, that's what we'd do. However, that poses a few problems:
We can largely solve the second use case via the zend-expressive-tooling project; in fact,there is an open issue requesting creation of a factory when middleware:create is called. The first is harder, however; unless we can write a tool to solve that migration problem, it's simpler to have the dedicated container. The third case, however, is probably the more winning argument here, as it ensures that weonly fetch middleware in the context ofmarshaling middleware for the pipeline and/or routing. |
weierophinney commentedJan 29, 2018 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
@Ocramius ,@froschdesign ,@webimpress,@ezimuel,@xtreamwayz — any feedback on design/implementation? Thoughts I've had since implementing (some of which are due to discussions with@ezimuel and@xtreamwayz):
Essentially, for usersupgrading from v2, we'd update their $app =$container->get(Application::class);$factory =$container->get(MiddlewareFactory::class);$routes =$container->get(RouteMiddleware::class);require'config/pipeline.php';require'config/routes.php'; These files would then look like the following: // config/pipeline.php:usefunctionZend\Stratigility\path;$app->pipe($factory->lazy(ErrorMiddleware::class));$app->pipe(path('/api',$factory->pipeline( CorsMiddleware::class, AuthenticationMiddleware::class, AuthorizationMiddleware::class));// Since we already have it instantiated, we can pipe the routing middleware as// an instance:$app->pipe($routes);$app->pipe($factory->lazy(ImplicitHeadMiddleware::class));$app->pipe($factory->lazy(ImplicitOptionsMiddleware::class));$app->pipe($factory->lazy(DispatchMiddleware::class));$app->pipe($factory->lazy(NotFoundMiddleware::class));// config/routes.php:$routes->get('/',$factory->lazy(HomeMiddleware::class));$routes->post('/api/books',$factory->pipeline( BookValidationMiddleware::class, CreateBookMiddleware::class)); Essentially, separating these concerns further means we can have more type-safety, less overall code, and more flexibility for users. The proxy class provides both a migration tool, but also potentially ausability layer for developers who do not want to always use the factory to prepare middleware for piping or routing, but instead just provide the arguments. Updates
|
geerteltink commentedJan 29, 2018
About everything you write sounds good. I'm not sure about the The proxy class for backward compatibility sounds good as well. |
weierophinney commentedJan 29, 2018
The $runner =$container->get(ApplicationRunner::class);$runner->run(); Internally, |
Xerkus commentedJan 29, 2018
May i suggest a following change: (require'config/pipeline.php')($app,$factory,$router);(require'config/routes.php')($app,$factory,$router); useZend\Expressive\Application;usefunctionZend\Stratigility\path;returnfunction (Application$app,MiddlewareFactory$factory,RouteMiddleware$routes) {$app->pipe(ErrorMiddleware::class);$app->pipe(path('/api',$factory->pipeline( CorsMiddleware::class, AuthenticationMiddleware::class, AuthorizationMiddleware::class ));// Since we already have it instantiated, we can pipe the routing middleware as// an instance:$app->pipe($routes);$app->pipe(ImplicitHeadMiddleware::class);$app->pipe(ImplicitOptionsMiddleware::class);$app->pipe(DispatchMiddleware::class);$app->pipe(NotFoundMiddleware::class);} |
weierophinney commentedJan 29, 2018
I really like that idea! |
Xerkus commentedJan 29, 2018
This is a good functionality to be split into separate package to be used with any request handler. |
geerteltink commentedJan 30, 2018
You have shown me this before. I really like it. |
weierophinney commentedJan 30, 2018
The pattern used to be very common in node, before the |
ezimuel commentedJan 30, 2018 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
@weierophinney I really like the idea of having routes specified on a I see the need for a $app->pipe(path('/api',$factory->pipeline( CorsMiddleware::class, AuthenticationMiddleware::class, AuthorizationMiddleware::class))); I think we should continue to supportarray as a way to specify a pipeline. I think this is a very intuitive idea to think about anordered sequence of middleware (a pipeline). I would like to propose this change: $app->pipe(path('/api, [ CorsMiddleware::class, AuthenticationMiddleware::class, AuthorizationMiddleware::class]));We can accomplish this managing the array of middleware in the This routing is very intuitive, even for people not familiar with Expressive: $routes->post('/api/books', [ BookValidationMiddleware::class, CreateBookMiddleware::class]); Regarding the other proposals, I'm in favor of it. It will be awesome to see a complete skeleton application to analyze the changes from a user API point of view. |
weierophinney commentedJan 30, 2018
I'm just about done handling the changesas suggested in my previous large design comment, and in doing so, discovered something interesting: separating the routing concerns, removing the application running concerns, and making the As such, I'm re-creating the
The class then implements both What's interesting about this approach is that it keeps the existing signatures and APIentirely. This then moves the discussion to: how do we want to write the skeleton? It could literally stay exactly the same as it is currently. Alternately, we could do like@Xerkus suggested above, and have the routes and pipeline files return callbacks that accept specific arguments (likely the middleware factory, and then one of either the middleware pipeline or route middleware). What's interesting to me is that this refactoring exercise leaves us with far more flexibility; simpler, more maintainable code; stronger typing; and choice in how we have users consume the project. Once the changes are complete, I'll push here. |
weierophinney commentedJan 30, 2018
All major refactors are now complete. The only bits I'm mulling over at this time are:
Thoughts on these proposals and/or the shape of the refactor at this time? |
src/MiddlewareFactory.php Outdated
| * Creates and returns a PathMiddlewareDecorator instance after first | ||
| * passing the $middleware argument to prepare(). | ||
| * | ||
| * @param string|array|MiddlewareInterface $middleware |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
missing@param for first parameter. I don't know if all IDEs will interpret this properly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
This is standard across major IDEs, at this point, and phpdocumentor infers types from typehints as well. We've already decided for zend-coding-standard to require annotations only if they're adding information, or the type is unspecified.
| returnnewApplicationRunner( | ||
| $container->get(Application::class), | ||
| $container->get(EmitterInterface::class), | ||
| $container->get(ServerRequestFactory::class), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
ServerRequestFactory and ServerRequestErrorResponseGenerator are not real classes, shouldn't they be used as string literals?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
I go back and forth on this, particularly when the service namespace doesn't match the current one.
We can address later.
| usePsr\Container\ContainerInterface; | ||
| usePsr\Http\Message\ResponseInterface; | ||
| useZend\Expressive\Middleware\RouteMiddleware; | ||
| useZend\Expressive\Router\RouteInterface; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Typo, should be RouterInterface
src/Middleware/RouteMiddleware.php Outdated
| * Add a route for the route middleware to match. | ||
| * | ||
| * Accepts either a Route instance, or a combination of a path and | ||
| * middleware, and optionally the HTTP methods allowed. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
This description is wrong, Route instance is not accepted
danizord commentedJan 31, 2018
I'm 👍 for this. IMHO the For the shape of the refactor, I need to review it with more time tomorrow, if you can wait one more day before merging. I missed the notification of this PR. 😄 Just a few comments from what I've read so far:
btw, congrats for the great work done in PSR-15 and Expressive 3 :) |
weierophinney commentedJan 31, 2018
@Xerkus has indicated he could use this for the zend-mvc refactor as well, so we will definitely extract it. My thought is to also extract the emitter interface and emitters from zend-stratigility either into their own package, or into the same package as the runner (which will consume them).
This makes usage more difficultwithin the I'll think on it.
The My thought is that we could bring the If we were to go that route, I'd suggest:
Thoughts on that approach,@danizord? |
I determined the `ZendTest\Expressive\IntegrationTest` to be obsolete;it's testing workflows that are tested elsewhere.The `ZendTest\Expressive\Router\IntegrationTest`, however, was aninteresting testbed in terms of seeing how the middleware pipeline,route middleware/router, and dispatch middleware work together,particularly in terms of the supported router _implementations_. Imodified the test setup to create a `Proxy` instance instead, to see iftests continued to pass. They did!
The new `Proxy` class will soon become the `Application` class.Since the AppFactory relied on the original design, it's obsolete.Particularly since the responsibilities are now separated between thefactory, pipeline, route middleware, and runner, using that approach nolonger seems appropriate.This patch also removes the ApplicationFactory, and all tests related tothe removed classes.
This patch renames the `Proxy` class to `Application`, and modifies itto use the `ApplicationConfigInjectionTrait` as well. Minormodifications were made on the trait due to the changes in the`Application` API and collaborators, and the trait's tests were updatedto properly configure the `Application` instance.
It now composes the required collaborators.It DOES NOT do configuration injection. Users will need to do that ontheir own via the `injectPipelineFromConfig()` and`injectRoutesFromConfig()` methods. Which I think I want to extract intoa purely functional utility class.
Ensures that the typo that snuck in during development will not continueto be an issue.
This patch resolves a circular dependency issue spotted by@Xerkus withregards to the `ApplicationRunner` and `Application` factories. It addsa new factory, `ApplicationPipelineFactory`, which will create andreturn a shared `Zend\Stratigility\MiddlewarePipe` instance; each of`ApplicationRunnerFactory` and `ApplicationFactory` now consume thisservice.
…onseGeneratorThis is what I'd intended originally.
This patch provides a ConfigProvider, which will allow offloading muchof the initial configuration provided in the skeleton to the componentitself.
Instead of using `path()` to create a `PathMiddlewareDecorator`, just`pipe()` both arguments to the `Application` instance.To make this work properly, the patch also does some additional logic tono longer create a `PathMiddlewareDecorator` if the the `$path` is `/`.
Also, discovered test case file did not reflect its class name.
This delegator factory decorates the application instance created by thecallback by injecting a pipeline and routes based on configurationpulled from the container.The functionality is directly from the ApplicationConfigInjectionTrait,which we can deprecate and remove now that this functionality is inplace.
This functionality is now in the ApplicationConfigInjectionDelegator.
This patch marks the two public injection methods in the delegatorfactory as static, allowing them to be used without instantiating thefactory.It also correctly places the tests for the delegator factory, and movesrequired test assests in a tree beneath it.
This is better accomplished using `Zend\Stratigility\path()` + thefactory.
The return type could potentially NOT be an `Application` in thesituation that `$callback` returns something else.
…ssive-router v3This patch updates zend-expressive to consume the `DispatchMiddleware`and `PathBasedRoutingMiddleware` classes from zend-expressive-routerv3.0.0alpha1 and up. Doing so allows removal of those classes andrelated tests from this package, but requires:- `Application` now needs to depend on `PathBasedRoutingMiddleware`- `ApplicationConfigInjectionDelegator` needs to use the new classes when injecting routing and dispatch middleware.- tests needed updating to refer to the new classes.
This patch removes the `ApplicationRunner`, and replaces it withzend-httphandlerrunner's `RequestHandlerInterface` and emitters.
This patch updates the `MiddlewareContainer` and `MiddlewareFactory` toallow them to detect PSR-15 request handlers, and decorate them usingzend-stratigility's `RequestHandlerMiddleware`. This ensures type-safetywhen used in either pipelines or with routed middleware, but alsoensures we can use the full-spectrum of available handlers with thesystem.A new method was also added to `MiddlewareFactory`: `handler()`. Thismethod accepts a `RequestHandlerInterface` instance and returns a`RequestHandlerMiddleware` instance decorating it, making it simple touse request handlers with the explicit functionality ofzend-expressive-router's `PathBasedRoutingMiddleware` API.
Uh oh!
There was an error while loading.Please reload this page.
This patch implements the changes as outlined in theRFC: Expressive 3 Design Changes, as well as those as outlined inthis comment andthis comment, below.
In particular:
Updates to consume and implement PSR-15.
The following changes were made to middleware marshaling:
A new class,
MiddlewareContainer, implementing PSR-11'sContainerInterfaceand decorating aContainerInterface. This class ensures that middleware pulled from the container implements the PSR-15MiddlewareInterface. It also allows retrieving middleware by class name if the class does not require constructor arguments.A new class,
MiddlewareFactory, accepts a PSR-11ContainerInterfaceto its constructor, which it decorates internally as aMiddlewareContainer. It then exposes methods for marshaling middleware:callable(callable $middleware) : CallableMiddlewareDecoratorlazy(string $middleware) : LazyLoadingMiddlewarepipeline(...$middleware) : MiddlewarePipelinepath(string $path, $middleware) : PathMiddlewareDecoratorprepare($middleware) : MiddlewareInterface; this one proxies to the other methods.Double-pass middleware is not supported.
A new class,
ApplicationRunner, composes:RequestHandlerInterfaceinstance (typically, aMiddlewarePipeInterface)EmitterInterfaceinstance (typically, anEmitterStackcomposing aSapiEmitter)ServerRequestInterfaceinstanceWhen
run()is called, the class marshals a request, potentially generates an error response, and otherwise passes handling of the request to the handler; it then passes the returned response to the emitter.This class can potentially be extracted to its own library.
The
RouteMiddlewarehas been updated to add the methodsroute,get,post, etc. fromApplication. UnlikeApplication, they only acceptMiddlewareInterfaceinstances.New factories (in the
Zend\Expressive\Containernamespace):RouteMiddlewareFactoryDispatchMiddlewareFactoryEmitterFactoryshould be mapped toZend\Diactros\Response\EmitterInterface.ServerRequestFactoryFactoryshould be mapped toZend\Expressive\ServerRequestFactoryServerRequestErrorResponseGeneratorFactoryshould be mapped toZend\Expressive\ServerRequestErrorResponseGenerator.Applicationhas been completely rewritten. It now composes:MiddlewareFactoryinstanceMiddlewarePipeInterfaceinstance, generally aMiddlewarePipeRouteMiddlewareinstanceApplicationRunnerinstanceIt implements
RequestHandlerInterfaceandMiddlewareInterface, and composes theApplicationConfigInjectionTrait. It defines the same public API as previously, minus the various getters (as none of them are applicable anymore). Each method now proxies to the appropriate collaborator, pre-processing arguments as necessary:handle()delegates to theMiddlewarePipeInterfaceprocess()delegates to theMiddlewarePipeInterfacerun()delegates to theApplicationRunnerpipe()delegates to theMiddlewarePipeInterface, after first passing its arguments to theMiddlewareFactory, and, in the case of two arguments, theZend\Stratigility\path()utility function.route()and related methods delegate to theRouteMiddleware, after first passing the$middlewareargument to theMiddlewareFactorypipeRoutingMiddlewareandpipeDispatchMiddlewareare removed; users will now pipe these middleware just like any other middleware.Zend\Expressive\Delegate\NotFoundDelegatewas renamed toZend\Expressive\Handler\NotFoundHandler.Zend\Expressive\Middleware\NotFoundHandlerwas renamed toZend\Expressive\Middleware\NotFoundMiddleware; its related factory in theZend\Expressive\Containernamespace was similarly renamed.Tests were updated to reflect the changes, as necessary.
Updates