Отправка почты по событию
Пусть у нас есть форма обратной связи на сайте. После отправки сообщения происходит отправка письма с данными этой формы. Но вместо того, чтобы просто отправить письмо, мы возбудим событие, перехватим его в слушателе и только после этого отправим письмо. Смысла в этом особого нет, сделано с целью изучения Laravel.
Контроллер
Создаем контроллер FeedbackController
:
php artisan make:controller FeedbackController
app/Http/Controllers/FeedbackController.php<?php
namespace App\Http\Controllers;
use stdClass;
use App\Mail\FeedbackMailer;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Mail;
class FeedbackController extends Controller {
// Выводим форму на странице
public function index() {
return view('feedback.index');
}
// Отправляем данные формы на почту
public function send(Request $request) {
// Валидация полей формы
$request->validate([
'name' => 'required|max:100',
'email' => 'required|email|max:100',
'message' => 'required|max:500',
]);
// Создаем динамический объект
$data = new stdClass();
// Данные из поля формы name
$data->name = $request->name;
// Данные из поля формы email
$data->email = $request->email;
// Данные из поля формы message
$data->message = $request->message;
// В метод Mail::to первым аргументом передаем почту куда будет отправка письма, вторым методом передаем класс отправки почты в который передаем аргументом объект с данными формы $data который попадет в конструктор класса FeedbackMailer
//Mail::to($data->email)->send(new FeedbackMailer($data));
// Вместо отправки письма возбуждаем событие
event(new FeedbackMailEvent($data));
// Редирект через имя роута на ту же страницу с формой
return redirect()->route('feedback.index')
// Вывод сообщения
->with('success', 'Ваше сообщение успешно отправлено');
}
}
Роуты
Добавляем два маршрута:
routes/web.phpRoute::get('/feedback', [FeedbackController::class, 'index'])->name('feedback.index');
Route::post('/feedback', [FeedbackController::class, 'send'])->name('feedback.send');
Форма связи
Создаем шаблон:
resources/views/feedback/index.blade.php@extends('layouts.app')
@section('content')
<h1>Обратная связь</h1>
@if (session('success'))
<div class="alert alert-success" role="alert">
{{ session('success') }}
</div>
@endif
@if ($errors->any())
<div class="alert alert-danger" role="alert">
<ul>
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
<form method="post" action="{{ route('feedback.send') }}">
@csrf
<div class="form-group">
<input type="text" class="form-control" name="name" placeholder="Имя, фамилия"
required maxlength="100" value="{{ old('name') ?? '' }}">
</div>
<div class="form-group">
<input type="email" class="form-control" name="email" placeholder="Адрес почты"
required maxlength="100" value="{{ old('email') ?? '' }}">
</div>
<div class="form-group">
<textarea class="form-control" name="message" placeholder="Ваше сообщение"
required maxlength="500" rows="3">{{ old('message') ?? '' }}</textarea>
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary">Отправить</button>
</div>
</form>
@endsection
Шаблон почтового сообщения
Нам потребуется шаблон для письма:
resources/views/email/feedback.blade.php<h1>Форма обратной связи</h1>
<p><strong>Имя:</strong> {{ $data->name }}</p>
<p><strong>Почта:</strong> {{ $data->email }}</p>
<p><strong>Сообщение:</strong> {{ $data->message }}</p>
Класс отправки почты
В Laravel каждый тип почтового сообщения (обратная связь, заказ в магазине), отправляемых приложением, представлен классом Mailable
. Эти классы хранятся в директории app/Mail
, которая будет создана при создании первого такого класса.
Создаем класс:
php artisan make:mail FeedbackMailer
Заполняем класс:
app/Mail/FeedbackMailer.php<?php
namespace App\Mail;
use Illuminate\Support\Facades\Storage;
use stdClass;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
class FeedbackMailer extends Mailable {
use Queueable, SerializesModels;
// Публичная переменная в которую запишем переданные данные формы из контроллера FeedbackController
public $data;
// Плучаем данные формы из контроллера FeedbackController
public function __construct(stdClass $feedback) {
$this->data = $feedback;
}
// Создаем сообщение
public function build() {
// От кого письмо
return $this->from('noreply@aurora.com', 'ООО ТД АВРОРА')
// Тема письма
->subject('Форма обратной связи')
// Вызываем представление и передаем объект data с данными
->view('email.feedback', ['data' => $this->data]);
}
}
Класс события
Создаем событие с помощью artisan-команды:
php artisan make:event FeedbackMailEvent
App/Events/FeedbackMailEvent.php<?php
// Событие FeedbackMailEvent
namespace App\Events;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class FeedbackMailEvent
{
use Dispatchable, InteractsWithSockets, SerializesModels;
// Создайте новый экземпляр события @return void
public function __construct($data)
{
$this->data = $data;
}
// Определите каналы, по которым должно транслироваться мероприятие @return \Illuminate\Broadcasting\Channel|array
public function broadcastOn()
{
return [];
}
}
Обработчик события
Создаем обработчика события с помощью artisan-команды:
php artisan make:listener FeedbackMailListener --event="FeedbackMailEvent"
App/Listeners/FeedbackMailListener.php<?php
// Обработчик события
namespace App\Listeners;
use App\Events\FeedbackMailEvent;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use App\Mail\FeedbackMailer;
use Illuminate\Support\Facades\Mail;
class FeedbackMailListener
{
// Создайте прослушиватель событий @return void
public function __construct()
{
//
}
// Обработайте событие @return void @param \App\Events\FeedbackMailEvent $event
public function handle(FeedbackMailEvent $event)
{
// обрабатываем событие, то есть отправляем письмо
Mail::to($event->data->email)->send(new FeedbackMailer($event->data));
}
}
Слушатель события
Открываем на редактирование файл класса EventServiceProvider
:
App/Providers/EventServiceProvider.php<?php
// Регистрируем слушателя события
namespace App\Providers;
use Illuminate\Auth\Events\Registered;
use Illuminate\Auth\Listeners\SendEmailVerificationNotification;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Event;
class EventServiceProvider extends ServiceProvider
{
// Сопоставления события с прослушивателем для приложения @var array<class-string, array<int, class-string>>
protected $listen = [
Registered::class => [
SendEmailVerificationNotification::class,
],
// Класс события при отправке формы
FeedbackMailEvent::class => [
// Класс обработчика события
FeedbackMailListener::class,
]
];
// Регистрируйте любые события для вашего приложения @return void
public function boot()
{
parent::boot();
}
// Определите, должны ли события и прослушиватели обнаруживаться автоматически @return bool
public function shouldDiscoverEvents()
{
return true;
}
}