-
Notifications
You must be signed in to change notification settings - Fork 91
Refactored to use upcoming EventManager v3 #31
Changes from all commits
3bdb9f4
953fa75
8b7915a
c342944
bdacaee
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
/doc export-ignore | ||
/test export-ignore | ||
/vendor export-ignore | ||
.coveralls.yml export-ignore | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,6 +6,7 @@ | |
.*.sw* | ||
.*.un~ | ||
nbproject | ||
doc/html/ | ||
tmp/ | ||
|
||
clover.xml | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
# Migration Guide | ||
|
||
This is a guide for migration from version 2 to version 3 of zend-mvc. | ||
|
||
## Application | ||
|
||
The constructor signature of `Zend\Mvc\Application` has changed. Previously, it | ||
was: | ||
|
||
```php | ||
__construct($configuration, ServiceManager $serviceManager) | ||
``` | ||
|
||
and internally, it pulled the services `EventManager`, `Request`, and `Response` | ||
from the provided `$serviceManager` during initialization. | ||
|
||
The new constructor signature is: | ||
|
||
```php | ||
__construct( | ||
$configuration, | ||
ServiceManager $serviceManager, | ||
EventManager $events, | ||
RequestInterface $request, | ||
ResponseInterface $response | ||
) | ||
``` | ||
|
||
making all dependencies explicit. The factory | ||
`Zend\Mvc\Service\ApplicationFactory` was updated to follow the new signature. | ||
|
||
This change should only affect users who are manually instantiating the | ||
`Application` instance. | ||
|
||
## EventManager initializer and ControllerManager event manager injection | ||
|
||
zend-mvc provides two mechanisms for injecting event managers into | ||
`EventManagerAware` objects. One is the "EventManagerAwareInitializer" | ||
registered in `Zend\Mvc\Service\ServiceManagerConfig`, and the other is internal | ||
logic in `Zend\Mvc\Controller\ControllerManager`. In both cases, the logic was | ||
updated due to changes in the v3 version of zend-eventmanager. | ||
|
||
Previously each would check if the instance's `getEventManager()` method | ||
returned an event manager instance, and, if so, inject the shared event manager: | ||
|
||
```php | ||
$events = $instance->getEventManager(); | ||
if ($events instanceof EventManagerInterface) { | ||
$events->setSharedManager($container->get('SharedEventManager')); | ||
} | ||
``` | ||
|
||
In zend-eventmanager v3, event manager's are now injected with the shared | ||
manager at instantiation, and no setter exists for providing the shared manager. | ||
As such, the above logic changed to: | ||
|
||
```php | ||
$events = $instance->getEventManager(); | ||
if (! $events || ! $events->getSharedManager()) { | ||
$instance->setEventManager($container->get('EventManager')); | ||
} | ||
``` | ||
|
||
In other words, it re-injects with a new event manager instance if the instance | ||
pulled does not have a shared manager composed. | ||
|
||
This likely will not cause regressions in existing code, but may be something to | ||
be aware of if you were previously depending on lazy-loaded event manager | ||
state. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
{ | ||
"title": "zend-mvc: MVC application provider", | ||
"content": [ | ||
{"Intro": "../README.md"}, | ||
{"Migration Guide": "book/migration.md"} | ||
], | ||
"target": "./html" | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,6 +12,7 @@ | |
use Zend\EventManager\EventManagerAwareInterface; | ||
use Zend\EventManager\EventManagerInterface; | ||
use Zend\ServiceManager\ServiceManager; | ||
use Zend\Stdlib\RequestInterface; | ||
use Zend\Stdlib\ResponseInterface; | ||
|
||
/** | ||
|
@@ -103,15 +104,18 @@ class Application implements | |
* @param mixed $configuration | ||
* @param ServiceManager $serviceManager | ||
*/ | ||
public function __construct($configuration, ServiceManager $serviceManager) | ||
{ | ||
public function __construct( | ||
$configuration, | ||
ServiceManager $serviceManager, | ||
EventManagerInterface $events, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we provide defaults to avoid BC break? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Absolutely agree here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a BC break but we are working to mvc 3.0 if it is a GOOD BC break this is a good time to merge it There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @gianarb it is kind of a big one, tbh, and it can be avoided There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Putting a note here as threads got broken up by me answering via email. This change was for a reason, which I stated in the PR summary: I ended up with a circular reference issue with the ApplicationFactory + EventManagerAware initializer that resulted in invalid EventManager state. The result was that the EM instance injected no longer had the default listeners injected, which broke the entire thing. As I noted in another comment elsewhere: hardly anybody directly instantiates the |
||
RequestInterface $request, | ||
ResponseInterface $response | ||
) { | ||
$this->configuration = $configuration; | ||
$this->serviceManager = $serviceManager; | ||
|
||
$this->setEventManager($serviceManager->get('EventManager')); | ||
|
||
$this->request = $serviceManager->get('Request'); | ||
$this->response = $serviceManager->get('Response'); | ||
$this->setEventManager($events); | ||
$this->request = $request; | ||
$this->response = $response; | ||
} | ||
|
||
/** | ||
|
@@ -142,19 +146,20 @@ public function bootstrap(array $listeners = []) | |
$listeners = array_unique(array_merge($this->defaultListeners, $listeners)); | ||
|
||
foreach ($listeners as $listener) { | ||
$events->attach($serviceManager->get($listener)); | ||
$serviceManager->get($listener)->attach($events); | ||
} | ||
|
||
// Setup MVC Event | ||
$this->event = $event = new MvcEvent(); | ||
$event->setName(MvcEvent::EVENT_BOOTSTRAP); | ||
$event->setTarget($this); | ||
$event->setApplication($this) | ||
->setRequest($this->request) | ||
->setResponse($this->response) | ||
->setRouter($serviceManager->get('Router')); | ||
$event->setApplication($this); | ||
$event->setRequest($this->request); | ||
$event->setResponse($this->response); | ||
$event->setRouter($serviceManager->get('Router')); | ||
|
||
// Trigger bootstrap events | ||
$events->trigger(MvcEvent::EVENT_BOOTSTRAP, $event); | ||
$events->triggerEvent($event); | ||
return $this; | ||
} | ||
|
||
|
@@ -294,13 +299,15 @@ public function run() | |
}; | ||
|
||
// Trigger route event | ||
$result = $events->trigger(MvcEvent::EVENT_ROUTE, $event, $shortCircuit); | ||
$event->setName(MvcEvent::EVENT_ROUTE); | ||
$result = $events->triggerEventUntil($shortCircuit, $event); | ||
if ($result->stopped()) { | ||
$response = $result->last(); | ||
if ($response instanceof ResponseInterface) { | ||
$event->setName(MvcEvent::EVENT_FINISH); | ||
$event->setTarget($this); | ||
$event->setResponse($response); | ||
$events->trigger(MvcEvent::EVENT_FINISH, $event); | ||
$events->triggerEvent($event); | ||
$this->response = $response; | ||
return $this; | ||
} | ||
|
@@ -311,14 +318,16 @@ public function run() | |
} | ||
|
||
// Trigger dispatch event | ||
$result = $events->trigger(MvcEvent::EVENT_DISPATCH, $event, $shortCircuit); | ||
$event->setName(MvcEvent::EVENT_DISPATCH); | ||
$result = $events->triggerEventUntil($shortCircuit, $event); | ||
|
||
// Complete response | ||
$response = $result->last(); | ||
if ($response instanceof ResponseInterface) { | ||
$event->setName(MvcEvent::EVENT_FINISH); | ||
$event->setTarget($this); | ||
$event->setResponse($response); | ||
$events->trigger(MvcEvent::EVENT_FINISH, $event); | ||
$events->triggerEvent($event); | ||
$this->response = $response; | ||
return $this; | ||
} | ||
|
@@ -350,8 +359,13 @@ protected function completeRequest(MvcEvent $event) | |
{ | ||
$events = $this->events; | ||
$event->setTarget($this); | ||
$events->trigger(MvcEvent::EVENT_RENDER, $event); | ||
$events->trigger(MvcEvent::EVENT_FINISH, $event); | ||
|
||
$event->setName(MvcEvent::EVENT_RENDER); | ||
$events->triggerEvent($event); | ||
|
||
$event->setName(MvcEvent::EVENT_FINISH); | ||
$events->triggerEvent($event); | ||
|
||
return $this; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Newline before this line (keeps consistent with the changes above) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Noted, and staged locally to push with other changes. |
||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -109,13 +109,14 @@ public function dispatch(Request $request, Response $response = null) | |
$this->response = $response; | ||
|
||
$e = $this->getEvent(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. While at it, maybe rename it There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Out of scope for this PR; I tried very hard only to update the code necessary to get the EM refactor working with it. If you feel strongly, open new PRs. |
||
$e->setRequest($request) | ||
->setResponse($response) | ||
->setTarget($this); | ||
$e->setName(MvcEvent::EVENT_DISPATCH); | ||
$e->setRequest($request); | ||
$e->setResponse($response); | ||
$e->setTarget($this); | ||
|
||
$result = $this->getEventManager()->trigger(MvcEvent::EVENT_DISPATCH, $e, function ($test) { | ||
$result = $this->getEventManager()->triggerEventUntil(function ($test) { | ||
return ($test instanceof Response); | ||
}); | ||
}, $e); | ||
|
||
if ($result->stopped()) { | ||
return $result->last(); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,7 +10,7 @@ | |
namespace Zend\Mvc\Controller; | ||
|
||
use Zend\EventManager\EventManagerAwareInterface; | ||
use Zend\EventManager\EventManagerInterface; | ||
use Zend\EventManager\SharedEventManagerInterface; | ||
use Zend\Mvc\Exception; | ||
use Zend\ServiceManager\AbstractPluginManager; | ||
use Zend\ServiceManager\ConfigInterface; | ||
|
@@ -73,10 +73,8 @@ public function injectControllerDependencies($controller, ServiceLocatorInterfac | |
// is why the shared EM injection needs to happen; the conditional | ||
// will always pass. | ||
$events = $controller->getEventManager(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Will need to check this against an interface (as per comment below), as the aware interface defines no getter :-( There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please see my previous comment...
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
if (!$events instanceof EventManagerInterface) { | ||
if (! $events || ! $events->getSharedManager() instanceof SharedEventManagerInterface) { | ||
$controller->setEventManager($parentLocator->get('EventManager')); | ||
} else { | ||
$events->setSharedManager($parentLocator->get('SharedEventManager')); | ||
} | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -177,9 +177,9 @@ protected function detachProblemListeners(SharedEvents $sharedEvents) | |
$results[$id] = []; | ||
foreach ($eventArray as $eventName => $classArray) { | ||
$results[$id][$eventName] = []; | ||
$events = $sharedEvents->getListeners($id, $eventName); | ||
$events = $sharedEvents->getListeners([$id], $eventName); | ||
foreach ($events as $currentEvent) { | ||
$currentCallback = $currentEvent->getCallback(); | ||
$currentCallback = $currentEvent; | ||
|
||
// If we have an array, grab the object | ||
if (is_array($currentCallback)) { | ||
|
@@ -193,7 +193,7 @@ protected function detachProblemListeners(SharedEvents $sharedEvents) | |
|
||
foreach ($classArray as $class) { | ||
if ($currentCallback instanceof $class) { | ||
$sharedEvents->detach($id, $currentEvent); | ||
$sharedEvents->detach($currentEvent, $id); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a super-subtle bc break. Is it possible to revert this in the EVM instead? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No. In the new version, the second argument is optional, the first required.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see. Still very very very annoying BC break There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's a rarely used feature, TBH; there are very few use cases currently for detaching listeners, much less shared listeners, and the Though with React, I suspect it will becomes more common. Those users will adopt v3 anyways, as it's faster. 😄 |
||
$results[$id][$eventName][] = $currentEvent; | ||
} | ||
} | ||
|
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.
Note: should probably use
zend-eventmanager dev-develop as 3.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.
Can't yet; not all components are updated to zend-eventmanager v3 yet, which means that there will be an unresolveable conflict. (I know; I tried. 😄)