小滕的博客

小滕的技术点滴

lumen引入laravel的notification

2 months ago · 3 MIN READ

Lumen的性能要高出laravel一大截,很大一部分原因是因为加载的文件变少了,少了非常多,但是正因为少了很多文件,功能方面也就丢失了很多,所以如果需要用到laravel的一些功能,还需要自己集成进去,今天就来演示下如何集成laravel的notification。lumne本身是不带有这个的。

首先,看下我的lumen版本:

Laravel Framework Lumen (5.6.4) (Laravel Components 5.6.*)

按照lumen的版本,我们来安装下对应的 notification 扩展包:

composer require illuminate/notifications=5.6.*

安装成功之后,接下来就是安装,首先我们需要 config 目录下面创建几个文件:

main.php

<?php

return [

    /*
    |--------------------------------------------------------------------------
    | Mail Driver
    |--------------------------------------------------------------------------
    |
    | Laravel supports both SMTP and PHP's "mail" function as drivers for the
    | sending of e-mail. You may specify which one you're using throughout
    | your application here. By default, Laravel is setup for SMTP mail.
    |
    | Supported: "smtp", "sendmail", "mailgun", "mandrill", "ses",
    |            "sparkpost", "log", "array"
    |
    */

    'driver' => env('MAIL_DRIVER', 'log'),

    /*
    |--------------------------------------------------------------------------
    | SMTP Host Address
    |--------------------------------------------------------------------------
    |
    | Here you may provide the host address of the SMTP server used by your
    | applications. A default option is provided that is compatible with
    | the Mailgun mail service which will provide reliable deliveries.
    |
    */

    'host' => env('MAIL_HOST', 'smtp.mailgun.org'),

    /*
    |--------------------------------------------------------------------------
    | SMTP Host Port
    |--------------------------------------------------------------------------
    |
    | This is the SMTP port used by your application to deliver e-mails to
    | users of the application. Like the host we have set this value to
    | stay compatible with the Mailgun e-mail application by default.
    |
    */

    'port' => env('MAIL_PORT', 587),

    /*
    |--------------------------------------------------------------------------
    | Global "From" Address
    |--------------------------------------------------------------------------
    |
    | You may wish for all e-mails sent by your application to be sent from
    | the same address. Here, you may specify a name and address that is
    | used globally for all e-mails that are sent by your application.
    |
    */

    'from' => [
        'address' => env('MAIL_FROM_ADDRESS', 'hello@example.com'),
        'name' => env('MAIL_FROM_NAME', 'Example'),
    ],

    /*
    |--------------------------------------------------------------------------
    | E-Mail Encryption Protocol
    |--------------------------------------------------------------------------
    |
    | Here you may specify the encryption protocol that should be used when
    | the application send e-mail messages. A sensible default using the
    | transport layer security protocol should provide great security.
    |
    */

    'encryption' => env('MAIL_ENCRYPTION', 'tls'),

    /*
    |--------------------------------------------------------------------------
    | SMTP Server Username
    |--------------------------------------------------------------------------
    |
    | If your SMTP server requires a username for authentication, you should
    | set it here. This will get used to authenticate with your server on
    | connection. You may also set the "password" value below this one.
    |
    */

    'username' => env('MAIL_USERNAME'),

    'password' => env('MAIL_PASSWORD'),

    /*
    |--------------------------------------------------------------------------
    | Sendmail System Path
    |--------------------------------------------------------------------------
    |
    | When using the "sendmail" driver to send e-mails, we will need to know
    | the path to where Sendmail lives on this server. A default path has
    | been provided here, which will work well on most of your systems.
    |
    */

    'sendmail' => '/usr/sbin/sendmail -bs',

    /*
    |--------------------------------------------------------------------------
    | Markdown Mail Settings
    |--------------------------------------------------------------------------
    |
    | If you are using Markdown based email rendering, you may configure your
    | theme and component paths here, allowing you to customize the design
    | of the emails. Or, you may simply stick with the Laravel defaults!
    |
    */

    'markdown' => [
        'theme' => 'default',

        'paths' => [
            resource_path('views/vendor/mail'),
        ],
    ],

];

view.php

<?php

return [

    /*
    |--------------------------------------------------------------------------
    | View Storage Paths
    |--------------------------------------------------------------------------
    |
    | Most templating systems load templates from disk. Here you may specify
    | an array of paths that should be checked for your views. Of course
    | the usual Laravel view path has already been registered for you.
    |
    */

    'paths' => [
        resource_path('views'),
    ],

    /*
    |--------------------------------------------------------------------------
    | Compiled View Path
    |--------------------------------------------------------------------------
    |
    | This option determines where all the compiled Blade templates will be
    | stored for your application. Typically, this is within the storage
    | directory. However, as usual, you are free to change this value.
    |
    */

    'compiled' => realpath(storage_path('framework/views')),

];

