From 2ba8e5cfe4cc19d9a0cf6854ec3bf609d3623a9c Mon Sep 17 00:00:00 2001 From: Jack Date: Sat, 8 Nov 2025 13:25:32 +0000 Subject: [PATCH] Add ability to default mailables and notifcations --- src/Illuminate/Mail/Mailable.php | 11 ++++- src/Illuminate/Notifications/Notification.php | 7 +++ .../Notifications/NotificationSender.php | 2 +- tests/Mail/MailableQueuedTest.php | 40 +++++++++++----- .../Notifications/NotificationSenderTest.php | 46 +++++++++++++++++++ 5 files changed, 92 insertions(+), 14 deletions(-) diff --git a/src/Illuminate/Mail/Mailable.php b/src/Illuminate/Mail/Mailable.php index 7e47f06a030d..8bd95e633639 100644 --- a/src/Illuminate/Mail/Mailable.php +++ b/src/Illuminate/Mail/Mailable.php @@ -189,6 +189,13 @@ class Mailable implements MailableContract, Renderable */ public static $viewDataCallback; + /** + * The name of the default queue that should be used when queued. + * + * @var string|null + */ + public static $defaultQueue; + /** * Send the message using the given mailer. * @@ -230,7 +237,7 @@ public function queue(Queue $queue) $connection = property_exists($this, 'connection') ? $this->connection : null; - $queueName = property_exists($this, 'queue') ? $this->queue : null; + $queueName = (property_exists($this, 'queue') ? $this->queue : null) ?? static::$defaultQueue; return $queue->connection($connection)->pushOn( $queueName ?: null, $this->newQueuedJob() @@ -248,7 +255,7 @@ public function later($delay, Queue $queue) { $connection = property_exists($this, 'connection') ? $this->connection : null; - $queueName = property_exists($this, 'queue') ? $this->queue : null; + $queueName = (property_exists($this, 'queue') ? $this->queue : null) ?? static::$defaultQueue; return $queue->connection($connection)->laterOn( $queueName ?: null, $delay, $this->newQueuedJob() diff --git a/src/Illuminate/Notifications/Notification.php b/src/Illuminate/Notifications/Notification.php index 3af22645e478..0fb678ff32e2 100644 --- a/src/Illuminate/Notifications/Notification.php +++ b/src/Illuminate/Notifications/Notification.php @@ -22,6 +22,13 @@ class Notification */ public $locale; + /** + * The name of the default queue that should be used when queued. + * + * @var string|null + */ + public static $defaultQueue; + /** * Get the channels the event should broadcast on. * diff --git a/src/Illuminate/Notifications/NotificationSender.php b/src/Illuminate/Notifications/NotificationSender.php index f6625558c417..488b08f51aa4 100644 --- a/src/Illuminate/Notifications/NotificationSender.php +++ b/src/Illuminate/Notifications/NotificationSender.php @@ -235,7 +235,7 @@ protected function queueNotification($notifiables, $notification) $connection = $notification->viaConnections()[$channel] ?? null; } - $queue = $notification->queue; + $queue = $notification->queue ?? Notification::$defaultQueue; if (method_exists($notification, 'viaQueues')) { $queue = $notification->viaQueues()[$channel] ?? null; diff --git a/tests/Mail/MailableQueuedTest.php b/tests/Mail/MailableQueuedTest.php index 2841745f7b2e..5812f96a6875 100644 --- a/tests/Mail/MailableQueuedTest.php +++ b/tests/Mail/MailableQueuedTest.php @@ -15,6 +15,7 @@ use Illuminate\Support\Testing\Fakes\QueueFake; use Laravel\SerializableClosure\SerializableClosure; use Mockery as m; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; use Symfony\Component\Mailer\Transport\TransportInterface; @@ -25,18 +26,35 @@ protected function tearDown(): void m::close(); } - public function testQueuedMailableSent(): void + public static function defaultQueueDataProvider() { - $queueFake = new QueueFake(new Application); - $mailer = $this->getMockBuilder(Mailer::class) - ->setConstructorArgs($this->getMocks()) - ->onlyMethods(['createMessage', 'to']) - ->getMock(); - $mailer->setQueue($queueFake); - $mailable = new MailableQueueableStub; - $queueFake->assertNothingPushed(); - $mailer->send($mailable); - $queueFake->assertPushedOn(null, SendQueuedMailable::class); + return [ + ['some-queue'], + [null], + ]; + } + + #[DataProvider('defaultQueueDataProvider')] + public function testDefaultQueue($queue): void + { + try { + if ($queue) { + Mailable::$defaultQueue = $queue; + } + + $queueFake = new QueueFake(new Application); + $mailer = $this->getMockBuilder(Mailer::class) + ->setConstructorArgs($this->getMocks()) + ->onlyMethods(['createMessage', 'to']) + ->getMock(); + $mailer->setQueue($queueFake); + $mailable = new MailableQueueableStub; + $queueFake->assertNothingPushed(); + $mailer->send($mailable); + $queueFake->assertPushedOn($queue, SendQueuedMailable::class); + } finally { + Mailable::$defaultQueue = null; + } } public function testQueuedMailableWithAttachmentSent(): void diff --git a/tests/Notifications/NotificationSenderTest.php b/tests/Notifications/NotificationSenderTest.php index 3221a87145c2..a258cc6c5ec6 100644 --- a/tests/Notifications/NotificationSenderTest.php +++ b/tests/Notifications/NotificationSenderTest.php @@ -14,6 +14,7 @@ use Illuminate\Notifications\Notification; use Illuminate\Notifications\NotificationSender; use Mockery as m; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; use Symfony\Component\Mailer\Exception\HttpTransportException; use Symfony\Component\Mailer\Exception\TransportException; @@ -166,6 +167,51 @@ public function testNotificationFailedSentWithoutHttpTransportException() $sender->sendNow($notifiable, new DummyNotificationWithViaConnections(), ['mail']); } + + public static function defaultNotificationQueueDataProvider() + { + return [ + ['some-queue'], + [null], + ]; + } + + #[DataProvider('defaultNotificationQueueDataProvider')] + public function testDefaultNotificationQueue($queue) + { + try { + if ($queue) { + Notification::$defaultQueue = $queue; + } + + $notifiable = new NotifiableUser; + $manager = m::mock(ChannelManager::class); + $manager->shouldReceive('getContainer')->andReturn(app()); + + $dispatchedJob = null; + $bus = m::mock(BusDispatcher::class); + $bus->shouldReceive('dispatch') + ->once() + ->withArgs(function ($job) use ($queue, &$dispatchedJob) { + $dispatchedJob = $job; + + return $job->queue === $queue; + }); + + $events = m::mock(EventDispatcher::class); + $events->shouldReceive('listen')->once(); + + $sender = new NotificationSender($manager, $bus, $events); + + $notification = new DummyNotificationWithMiddleware; + + $sender->send($notifiable, $notification); + + $this->assertSame($queue, $dispatchedJob->queue); + } finally { + Notification::$defaultQueue = null; + } + } } class DummyQueuedNotificationWithStringVia extends Notification implements ShouldQueue