Как я могу переопределить методы Laravel Facade?

Я хочу переопределить метод отправки фасада классов Laravel Mail (просто перехватите его, выполнив некоторые проверки, а затем, если он пройдет, вызовет parent::send())

Как лучше всего это сделать?


person naneri    schedule 22.09.2016    source источник
comment
Вы не должны заставлять Mailer выполнять проверки, это не его работа, он просто отправляет почту. Логика должна выполняться снаружи, и если почта должна отправляться, вызывать метод send.   -  person tam5    schedule 23.09.2016
comment
@tam Вы говорите о ремонтопригодности и структуре, и я знаю, что лучше не возлагать ответственность на почтовую программу. Но вопрос не в этом.   -  person naneri    schedule 23.09.2016


Ответы (1)


Фасад так не работает. По сути, это что-то вроде класса-оболочки, который вызывает базовый класс, который он представляет.

Фасад Mail на самом деле не имеет метода send. Когда вы выполняете Mail::send(), под капотом "аксессор фасада" используется для ссылки на экземпляр класса Illuminate\Mail\Mailer, привязанный к контейнеру IoC. Именно на этом объекте вызывается метод send.

Способ, которым вы можете достичь того, что вам нужно, на самом деле немного сложнее, чем кажется. Что вы можете сделать, это:

  • Напишите собственную реализацию Mailer, расширяющую Illuminate\Mail\Mailer, в которой вы можете переопределить метод send, реализовать свои проверки и вызвать parent::send().
  • Напишите свой собственный поставщик услуг (расширение Illuminate\Mail\MailServiceProvider), в частности повторно реализуйте метод register. Он должен создать ваш собственный экземпляр Mailer вместо собственного экземпляра Laravel. (Вы можете скопировать большую часть кода из метода register Laravel).
  • Теперь в вашем файле config/app.php в массиве providers замените Illuminate\Mail\MailServiceProvider::class, на вашего собственного провайдера.

Это должно позволить вам подключиться к функциональности Laravel Mail.


Для получения дополнительной информации вы можете взглянуть на следующий вопрос/ответ, который достигает аналогичного результата. Он расширяет функциональные возможности Mail, добавляя новый транспортный драйвер, но использует аналогичный подход в том смысле, что предоставляет собственную реализацию Mailer и поставщика услуг.

Добавить новый транспортный драйвер в Mailer Laravel


приложение/MyMailer/Mailer.php

<?php

namespace App\MyMailer;

class Mailer extends \Illuminate\Mail\Mailer
{
    public function send($view, array $data = [], $callback = null)
    {
        // Do your checks

        return parent::send($view, $data, $callback);
    }
}

app/MyMailer/MailServiceProvider.php (большая часть кода скопирована из класса Laravel MailServiceProvider)

<?php

namespace App\MyMailer;

class MailServiceProvider extends \Illuminate\Mail\MailServiceProvider
{
    public function register()
    {
        $this->registerSwiftMailer();

        $this->app->singleton('mailer', function ($app) {
            // This is YOUR mailer - notice there are no `use`s at the top which
            // Looks for a Mailer class in this namespace
            $mailer = new Mailer(
                $app['view'], $app['swift.mailer'], $app['events']
            );

            $this->setMailerDependencies($mailer, $app);


            $from = $app['config']['mail.from'];

            if (is_array($from) && isset($from['address'])) {
                $mailer->alwaysFrom($from['address'], $from['name']);
            }

            $to = $app['config']['mail.to'];

            if (is_array($to) && isset($to['address'])) {
                $mailer->alwaysTo($to['address'], $to['name']);
            }

            return $mailer;
        });
    }
}

config/app.php (в массиве поставщиков)

//...
// Illuminate\Mail\MailServiceProvider::class,
App\MyMailer\MailServiceProvider::class,
//...
person Jonathon    schedule 22.09.2016
comment
Как я могу получить письмо из обратного вызова? - person naneri; 22.09.2016
comment
Что ты имеешь в виду? - person Jonathon; 23.09.2016