其中 mail.php 用于邮件发送的配置,notification是有邮件通知的,所以邮件配置是必须得,另外 view.php 的配置是 laravel 的模板引擎的,这里的邮件发送需要 blade 模板,所以也需要配置下这个,另外的话需要在 .env 文件中增加:

#MAIN
MAIL_DRIVER=log
MAIL_HOST=
MAIL_PORT=
MAIL_FROM_ADDRESS=
MAIL_FROM_NAME=
MAIL_ENCRYPTION=null
MAIL_USERNAME=
MAIL_PASSWORD=

到这里,文件配置好了,接下来,我们需要加载这些配置文件,这里需要注意的是 lumen 的配置文件不是自动加载的,而需要自己配置,所以我们需要在 bootstrap/app.php 文件中配置:

$app->configure('mail');
$app->configure('view');

之后,我们需要加载这些服务,所以还是需要在 bootstrap/app.php 中配置相关的服务注册:

$app->configure('mail');
$app->configure('view');

$app->register(\Illuminate\Mail\MailServiceProvider::class);
$app->register(\Illuminate\View\ViewServiceProvider::class);
$app->register(\Illuminate\Notifications\NotificationServiceProvider::class);

其中的 NotificationServiceProvider 服务肯定是需要的,MailServiceProviderViewServiceProvider 是依赖的服务,也需要加载进去,否则影响功能的使用,到这里我们基本上就配置完成了,接下来我们写个命令测试下:

<?php
/**
 * Created by PhpStorm.
 * User: apple
 * Date: 2019-01-14
 * Time: 17:29
 */

namespace App\Console\Commands;

use App\Models\User\User;
use App\Notifications\TestNotification;
use Illuminate\Console\Command;

class TestCommand extends Command
{

    protected $signature = 'test';

    public function __construct() {
        parent::__construct();
    }

    public function handle() {
        $user = User::find(34);
        $user->notify(new TestNotification());
    }
}

然后在 Console/Kernel.php 中注册:

protected $commands = [
        TestCommand::class,
    ];

然后执行:

pangu git:(notification) php artisan test

In Container.php line 933:

  Target [Illuminate\Contracts\Mail\Mailer] is not instantiable while buildin
  g [Illuminate\Notifications\Channels\MailChannel].

可以看到,报错,提示说 Mailer 没有实例化,我们看下 Illuminate\Notifications\Channels\MailChannel 的代码,可以看到它的初始化函数:

public function __construct(Mailer $mailer, Markdown $markdown)
    {
        $this->mailer = $mailer;
        $this->markdown = $markdown;
    }

它依赖 Mailer 的实例,但是在容器创建的时候却并没有 Mailer 的实例给它,因为是邮件服务,我们来下 MailServiceProvider ,其中的:

protected function registerIlluminateMailer()
    {
        $this->app->singleton('mailer', function ($app) {
            $config = $app->make('config')->get('mail');

            // Once we have create the mailer instance, we will set a container instance
            // on the mailer. This allows us to resolve mailer classes via containers
            // for maximum testability on said classes instead of passing Closures.
            $mailer = new Mailer(
                $app['view'], $app['swift.mailer'], $app['events']
            );

            if ($app->bound('queue')) {
                $mailer->setQueue($app['queue']);
            }

            // Next we will set all of the global addresses on this mailer, which allows
            // for easy unification of all "from" addresses as well as easy debugging
            // of sent messages since they get be sent into a single email address.
            foreach (['from', 'reply_to', 'to'] as $type) {
                $this->setGlobalAddress($mailer, $config, $type);
            }

            return $mailer;
        });
    }

这个方法其实已经完成了 Mailer 的实例化,但是为什么上面提示没有 Mailer 实例呢?是这样的,这里的注册时给 Mailer 一个别名 mailer ,它并没有与 Illuminate\Contracts\Mail\Mailer 产生关联,所以在我们用 Illuminate\Contracts\Mail\Mailer 的接口去要求容器传入一个接口的实现的时候,就会出现问题,所以这里还需要我们自己绑定下,我们可以在 AppServiceProvider 中注册下:

        // Mailer实例化
        $app->alias('mailer', Mailer::class);

这样,我们在执行下:

php artisan test

成功,无报错,打开 lumen.log,可以看到:

[2019-03-20 11:41:06] local.DEBUG: Message-ID: <9f872f9fd6788d9ed349a8f1b9e526df@swift.generated>
Date: Wed, 20 Mar 2019 11:41:06 +0800
Subject: test mail title.
From: 
To: dawnkeyan@126.com
MIME-Version: 1.0
Content-Type: text/html; charset=utf-8
Content-Transfer-Encoding: quoted-printable

haha  

通知成功发出去了,到此,notification 基本已经集成到lumen当中。

···

xiao teng



备案号:皖ICP备14012032号-5