
Спостерігачі моделей в Laravel
13.07.2018 19:35 | Laravel
Відразу до практики - подивимося де і як можна використовувати спостерігачів.
Отже, припустимо у нас є модель категорій з декількома властивостями:
- назвою
title
- так званим
slug
- псевдонімом для url, тобто адреса у браузері буде виглядати якmysite.com/categories/laravel
, деlaravel
- і є той самий псевдонім - булевим
published
, яке вказує, чи опублікована дана категорія
Якщо всі поля прописані у формах створення нової та оновлення існуючої категорій, то відповідні методи в моєму контролері виглядали б приблизно так:
class CategoryController extends Controller
{
public function store(Request $request)
{
$category = Category::create($request->only($this->getEditableColumns()));
...
}
public function update(Request $request, Category $category)
{
$category->update($request->only($this->getEditableColumns()));
...
}
protected function getEditableColumns()
{
return ['title', 'slug', 'published', 'sort_order'];
}
}
(валідацію в даному випадку опускаю, ну а якщо є бажання, на цю тему є окрема стаття)
Та річ в тому, що slug
- це всього-навсього приведена до нижнього регістру назву категорії, в якій підчищені "ліві" символи, а пробіли та підкреслення замінені дефісами. Тому не бачу сенсу додавати в форму поле пседовніма, і тим більше, змушувати користувачів думати, як його заповнювати. І все ж якимось чином псевдоніму треба присвоїти значення - ось і проблема, яку допоможуть вирішити спостерігачі.
Для початку за допомогою консолі створимо спостерігача і відразу зазначимо модель, події якої треба прослуховувати:
$ php artisan make:observer CategoryObserver --model=Category
Результатом є каталог project/app/Observers
, в якому розміщений файл CategoryObserver.php
з потрібним класом. Тепер ми хочемо присвоїти значення псевдоніму до того, как модель будет сохранена или обновлена. як модель буде збережена або оновлена. Можна, звичайно, було б відразу тупо прописати методи creating()
і updating()
. Але ми ж люди розумні, а тому заглянемо в доки, де зможемо прочитати, що як у випадку збереження, так і в разі поновлення будуть ініційовані події saving/saved
. Нас цікавить тільки перша. Редагуємо код створеного файлу:
<?php
namespace App\Observers;
use App\Category;
class CategoryObserver
{
public function saving(Category $category)
{
$category->slug = str_slug($category->title);
}
}
Нагадаю, str_slug() - це функція-хелпер в Laravel, яка з рядка робить пседовнім. Причому не проблема, якщо рядок буде українською - кирилиця буде перетворена на латиницю.
Залишилося зареєструвати спостерігача. Для цього можна створити окремого постачальника послуг, але зараз обійдемося без нього - пропишемо необхідний код у AppServiceProvider
:
<?php
namespace App\Providers;
use App\Category;
use App\Observers\CategoryObserver;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
public function boot()
{
Category::observe(CategoryObserver::class);
}
...
}
Бум! Проблема вирішена.
Однак рано говорити стоп, зачепимо ще поле published
. Припустимо, що це чекбокс, а як ми знаємо, якщо чекбокс не зазначено, то і у реквесті його не буде. Іншими словами, якщо категорія опублікована, а ми захочемо зняти її з публікації і під час редагування форми приберемо галочку з чекбокса - поле в базі даних не оновиться. Є різні методи боротьби з цим явищем, як, наприклад, створення в формі прихованого поля і т.д. Але оскільки у нас вже є спостерігач, нехай попрацює і тут. Повернемося до методу saving()
, і хоча "кожен такий метод отримує модель в якості єдиного аргументу", нас це не злякає - дістанемо реквест і там:
<?php
namespace App\Observers;
use App\Category;
class CategoryObserver
{
public function saving(Category $category)
{
$category->slug = str_slug($category->title);
$category->live = request()->published ? true : false;
}
}
Готово.
Так, приклад простий, але все ж - мінімум коду - і все працює, як годинник. Лаконічно і зрозуміло, як і завжди в Laravel.