Наблюдатели за событиями Eloquent
Наблюдатели предоставляют механизм, который позволяет контролировать каждый процесс, происходящий с базой данных. Список событий, которые можно использовать при работе с базой данных, можно посмотреть в трейте HasEvents
.
booting
, booted
, creating
, created
, updating
, updated
, deleting
, deleted
, saving
, saved
, restoring
, restored
. На каждую операцию с моделью предусмотрено 2 события. Например, при создании объекта модели сработает 2 события — creating
и created
. Первое срабатывает перед операцией добавления, второе после. Этот принцип распространяется на каждую операцию. Причём, если при обработке первого события вернуть false
, то операция отменяется.
vendor/laravel/framework/src/illuminate/database/eloquent/concerns/HasEvents.php<?php
namespace Illuminate\Database\Eloquent\Concerns;
use Illuminate\Contracts\Events\Dispatcher;
use Illuminate\Events\NullDispatcher;
use Illuminate\Support\Arr;
use InvalidArgumentException;
trait HasEvents {
public function getObservableEvents() {
return array_merge(
[
'retrieved', 'creating', 'created', 'updating', 'updated',
'saving', 'saved', 'restoring', 'restored', 'replicating',
'deleting', 'deleted', 'forceDeleted',
],
$this->observables
);
}
}
Создадим нового поставщика услуг:
php artisan make:provider EloquentEventServiceProvider
App/Providers/EloquentEventServiceProvider.php<?php
namespace App\Providers;
use App\Models\Page;
use Illuminate\Support\ServiceProvider;
class EloquentEventServiceProvider extends ServiceProvider {
// Регистрируйте услуги @return void
public function register() {
// ...
}
// Сервисы начальной загрузки @return void
public function boot() {
Page::creating(function ($page) {
$page->name = $page->name . ' (создана ' . auth()->user()->name . ')';
});
}
}
Добавим нового поставщика услуг в config/app.php
:
config/app.phpreturn [
'providers' => [
App\Providers\EloquentEventServiceProvider::class,
]
]
Теперь перед добавлением новой страницы в базу данных к ее названию добавляется имя автора, который ее создал.
Наблюдать за множеством событий
Если нужно наблюдать за множеством событий для разных моделей (Page
, Post
, Category
), то неудобно, что все они будут в методе boot()
сервис-провайдера EloquentEventServiceProvider
. Давайте создадим отдельную директорию app/Observers
и разместим в ней файл класса PageObserver.php
:
app/Observers/PageObserver.php<?php
namespace App\Observers;
use App\Models\Page;
class PageObserver {
// Срабатывает перед записью новой страницы
public function creating(Page $page) {
$page->name = 'Перед созданием, ' . $page->name;
}
// Срабатывает при извлечении из базы данных
public function retrieved(Page $page) {
$page->name = 'При извлечении, ' . $page->name;
}
// Срабатывает перед удалением страницы из БД
public function deleting(Page $page) {
return false;
}
}
В сервис-провайдере уже не будем обрабатывать события, а только укажем класс, который будет это делать. Другими словами — зарегистрируем наблюдателя за событиями модели Page
:
App/Providers/EloquentEventServiceProvider.phpnamespace App\Providers;
use App\Models\Page;
use App\Observers\PageObserver;
use Illuminate\Support\ServiceProvider;
class EloquentEventServiceProvider extends ServiceProvider {
/**
* Register services.
*
* @return void
*/
public function register() {
// ...
}
/**
* Bootstrap services.
*
* @return void
*/
public function boot() {
Page::observe(PageObserver::class);
}
}
Поскольку метод deleting()
возвращает false
— страницу теперь вообще нельзя удалить.
Наблюдатели работают с предопределенными событиями, которые происходят только в Eloquent Models (создание записи, обновление записи, удаление и т.д.). События создает сам разработчик, они не определены заранее и могут использоваться где угодно, а не только в моделях. Поэтому мы разместили класс PageObserver
в отдельной директории app/Observers
, а не в директории app/Listeners
.