这个逻辑非常长,先扔结论,写在这里:
\vendor\laravel\framework\src\Illuminate\Notifications\Channels\DatabaseChannel.php
public function send($notifiable, Notification $notification)
{
return $notifiable->routeNotificationFor('database', $notification)->create(
$this->buildPayload($notifiable, $notification)
);
}
简要分析:
假如从app\Observers\ReplyObserver.php开始
public function created(Reply $reply)
{
$reply->topic->reply_count = $reply->topic->replies->count();
$reply->topic->save();
// 通知话题作者
$reply->topic->user->notify(new TopicReplied($reply));
}
notify方法位于vendor\laravel\framework\src\Illuminate\Notifications\RoutesNotifications.php
public function notify($instance)
{
app(Dispatcher::class)->send($this, $instance);
}
接着,send方法位于\vendor\laravel\framework\src\Illuminate\Notifications\ChannelManager.php
public function send($notifiables, $notification)
{
return (new NotificationSender(
$this, $this->container->make(Bus::class), $this->container->make(Dispatcher::class), $this->locale)
)->send($notifiables, $notification);
}
这里面的send又位于\vendor\laravel\framework\src\Illuminate\Notifications\NotificationSender.php
public function send($notifiables, $notification)
{
$notifiables = $this->formatNotifiables($notifiables);
if ($notification instanceof ShouldQueue) {
return $this->queueNotification($notifiables, $notification);
}
return $this->sendNow($notifiables, $notification);
}
关键看sendNow,位于vendor\laravel\framework\src\Illuminate\Notifications\NotificationSender.php
public function sendNow($notifiables, $notification, array $channels = null)
{
$notifiables = $this->formatNotifiables($notifiables);
$original = clone $notification;
foreach ($notifiables as $notifiable) {
if (empty($viaChannels = $channels ?: $notification->via($notifiable))) {
continue;
}
$this->withLocale($this->preferredLocale($notifiable, $notification), function () use ($viaChannels, $notifiable, $original) {
$notificationId = Str::uuid()->toString();
foreach ((array) $viaChannels as $channel) {
$this->sendToNotifiable($notifiable, $notificationId, clone $original, $channel);
}
});
}
}
注意到via
方法,获取到的是通知类里面定义的,位于app\Notifications\TopicReplied.php
public function via($notifiable)
{
return ['database', 'mail'];
}
所以通知的频道包含有database,将会存数据到notifications表。
接着关注sendToNotifiable
方法,
protected function sendToNotifiable($notifiable, $id, $notification, $channel)
{
if (! $notification->id) {
$notification->id = $id;
}
if (! $this->shouldSendNotification($notifiable, $notification, $channel)) {
return;
}
$response = $this->manager->driver($channel)->send($notifiable, $notification);
$this->events->dispatch(
new Events\NotificationSent($notifiable, $notification, $channel, $response)
);
}
存数据到数据库的动作包含在send方法中,而$channel是database的时候,send方法则是vendor\laravel\framework\src\Illuminate\Notifications\Channels\DatabaseChannel.php中的send方法:
public function send($notifiable, Notification $notification)
{
return $notifiable->routeNotificationFor('database', $notification)->create(
$this->buildPayload($notifiable, $notification)
);
}
这就到达开头的结论。展开来,routeNotificationFor
方法在\vendor\laravel\framework\src\Illuminate\Notifications\RoutesNotifications.php中:
public function routeNotificationFor($driver, $notification = null)
{
if (method_exists($this, $method = 'routeNotificationFor'.Str::studly($driver))) {
return $this->{$method}($notification);
}
switch ($driver) {
case 'database':
return $this->notifications(); //<--
case 'mail':
return $this->email;
}
}
因为User模型和Notification是多态关系,其关联定义在:vendor\laravel\framework\src\Illuminate\Notifications\HasDatabaseNotifications.php中:
public function notifications()
{
return $this->morphMany(DatabaseNotification::class, 'notifiable')->orderBy('created_at', 'desc');
}
所以,上面的send,大概操作就是:$user->notifications()->create($data)
,即把通知数据存到数据库中。
这个逻辑非常长,先扔结论,写在这里:
\vendor\laravel\framework\src\Illuminate\Notifications\Channels\DatabaseChannel.php
public function send($notifiable, Notification $notification)
{
return $notifiable->routeNotificationFor('database', $notification)->create(
$this->buildPayload($notifiable, $notification)
);
}
简要分析:
假如从app\Observers\ReplyObserver.php开始
public function created(Reply $reply)
{
$reply->topic->reply_count = $reply->topic->replies->count();
$reply->topic->save();
// 通知话题作者
$reply->topic->user->notify(new TopicReplied($reply));
}
notify方法位于vendor\laravel\framework\src\Illuminate\Notifications\RoutesNotifications.php
public function notify($instance)
{
app(Dispatcher::class)->send($this, $instance);
}
接着,send方法位于\vendor\laravel\framework\src\Illuminate\Notifications\ChannelManager.php
public function send($notifiables, $notification)
{
return (new NotificationSender(
$this, $this->container->make(Bus::class), $this->container->make(Dispatcher::class), $this->locale)
)->send($notifiables, $notification);
}
这里面的send又位于\vendor\laravel\framework\src\Illuminate\Notifications\NotificationSender.php
public function send($notifiables, $notification)
{
$notifiables = $this->formatNotifiables($notifiables);
if ($notification instanceof ShouldQueue) {
return $this->queueNotification($notifiables, $notification);
}
return $this->sendNow($notifiables, $notification);
}
关键看sendNow,位于vendor\laravel\framework\src\Illuminate\Notifications\NotificationSender.php
public function sendNow($notifiables, $notification, array $channels = null)
{
$notifiables = $this->formatNotifiables($notifiables);
$original = clone $notification;
foreach ($notifiables as $notifiable) {
if (empty($viaChannels = $channels ?: $notification->via($notifiable))) {
continue;
}
$this->withLocale($this->preferredLocale($notifiable, $notification), function () use ($viaChannels, $notifiable, $original) {
$notificationId = Str::uuid()->toString();
foreach ((array) $viaChannels as $channel) {
$this->sendToNotifiable($notifiable, $notificationId, clone $original, $channel);
}
});
}
}
注意到via
方法,获取到的是通知类里面定义的,位于app\Notifications\TopicReplied.php
public function via($notifiable)
{
return ['database', 'mail'];
}
所以通知的频道包含有database,将会存数据到notifications表。
接着关注sendToNotifiable
方法,
protected function sendToNotifiable($notifiable, $id, $notification, $channel)
{
if (! $notification->id) {
$notification->id = $id;
}
if (! $this->shouldSendNotification($notifiable, $notification, $channel)) {
return;
}
$response = $this->manager->driver($channel)->send($notifiable, $notification);
$this->events->dispatch(
new Events\NotificationSent($notifiable, $notification, $channel, $response)
);
}
存数据到数据库的动作包含在send方法中,而$channel是database的时候,send方法则是vendor\laravel\framework\src\Illuminate\Notifications\Channels\DatabaseChannel.php中的send方法:
public function send($notifiable, Notification $notification)
{
return $notifiable->routeNotificationFor('database', $notification)->create(
$this->buildPayload($notifiable, $notification)
);
}
这就到达开头的结论。展开来,routeNotificationFor
方法在\vendor\laravel\framework\src\Illuminate\Notifications\RoutesNotifications.php中:
public function routeNotificationFor($driver, $notification = null)
{
if (method_exists($this, $method = 'routeNotificationFor'.Str::studly($driver))) {
return $this->{$method}($notification);
}
switch ($driver) {
case 'database':
return $this->notifications(); //<--
case 'mail':
return $this->email;
}
}
因为User模型和Notification是多态关系,其关联定义在:vendor\laravel\framework\src\Illuminate\Notifications\HasDatabaseNotifications.php中:
public function notifications()
{
return $this->morphMany(DatabaseNotification::class, 'notifiable')->orderBy('created_at', 'desc');
}
所以,上面的send,大概操作就是:$user->notifications()->create($data)
,即把通知数据存到数据库中。
推荐文章: