Файл: vendor/laravel/framework/src/Illuminate/Notifications/NotificationSender.php
Строк: 591
<?php
namespace IlluminateNotifications;
use IlluminateContractsQueueShouldQueue;
use IlluminateContractsTranslationHasLocalePreference;
use IlluminateDatabaseEloquentCollection as EloquentCollection;
use IlluminateDatabaseEloquentModel;
use IlluminateNotificationsEventsNotificationFailed;
use IlluminateNotificationsEventsNotificationSending;
use IlluminateNotificationsEventsNotificationSent;
use IlluminateQueueAttributesConnection;
use IlluminateQueueAttributesDelay;
use IlluminateQueueAttributesQueue as QueueAttribute;
use IlluminateQueueAttributesReadsQueueAttributes;
use IlluminateSupportCollection;
use IlluminateSupportStr;
use IlluminateSupportTraitsLocalizable;
use SymfonyComponentMailerExceptionHttpTransportException;
use SymfonyComponentMailerExceptionTransportException;
use Throwable;
class NotificationSender
{
use Localizable, ReadsQueueAttributes;
/**
* The notification manager instance.
*
* @var IlluminateNotificationsChannelManager
*/
protected $manager;
/**
* The Bus dispatcher instance.
*
* @var IlluminateContractsBusDispatcher
*/
protected $bus;
/**
* The event dispatcher.
*
* @var IlluminateContractsEventsDispatcher
*/
protected $events;
/**
* The locale to be used when sending notifications.
*
* @var string|null
*/
protected $locale;
/**
* Indicates whether a NotificationFailed event has been dispatched.
*
* @var bool
*/
protected $failedEventWasDispatched = false;
/**
* Create a new notification sender instance.
*
* @param IlluminateNotificationsChannelManager $manager
* @param IlluminateContractsBusDispatcher $bus
* @param IlluminateContractsEventsDispatcher $events
* @param string|null $locale
*/
public function __construct($manager, $bus, $events, $locale = null)
{
$this->bus = $bus;
$this->events = $events;
$this->locale = $locale;
$this->manager = $manager;
$this->events->listen(NotificationFailed::class, fn () => $this->failedEventWasDispatched = true);
}
/**
* Send the given notification to the given notifiable entities.
*
* @param IlluminateSupportCollection|mixed $notifiables
* @param mixed $notification
* @return void
*/
public function send($notifiables, $notification)
{
if ($notification instanceof ShouldQueue) {
return $this->queueNotification($notifiables, $notification);
}
$this->sendNow($notifiables, $notification);
}
/**
* Send the given notification immediately.
*
* @param IlluminateSupportCollection|mixed $notifiables
* @param mixed $notification
* @param array|null $channels
* @return void
*/
public function sendNow($notifiables, $notification, ?array $channels = null)
{
$notifiables = $this->formatNotifiables($notifiables);
$original = clone $notification;
foreach ($notifiables as $notifiable) {
if (empty($viaChannels = $channels ?: $original->via($notifiable))) {
continue;
}
$this->withLocale($this->preferredLocale($notifiable, $original), function () use ($viaChannels, $notifiable, $original) {
$notificationId = (string) Str::uuid();
foreach ((array) $viaChannels as $channel) {
if (! ($notifiable instanceof AnonymousNotifiable && $channel === 'database')) {
$this->sendToNotifiable($notifiable, $notificationId, clone $original, $channel);
}
}
});
}
}
/**
* Get the notifiable's preferred locale for the notification.
*
* @param mixed $notifiable
* @param mixed $notification
* @return string|null
*/
protected function preferredLocale($notifiable, $notification)
{
return $notification->locale ?? $this->locale ?? value(function () use ($notifiable) {
if ($notifiable instanceof HasLocalePreference) {
return $notifiable->preferredLocale();
}
});
}
/**
* Send the given notification to the given notifiable via a channel.
*
* @param mixed $notifiable
* @param string $id
* @param mixed $notification
* @param string $channel
* @return void
*
* @throws Throwable
*/
protected function sendToNotifiable($notifiable, $id, $notification, $channel)
{
if (! $notification->id) {
$notification->id = $id;
}
if (! $this->shouldSendNotification($notifiable, $notification, $channel)) {
return;
}
try {
$response = $this->manager->driver($channel)->send($notifiable, $notification);
} catch (Throwable $exception) {
if (! $this->failedEventWasDispatched) {
if ($exception instanceof HttpTransportException) {
$exception = new TransportException($exception->getMessage(), $exception->getCode());
}
$this->events->dispatch(
new NotificationFailed($notifiable, $notification, $channel, ['exception' => $exception])
);
}
$this->failedEventWasDispatched = false;
throw $exception;
}
if (method_exists($notification, 'afterSending')) {
$notification->afterSending($notifiable, $channel, $response);
}
$this->events->dispatch(
new NotificationSent($notifiable, $notification, $channel, $response)
);
}
/**
* Determines if the notification can be sent.
*
* @param mixed $notifiable
* @param mixed $notification
* @param string $channel
* @return bool
*/
protected function shouldSendNotification($notifiable, $notification, $channel)
{
if (method_exists($notification, 'shouldSend') &&
$notification->shouldSend($notifiable, $channel) === false) {
return false;
}
return $this->events->until(
new NotificationSending($notifiable, $notification, $channel)
) !== false;
}
/**
* Queue the given notification instances.
*
* @param mixed $notifiables
* @param IlluminateNotificationsNotification $notification
* @return void
*/
protected function queueNotification($notifiables, $notification)
{
$notifiables = $this->formatNotifiables($notifiables);
$original = clone $notification;
foreach ($notifiables as $notifiable) {
$notificationId = (string) Str::uuid();
foreach ((array) $original->via($notifiable) as $channel) {
$notification = clone $original;
if (! $notification->id) {
$notification->id = $notificationId;
}
if (! is_null($this->locale)) {
$notification->locale = $this->locale;
}
$connection = $this->getAttributeValue($notification, Connection::class, 'connection')
?? $this->manager->resolveConnectionFromQueueRoute($notification)
?? null;
if (method_exists($notification, 'viaConnections')) {
$connection = $notification->viaConnections()[$channel] ?? $connection;
}
$queue = $this->getAttributeValue($notification, QueueAttribute::class, 'queue')
?? $this->manager->resolveQueueFromQueueRoute($notification)
?? null;
if (method_exists($notification, 'viaQueues')) {
$queue = $notification->viaQueues()[$channel] ?? $queue;
}
$delay = method_exists($notification, 'withDelay')
? ($notification->withDelay($notifiable, $channel) ?? null)
: $this->getAttributeValue($notification, Delay::class, 'delay');
$messageGroup = $notification->messageGroup ?? (method_exists($notification, 'messageGroup') ? $notification->messageGroup() : null);
if (method_exists($notification, 'withMessageGroups')) {
$messageGroup = $notification->withMessageGroups($notifiable, $channel) ?? null;
}
$deduplicator = $notification->deduplicator ?? (method_exists($notification, 'deduplicationId') ? $notification->deduplicationId(...) : null);
if (method_exists($notification, 'withDeduplicators')) {
$deduplicator = $notification->withDeduplicators($notifiable, $channel) ?? null;
}
$middleware = $notification->middleware ?? [];
if (method_exists($notification, 'middleware')) {
$middleware = array_merge(
$notification->middleware($notifiable, $channel),
$middleware
);
}
$this->bus->dispatch(
$this->manager->getContainer()->make(SendQueuedNotifications::class, [
'notifiables' => $notifiable,
'notification' => $notification,
'channels' => [$channel],
])
->onConnection($connection)
->onQueue($queue)
->delay(is_array($delay) ? ($delay[$channel] ?? null) : $delay)
->onGroup(is_array($messageGroup) ? ($messageGroup[$channel] ?? null) : $messageGroup)
->withDeduplicator(is_array($deduplicator) ? ($deduplicator[$channel] ?? null) : $deduplicator)
->through($middleware)
);
}
}
}
/**
* Format the notifiables into a Collection / array if necessary.
*
* @param mixed $notifiables
* @return IlluminateDatabaseEloquentCollection|array
*/
protected function formatNotifiables($notifiables)
{
if (! $notifiables instanceof Collection && ! is_array($notifiables)) {
return $notifiables instanceof Model
? new EloquentCollection([$notifiables])
: [$notifiables];
}
return $notifiables;
}
}