Skip to content

Commit 88eadfc

Browse files
committed
feat: add event lifecycle hooks
1 parent 85f7487 commit 88eadfc

File tree

5 files changed

+1608
-11
lines changed

5 files changed

+1608
-11
lines changed

src/Illuminate/Events/Dispatcher.php

Lines changed: 40 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525

2626
class Dispatcher implements DispatcherContract
2727
{
28-
use Macroable, ReflectsClosures;
28+
use EventHooks, Macroable, ReflectsClosures;
2929

3030
/**
3131
* The IoC container instance.
@@ -216,7 +216,7 @@ public function subscribe($subscriber)
216216
protected function resolveSubscriber($subscriber)
217217
{
218218
if (is_string($subscriber)) {
219-
return $this->container->make($subscriber);
219+
return $this->getContainer()->make($subscriber);
220220
}
221221

222222
return $subscriber;
@@ -278,32 +278,61 @@ public function dispatch($event, $payload = [], $halt = false)
278278
*/
279279
protected function invokeListeners($event, $payload, $halt = false)
280280
{
281+
// If a callback throws an EventPropagationException, no further
282+
// callbacks are run and the event is not dispatched to listeners.
283+
try {
284+
if ($this->hasCallbacks(static::HOOK_BEFORE, $event)) {
285+
$this->invokeCallbacks(static::HOOK_BEFORE, $event, $payload);
286+
}
287+
} catch (EventPropagationException) {
288+
return null;
289+
}
290+
281291
if ($this->shouldBroadcast($payload)) {
282292
$this->broadcastEvent($payload[0]);
283293
}
284294

285295
$responses = [];
296+
$failure = false;
286297

287298
foreach ($this->getListeners($event) as $listener) {
288299
$response = $listener($event, $payload);
289300

290-
// If a response is returned from the listener and event halting is enabled
291-
// we will just return this response, and not call the rest of the event
292-
// listeners. Otherwise we will add the response on the response list.
301+
// If a response is returned from the listener and event halting is enabled, we
302+
// will fire the after callbacks (or the failure callbacks when boolean false is
303+
// returned, indicating failure), return this response, and not call the rest of
304+
// the event listeners, otherwise we will add the response to the response list.
293305
if ($halt && ! is_null($response)) {
306+
$hook = $response === false ? static::HOOK_FAILURE : static::HOOK_AFTER;
307+
if ($this->hasCallbacks($hook, $event)) {
308+
$this->invokeCallbacks($hook, $event, $payload);
309+
}
310+
294311
return $response;
295312
}
296313

297-
// If a boolean false is returned from a listener, we will stop propagating
298-
// the event to any further listeners down in the chain, else we keep on
299-
// looping through the listeners and firing every one in our sequence.
314+
// If a boolean false is returned from a listener (indicating failure), we will
315+
// fire the failure callbacks and stop propagating the event to any further
316+
// listeners down the chain, otherwise we keep on looping through the listeners
317+
// and firing each one in our sequence.
300318
if ($response === false) {
319+
if ($this->hasCallbacks(static::HOOK_FAILURE, $event)) {
320+
$this->invokeCallbacks(static::HOOK_FAILURE, $event, $payload);
321+
}
322+
323+
$failure = true;
324+
301325
break;
302326
}
303327

304328
$responses[] = $response;
305329
}
306330

331+
// If we've fired all listeners without failure, we will fire the after callbacks.
332+
if (! $failure && $this->hasCallbacks(static::HOOK_AFTER, $event)) {
333+
$this->invokeCallbacks(static::HOOK_AFTER, $event, $payload);
334+
}
335+
307336
return $halt ? null : $responses;
308337
}
309338

@@ -357,7 +386,7 @@ protected function broadcastWhen($event)
357386
*/
358387
protected function broadcastEvent($event)
359388
{
360-
$this->container->make(BroadcastFactory::class)->queue($event);
389+
$this->getContainer()->make(BroadcastFactory::class)->queue($event);
361390
}
362391

363392
/**
@@ -502,7 +531,7 @@ protected function createClassCallable($listener)
502531
return $this->createQueuedHandlerCallable($class, $method);
503532
}
504533

505-
$listener = $this->container->make($class);
534+
$listener = $this->getContainer()->make($class);
506535

507536
return $this->handlerShouldBeDispatchedAfterDatabaseTransactions($listener)
508537
? $this->createCallbackForListenerRunningAfterCommits($listener, $method)
@@ -599,7 +628,7 @@ function () use ($listener, $method, $payload) {
599628
*/
600629
protected function handlerWantsToBeQueued($class, $arguments)
601630
{
602-
$instance = $this->container->make($class);
631+
$instance = $this->getContainer()->make($class);
603632

604633
if (method_exists($instance, 'shouldQueue')) {
605634
return $instance->shouldQueue($arguments[0]);

0 commit comments

Comments
 (0)