Skip to content
This repository has been archived by the owner on Jan 29, 2020. It is now read-only.

Conversation

Ocramius
Copy link
Member

@Ocramius Ocramius commented Apr 28, 2017

This patch makes sure that the successful dispatch of a middleware won't trigger exception and 404 strategies. This can happen when the return value of the MiddlewareListener is not a Zend\Stdlib\ResponseInterface instance, and therefore the EventManager will not short-circuit and stop event propagation.


 * ~~~`['foo' => 'bar']`~~~
 * ~~~`'Hello World!'`~~~
 * ~~~`new ViewModel(['foo' => 'bar'])`~~~

~~~This also fixes https://github.com/zendframework/zendframework/issues/5806~~ ERRATA: it doesn't, as #217 now enforces middleware to return `ResponseInterface` instances.

~~~I'm still stuck on this though. As per tradition `Zend\Mvc\ViewManager` is being absolutely useless, and [attaches all listeners to the shared manager `DispatchableInterface` identifier](https://github.com/zendframework/zend-mvc/blob/2c64d2ed50063e13b23f1c7e19f17ce3354bea36/src/View/Http/ViewManager.php#L124-L152): that means that basically nothing in the view layer works when using this stuff.~~~

~~~Currently preparing a workaround that triggers events that have the `DispatchableInterface` identifier, since otherwise it is impossible to get this thing running correctly.~~~

@@ -91,6 +90,8 @@ public function onDispatch(MvcEvent $event)
}
}

$event->setError('');
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: this still means that the DispatchListener will try to execute and fail. The patch is not yet done. Ideally, the DispatchListener should check whether there is a $event->getResult(), and bail out if there already is one.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd argue both the DispatchListener and MiddlewareListener should act that way, with the following at the top of the listeners:

if (null !== $e->getResult()) {
    return;
}

Do you want to incorporate that change in this PR?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@weierophinney done for both listeners

Copy link
Member

@weierophinney weierophinney left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this approach a ton; I think triggering events for dispatched middleware in the same way as for controllers could have a ton of benefits.

A few comments:

  • This is technically new functionality (new class), and I think it would be best to do for the 3.1.0 release. As such, you'd need to rebase against develop... which has a number of changes due to me merging Modify middleware listener to use stratigility pipe #217 earlier today. I'd be happy to help with that if you wish.
  • The MiddlewareController should also allow http-interop middleware; I have detailed comments on that below.
  • I agree that this and the DispatchListener should return early if the MvcEvent composes a result already, and think that change should be part of this PR (as this PR is the one that demonstrates the need for that change).

@@ -91,6 +90,8 @@ public function onDispatch(MvcEvent $event)
}
}

$event->setError('');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd argue both the DispatchListener and MiddlewareListener should act that way, with the following at the top of the listeners:

if (null !== $e->getResult()) {
    return;
}

Do you want to incorporate that change in this PR?

*/
private $middleware;

public function __construct(callable $middleware, EventManager $eventManager, MvcEvent $event)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a note: on the develop branch, we're now targeting Stratigility ^2.0.1, which means we can have:

  • callable middleware
  • http-interop middleware

If this patch targets master, we would need to remove the typehint for $middleware, and also update how middleware is invoked based on whether or not it implements Interop\Http\ServerMiddleware\MiddlewareInterface.

}
}

$result = \call_user_func($this->middleware, $psr7Request, Psr7Response::fromZend($response));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See previous note about http-interop.

@@ -76,6 +84,7 @@ public function testSuccessfullyDispatchesMiddleware()
$application = $event->getApplication();

$application->getEventManager()->attach(MvcEvent::EVENT_DISPATCH_ERROR, function ($e) {
die(var_dump($e->getParam('exception')->getMessage()));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Um, die()? Why not just a var_dump() or capturing that info to a variable to emit with the fail() below?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is also gone :-)

Ocramius added 23 commits May 1, 2017 20:00
…eware produces, regardless of its shape/type, unless it is a PSR7-response
…t is mocking anything particular at this point
…e useless view layer can do its terrible view model magic
…e of a middleware is OK

This is likely going to land into a separate dispatch listener instead
@Ocramius Ocramius force-pushed the fix/allow-middleware-dispatch-to-behave-like-controller-dispatch branch from 80200a7 to 98c6d39 Compare May 1, 2017 18:24
@Ocramius Ocramius changed the base branch from master to develop May 1, 2017 18:25
@Ocramius
Copy link
Member Author

Ocramius commented May 1, 2017

This is technically new functionality (new class), and I think it would be best to do for the 3.1.0 release. As such, you'd need to rebase against develop... which has a number of changes due to me merging #217 earlier today. I'd be happy to help with that if you wish.

Provided

The MiddlewareController should also allow http-interop middleware; I have detailed comments on that below.

That's also handled. The MiddlewareController, being an internal class, can be changed as much as it suits us.

I agree that this and the DispatchListener should return early if the MvcEvent composes a result already, and think that change should be part of this PR (as this PR is the one that demonstrates the need for that change).

Implemented/tested


public function __construct(
MiddlewarePipe $pipe,
ResponseInterface $responsePrototype,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not particularly proud of this, but PSR-7's immutability makes it quite acceptable to pass in a request as a prototype. Still, this class is designed as "fire once" and "internal" specifically due to this weirdness.

@Ocramius Ocramius changed the title [WIP] Fix: allow middleware dispatch to behave like controller dispatch Fix: allow middleware dispatch to behave like controller dispatch May 1, 2017
@weierophinney weierophinney merged commit a122791 into zendframework:develop May 1, 2017
weierophinney added a commit that referenced this pull request May 1, 2017
…o-behave-like-controller-dispatch

Fix: allow middleware dispatch to behave like controller dispatch
weierophinney added a commit that referenced this pull request May 1, 2017
weierophinney added a commit that referenced this pull request May 1, 2017
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants