{"action":"created","issue":{"url":"https://api.github.com/repos/zendframework/zend-eventmanager/issues/4","labels_url":"https://api.github.com/repos/zendframework/zend-eventmanager/issues/4/labels{/name}","comments_url":"https://api.github.com/repos/zendframework/zend-eventmanager/issues/4/comments","events_url":"https://api.github.com/repos/zendframework/zend-eventmanager/issues/4/events","html_url":"https://github.com/zendframework/zend-eventmanager/pull/4","id":92741693,"number":4,"title":"[WIP] Alternate EventManager refactor","user":{"login":"weierophinney","id":25943,"avatar_url":"https://avatars.githubusercontent.com/u/25943?v=3","gravatar_id":"","url":"https://api.github.com/users/weierophinney","html_url":"https://github.com/weierophinney","followers_url":"https://api.github.com/users/weierophinney/followers","following_url":"https://api.github.com/users/weierophinney/following{/other_user}","gists_url":"https://api.github.com/users/weierophinney/gists{/gist_id}","starred_url":"https://api.github.com/users/weierophinney/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/weierophinney/subscriptions","organizations_url":"https://api.github.com/users/weierophinney/orgs","repos_url":"https://api.github.com/users/weierophinney/repos","events_url":"https://api.github.com/users/weierophinney/events{/privacy}","received_events_url":"https://api.github.com/users/weierophinney/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/zendframework/zend-eventmanager/labels/BC%20Break","name":"BC Break","color":"e11d21"},{"url":"https://api.github.com/repos/zendframework/zend-eventmanager/labels/enhancement","name":"enhancement","color":"84b6eb"},{"url":"https://api.github.com/repos/zendframework/zend-eventmanager/labels/WIP","name":"WIP","color":"0b02e1"}],"state":"open","locked":false,"assignee":null,"milestone":{"url":"https://api.github.com/repos/zendframework/zend-eventmanager/milestones/2","html_url":"https://github.com/zendframework/zend-eventmanager/milestones/3.0.0","labels_url":"https://api.github.com/repos/zendframework/zend-eventmanager/milestones/2/labels","id":1137638,"number":2,"title":"3.0.0","description":"next backward compatibility break release","creator":{"login":"Maks3w","id":1301698,"avatar_url":"https://avatars.githubusercontent.com/u/1301698?v=3","gravatar_id":"","url":"https://api.github.com/users/Maks3w","html_url":"https://github.com/Maks3w","followers_url":"https://api.github.com/users/Maks3w/followers","following_url":"https://api.github.com/users/Maks3w/following{/other_user}","gists_url":"https://api.github.com/users/Maks3w/gists{/gist_id}","starred_url":"https://api.github.com/users/Maks3w/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Maks3w/subscriptions","organizations_url":"https://api.github.com/users/Maks3w/orgs","repos_url":"https://api.github.com/users/Maks3w/repos","events_url":"https://api.github.com/users/Maks3w/events{/privacy}","received_events_url":"https://api.github.com/users/Maks3w/received_events","type":"User","site_admin":false},"open_issues":1,"closed_issues":0,"state":"open","created_at":"2015-05-28T09:27:58Z","updated_at":"2015-07-02T21:42:41Z","due_on":null,"closed_at":null},"comments":60,"created_at":"2015-07-02T21:41:14Z","updated_at":"2015-09-28T22:26:08Z","closed_at":null,"pull_request":{"url":"https://api.github.com/repos/zendframework/zend-eventmanager/pulls/4","html_url":"https://github.com/zendframework/zend-eventmanager/pull/4","diff_url":"https://github.com/zendframework/zend-eventmanager/pull/4.diff","patch_url":"https://github.com/zendframework/zend-eventmanager/pull/4.patch"},"body":"- Removes:\r\n  - `SharedEventAggregateAwareInterface::detachAggregate`\r\n  - `SharedEventManagerAwareInterface::getSharedManager` and `unsetSharedManager`.\r\n- Modifies:\r\n  - `EventManagerInterface::attach` renames `$callback` to `$listener`, typehints it as callable, and makes it required. The method no longer has a return value.\r\n  - `EventManagerInterface::detach` renames `$callback` to `$listener`, and typehints it as callable; it also adds a second, optional argument, `$event`, for indicating which event(s) to detach the listener from (no `$event` or `*` means all events).\r\n  - `EventManagerInterface::trigger` now typehints the `$callback` argument as callable\r\n  - `SharedEventManagerInterface::getListeners` now markes the `$event` argument as optional, and returns an array.\r\n- Adds:\r\n  - `Exception\\RuntimeException`\r\n  - `LazyListener`; this allows specifying a listener \"specification\" that includes the listener service name and method, and which creates a closure around pulling the listener service from a container and invoking the provided method on it.\r\n  - `LazyListenerAggregate`, which allows creating a set of lazy listeners to attach as an aggregate.\r\n\r\nAll implementations of the above interfaces were modified accordingly.\r\n\r\n`SharedEventManager` was modified to store the various listeners within structured arrays instead of `EventManager` and/or `PriorityQueue` instances.\r\n\r\n`EventManager` was altered to accept both identifiers and a `SharedEventManager` instance to the constructor. It now composes `FastPriorityQueue` instances (from zend-stdlib 2.7+), which provide significant performance improvement.\r\n\r\nThe first time *any* event is triggered, and only the first time, a call is made to a new method, `prepareListeners`; this method does the following:\r\n\r\n- It loops through all identifiers,\r\n- If a shared manager is present, it:\r\n  - pulls listeners from the shared manager based on those identifiers, attaching each;\r\n  - attaches listeners attached to the wildcard identifier.\r\n- Finally, it loops through all events, attaching any listeners attached to wildcard events.\r\n\r\nThe BC breaks from this approach are as follows:\r\n\r\n- Obviously, if you used any of the removed methods, they are no longer available.\r\n\r\n- `CallbackHandler` instances can no longer be used when calling `attach()`\r\n\r\n- Any shared listeners attached *after* the first `trigger()` call will not be executed. This means attachment of shared listeners should be done early, before calling instance methods on the target.\r\n\r\nThe changes, however, are essentially BC with the current solution.\r\n\r\n**My initial benchmarks show that execution is around twice as fast as the current solution.** This keeps the differentiating features of our solution, including the granularity of listener attachment, at a substantial speed savings.\r\n\r\n## TODO\r\n\r\n- [x] Addition of lazy-loading listeners, per #2 .\r\n- [x] Testing\r\n- [x] Performance benchmarking tests (via Athletic)\r\n- [x] Investigate and/or implement `detach()` functionality\r\n- [x] Integrate new zend-stdlib FastPriorityQueue\r\n- [x] Determine if we can support preparing at each trigger, now that performance is largely solved with FastPriorityQueue.\r\n- [x] Use an event prototype instead of an event class for instances; clone it when building new event instances.\r\n- [x] Consider having two trigger methods:\r\n  ```php\r\n  public function trigger($event, $target, $args = [], callable $shortCircuit = null);\r\n  public function triggerEvent(EventInterface $event, callable $shortcircuit = null);\r\n  ```\r\n  The former would no longer allow multiple signatures, simplifying the internal logic for creating the Event instance and verifying arguments; the latter would provide a way to use an Event instance when triggering. We could potentially add the latter to a minor version on the 2.X series to signal a forward migration path for users.\r\n- [x] Remove all shared aggregate concepts (too painful to maintain, not widely used).\r\n- [x] Increase test coverage\r\n- [x] Remove getEvents() and getListeners() from EventManagerInterface/EventManager.\r\n- [ ] Remove `(attach|detach)Aggregate()` from `EventManagerInterface` and document in migration guide how to forward-proof attaching aggregates in existing applications.\r\n- [ ] Add `$priority = 1` argument to `ListenerAggregateInterface::attach()`, and document in migration guide how to forward-proof existing aggregate implementations.\r\n- [ ] Migration scripts"},"comment":{"url":"https://api.github.com/repos/zendframework/zend-eventmanager/issues/comments/143891298","html_url":"https://github.com/zendframework/zend-eventmanager/pull/4#issuecomment-143891298","issue_url":"https://api.github.com/repos/zendframework/zend-eventmanager/issues/4","id":143891298,"user":{"login":"bakura10","id":1198915,"avatar_url":"https://avatars.githubusercontent.com/u/1198915?v=3","gravatar_id":"","url":"https://api.github.com/users/bakura10","html_url":"https://github.com/bakura10","followers_url":"https://api.github.com/users/bakura10/followers","following_url":"https://api.github.com/users/bakura10/following{/other_user}","gists_url":"https://api.github.com/users/bakura10/gists{/gist_id}","starred_url":"https://api.github.com/users/bakura10/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/bakura10/subscriptions","organizations_url":"https://api.github.com/users/bakura10/orgs","repos_url":"https://api.github.com/users/bakura10/repos","events_url":"https://api.github.com/users/bakura10/events{/privacy}","received_events_url":"https://api.github.com/users/bakura10/received_events","type":"User","site_admin":false},"created_at":"2015-09-28T22:26:08Z","updated_at":"2015-09-28T22:26:08Z","body":"Did you try array_replace_recursive after all?\r\n\r\nAnyway, thanks A LOT for taking care of the tests for me!"}}