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

Commit 9784e7b

Browse files
committed
docs: provide comprehensive checklist for PSR-14 adoption
1 parent 4fbd54a commit 9784e7b

File tree

1 file changed

+183
-0
lines changed

1 file changed

+183
-0
lines changed

TODO-PSR-14.md

Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
# TODO for PSR-14 implementation
2+
3+
## 3.3.0 forwards-compatibility release
4+
5+
- [ ] `StoppableEventInterface` implementation
6+
- [x] Create a `StoppableEventInterface`
7+
- [x] Make `Event` implement it
8+
- [x] Deprecate `propagationIsStopped()` in both `EventInterface` and `Event`
9+
- [x] Have `Event::propagationIsStopped()` proxy to `Event::isPropagationStopped()`
10+
- [x] Modify `EventManager` internals to use the PSR-14 method if available
11+
- [ ] Mark `StoppableEventInterface` as deprecated
12+
- [ ] Listener provider implementation
13+
- [ ] Create a `ListenerProvider` subnamespace
14+
- [ ] Create a `ListenerProviderInterface` shim
15+
- [ ] Create a `PrioritizedListenerProvider` interface extending the
16+
`ListenerProviderInterface` and defining a
17+
`getListenersForEventByPriority($event, array $identifiers = []) : array<int, callable[]>` method.
18+
- [ ] Create a `PrioritizedListenerAttachmentInterface`, defining:
19+
- [ ] `attach($event, callable $listener, $priority = 1)` (where `$event`
20+
can be an object or string name)
21+
- [ ] `detach(callable $listener, $event = null, $force = false)` (where `$event`
22+
can be an object or string name and `$force` is boolean)
23+
- [ ] `attachWildcardListener(callable $listener, $priority = 1)`
24+
(`attach('*', $listener, $priority)` will proxy to this method)
25+
- [ ] Create a `PrioritizedListenerProvider` implementation of the above based
26+
on the internals of `EventManager`
27+
- [ ] attachment/detachment
28+
- [ ] getListenersForEvent should take into account event name if an EventInterface
29+
- [ ] getListenersForEvent should also pull wildcard listeners
30+
- [ ] getListenersForEvent should accept an optional second argument, an
31+
array of identifiers. This method will return all listeners in prioritized
32+
order.
33+
- [ ] implement `getListenersForEventByPriority`
34+
- [ ] Create a `PrioritizedIdentifierListenerProvider` that implements
35+
both the `PrioritizedListenerProvider` interface and the
36+
`SharedEventManagerInterface`
37+
- [ ] implement `getListenersForEventByPriority`
38+
- [ ] `SharedEventManager` will extend this class
39+
- [ ] mark as deprecated (will not use this in v4)
40+
- [ ] Create a `PrioritizedAggregateListenerProvider` implementation
41+
- [ ] Accepts a list of `PrioritizedListenerProvider` instances
42+
- [ ] `getListenersByEvent()` will loop through each, in order, calling the
43+
`getListenersForEventByPriority()` method of each, returning the
44+
aggregated listeners in priority order.
45+
- [ ] Create `ListenerSubscriberInterface`
46+
- [ ] `attach(PrioritizedListenerAttachmentInterface $provider, $priority = 1)`
47+
- [ ] `detach(PrioritizedListenerAttachmentInterface $provider)`
48+
- [ ] Create `AbstractListenerSubscriber` and/or `ListenerSubscriberTrait`
49+
- [ ] define a default `detach()` implementation
50+
- [ ] Create `LazyListenerSubscriber` based on `LazyListenerAggregate`
51+
- [ ] Define an alternate LazyListener:
52+
- [ ] `__construct(ContainerInterface $container, string $event = null, int $priority = 1)`
53+
- [ ] implements functionality from both `LazyListener` and `LazyEventListener`, minus passing env to container
54+
- [ ] without an event, can be attached to any provider
55+
- [ ] with an event, can be attached to `LazyListenerSubscriber`
56+
- Constructor aggregates `LazyListener` _instances_ only
57+
- [ ] `attach()` skips any where `getEvent()` returns null
58+
- [ ] Event Dispatcher implementation
59+
- [ ] Create a `PrioritizedListenerProvider` instance in the `EventManger`
60+
constructor, and have the various `attach()`, `detach()`, etc. methods
61+
proxy to it.
62+
- [ ] When triggering listeners, create a `PrioritizedAggregateListenerProvider`
63+
with the composed `PrioritizedListenerProvider` and `SharedListenerProvider` /
64+
`PrioritizedIdentifierListenerProvider` implementations, in that order.
65+
- [ ] Replace logic of `triggerListeners()` to just call
66+
`getListenersForEvent()` on the provider. It can continue to aggregate the
67+
responses in a `ResponseCollection`
68+
- [ ] `triggerListeners()` no longer needs to type-hint its first argument
69+
- [ ] Create a `dispatch()` method
70+
- [ ] Method will act like `triggerEvent()`, except
71+
- [ ] it will return the event itself
72+
- [ ] it will need to validate that it received an object before calling
73+
`triggerListeners`
74+
- [ ] Additional utilities
75+
- [ ] `EventDispatchingInterface` with a `getEventDispatcher()` method
76+
- [ ] Alternate dispatcher implementation, `EventDispatcher`
77+
- [ ] Should accept a listener provider interface to its constructor
78+
- [ ] Should implement `EventDispatcherInterface` via duck-typing: it will
79+
implement a `dispatch()` method only
80+
- [ ] Deprecations
81+
- [ ] `EventInterface`
82+
- [ ] `EventManager`
83+
- [ ] `EventManagerInterface`
84+
- [ ] `EventManagerAwareInterface`
85+
- [ ] `EventManagerAwareTrait`
86+
- [ ] `EventsCapableInterface` (point people to `EventDispatchingInterface`)
87+
- [ ] `SharedEventManager`
88+
- [ ] `SharedEventManagerInterface`
89+
- [ ] `SharedEventsCapableInterface`
90+
- [ ] `ListenerAggregateInterface` (point people to the `PrioritizedListenerAttachmentInterface`)
91+
- [ ] `ListenerAggregateTrait` (point people to `ListenerSubscriberTrait`)
92+
- [ ] `AbstractListenerAggregate` (point people to `AbstractListenerSubscriber` and/or `ListenerSubscriberTrait`)
93+
- [ ] `ResponseCollection` (tell people to aggregate state/results in the event itself)
94+
- [ ] `LazyListener` (point people to `ListenerProvider\LazyListener`)
95+
- [ ] `LazyEventListener` (point people to `ListenerProvider\LazyListener`)
96+
- [ ] `LazyListenerAggregate` (point people to `ListenerProvider\LazyListenerSubscriber`)
97+
- [ ] `FilterChain` and `Filter` subnamespace (this should be done in a separate component)
98+
99+
## 4.0.0 full release
100+
101+
- [ ] Removals
102+
- [ ] `EventInterface`
103+
- [ ] `EventManager`
104+
- [ ] `EventManagerInterface`
105+
- [ ] `EventManagerAwareInterface`
106+
- [ ] `EventManagerAwareTrait`
107+
- [ ] `EventsCapableInterface`
108+
- [ ] `SharedEventManager`
109+
- [ ] `SharedEventManagerInterface`
110+
- [ ] `SharedEventsCapableInterface`
111+
- [ ] `ListenerAggregateInterface`
112+
- [ ] `ListenerAggregateTrait`
113+
- [ ] `AbstractListenerAggregate`
114+
- [ ] `ResponseCollection`
115+
- [ ] `LazyListener`
116+
- [ ] `LazyEventListener`
117+
- [ ] `LazyListenerAggregate`
118+
- [ ] `FilterChain` and `Filter` subnamespace
119+
- [ ] `StoppableEventInterface` (will use PSR-14 version)
120+
- [ ] `ListenerProviderInterface` (will use PSR-14 version)
121+
- [ ] `PrioritizedIdentifierListenerProvider`
122+
- Changes
123+
- [ ] `PrioritizedListenerAttachmentInterface` (and implementations)
124+
- [ ] extend PSR-14 `ListenerProviderInterface`
125+
- [ ] add `string` typehint to `$event` in `attach()` and `detach()`
126+
- [ ] add `bool` typehint to `$force` argument of `detach()`
127+
- [ ] `PrioritizedListenerProvider` interface (and implementations)
128+
- [ ] Fulfill PSR-14 `ListenerProviderInterface`
129+
- [ ] remove `$identifiers` argument to getListenersForEventByPriority and getListenersForEvent
130+
- [ ] add `object` typehint to `getListenersForEventByPriority`
131+
- [ ] `EventDispatcher`
132+
- [ ] implement PSR-14 `EventDispatcherInterface`
133+
134+
## Concerns
135+
136+
### MVC
137+
138+
Currently, the MVC relies heavily on:
139+
140+
- event names (vs types)
141+
- event targets
142+
- event params
143+
- `stopPropagation($flag)` (vs custom stop conditions in events)
144+
- `triggerEventUntil()` (vs custom stop conditions in events)
145+
146+
We would need to draw attention to usage of methods that are not specific to an
147+
event implementation, and recommend usage of other methods where available.
148+
(We would likely keep the params implementation, however, to allow passing
149+
messages via the event instance(s).)
150+
151+
Additionally, we will need to have some sort of event hierarchy:
152+
153+
- a base MVC event from which all others derive. This will be necessary to
154+
ensure that existing code continues to work.
155+
- a BootstrapEvent
156+
- a RouteEvent
157+
- a DispatchEvent
158+
- a DispatchControllerEvent
159+
- a DispatchErrorEvent
160+
- Potentially broken into a RouteUnmatchedEvent, DispatchExceptionEvent,
161+
MiddlewareExceptionEvent, ControllerNotFoundEvent, InvalidControllerEvent,
162+
and InvalidMiddlewareEvent
163+
- a RenderEvent
164+
- a RenderErrorEvent
165+
- a FinishEvent
166+
- a SendResponseEvent (this one is not an MvcEvent, however)
167+
168+
The event names associated with each would be based on existing event names,
169+
allowing the ability to attach using legacy names OR the class name.
170+
171+
We can allow using `stopPropagation()`, but have it trigger a deprecation
172+
notice, asking users to use more specific methods of the event to stop
173+
propagation, or, in the case of errors, raising exceptions.
174+
175+
- `setError()` would cause `isPropagationStopped()` to return true.
176+
- A new method, `setFinalResponse()` would both set the response instance, as
177+
well as cause `isPropagationStopped()` to return true.
178+
- The `RouteEvent` would also halt propagation when `setRouteResult()` is
179+
called.
180+
181+
Internally, we will also stop using the `*Until()` methods, and instead rely on
182+
the events to handle this for us. If we need a return value, we will instead
183+
pull it from the event on completion.

0 commit comments

Comments
 (0)