请问下,notifications 表中的数据写入逻辑在哪里呢

小白在 代码中找不到这一部分流程。。

《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
最佳答案

这个逻辑非常长,先扔结论,写在这里:
\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),即把通知数据存到数据库中。

4年前 评论
nightlostk (楼主) 4年前
讨论数量: 1

这个逻辑非常长,先扔结论,写在这里:
\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),即把通知数据存到数据库中。

4年前 评论
nightlostk (楼主) 4年前

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!