29 private array $listeners = [];
36 private array $pendingSubscribers = [];
40 private ObjectFactory $objectFactory;
43 $this->hookContainer = $hookContainer;
44 $this->objectFactory = $objectFactory;
57 $this->hookContainer->
run(
58 $event->getEventType(),
59 [ $event, $dbProvider, ]
70 if ( !is_callable( $listener ) ) {
71 throw new InvalidArgumentException(
'$listener must be callable' );
74 $this->registerTriggerIfNeeded( $eventType );
75 $this->listeners[$eventType][] = $listener;
87 $subscriber->registerListeners( $this );
91 if ( !is_array( $subscriber ) ) {
92 throw new InvalidArgumentException(
93 '$subscriber must be a DomainEventSubscriber or an array'
102 if ( !isset( $subscriber[
'events'] ) ) {
103 throw new InvalidArgumentException(
104 '$subscriber must contain the key "events" to specify which ' .
105 'events will trigger instantiation of the subscriber'
111 foreach ( $subscriber[
'events'] as $eventType ) {
112 $this->registerTriggerIfNeeded( $eventType );
115 $this->pendingSubscribers[$eventType][] =& $subscriber;
123 private function resolveSubscribers(
string $eventType ) {
126 $pending = $this->pendingSubscribers[$eventType] ?? [];
131 $this->pendingSubscribers[$eventType] = [];
134 foreach ( $pending as &$spec ) {
141 $this->applySubscriberSpec( $spec );
148 if ( $this->pendingSubscribers[$eventType] ) {
150 $this->resolveSubscribers( $eventType );
154 private function applySubscriberSpec( array $spec ) {
156 $subscriber = $this->objectFactory->createObject(
158 [
'assertClass' => DomainEventSubscriber::class, ]
161 if ( $subscriber instanceof InitializableDomainEventSubscriber ) {
162 $subscriber->initSubscriber( $spec );
165 $subscriber->registerListeners( $this );
172 private function registerTriggerIfNeeded(
string $eventName ) {
174 isset( $this->listeners[ $eventName ] ) ||
175 isset( $this->pendingSubscribers[ $eventName ] )
182 $this->hookContainer->register(
184 function ( DomainEvent $event, IConnectionProvider $dbProvider ) {
185 $this->dispatchInternal( $event, $dbProvider );
194 private function dispatchInternal( DomainEvent $event, IConnectionProvider $dbProvider ) {
195 $this->resolveSubscribers( $event->getEventType() );
196 $listeners = $this->listeners[ $event->getEventType() ] ?? [];
198 foreach ( $listeners as $callback ) {
199 $this->push( $callback, $event, $dbProvider );
207 private function push(
210 IConnectionProvider $dbProvider
214 $dbw = $dbProvider->getPrimaryDatabase();
215 DeferredUpdates::addUpdate(
new MWCallableUpdate(
216 function () use ( $callback, $event, $dbProvider ) {
217 $this->invoke( $callback, $event, $dbProvider );
227 private function invoke(
230 IConnectionProvider $dbProvider
232 $callback( $event, $dbProvider );