
Вступ
Якщо у вас є кілька моделей у Laravel з одним nullable-полем, створення мутатора для цього поля — процес доволі тривіальний:
public function setNicknameAttribute($nickname)
{
$this->attributes['nickname'] = trim($nickname) == '' ? null : trim($nickname);
}
Тут ми перевіряємо вхідні дані, у цьому випадку — $nickname, на порожнечу. Якщо$nickname порожнє, то ми встановлюємо атрибуту значення null, інакше — trim($nickname).
Чому я використовую trim замість empty? Функція trim прибирає пробільні символи з початку та кінця рядка, а порівняння результату її виконання з порожнім рядком перевіряє, чи справді вхідні дані порожні. Це дає нам змогу переконатися в тому, що ніхто не намагається вставити в базу даних порожній рядок. А empty вважає будь-яку кількість пробільних символів непорожнім рядком.
Але за наявності кількох моделей із полями такого типу в базі даних з’являється дублювання коду; у кожній такій моделі потрібно встановлювати мутатор перевірки на порожнечу. Чи справді це — найкращий спосіб дій? Я бачу два способи прибрати дублювання коду в цьому випадку, і кожен із них залежить від вашого оточення (сервера).
Використання базової моделі
Якщо у вас є кілька методів у Laravel із повторюваною логікою в моделях, ви можете винести її (цю логіку) в базову модель, від якої інші моделі будуть розширюватися. Це корисно, якщо в кожній вашій моделі буде використовуватися метод nullIfEmpty (у нашому випадку). Але розширення моделі без використання її методів може додавати непотрібне додаткове споживання ресурсів.
<?php namespace App;
use IlluminateDatabaseEloquentModel;
class BaseModel extends Model {
public function __construct(array $attributes = array())
{
parent::__construct($attributes);
}
protected function nullIfEmpty($input)
{
return trim($input) == '' ? null : trim($input);
}
}
Функція nullIfEmpty буде доступна в кожній моделі, що розширює BaseModel:
<?php namespace App;
class UserModel extends BaseModel {
public function setNicknameAttribute($nickname)
{
$this->attributes['nickname'] = $this->nullIfEmpty($nickname);
}
}
Цей спосіб працює, але не одразу зрозуміло, звідки приходить метод nullIfEmpty. Потрібен певний час, щоб з’ясувати, звідки він з’явився. Проте цю незрозумілість можна уникнути.
Але для тих, у кого версія PHP < 5.4.0, цей спосіб, мабуть, буде єдиним.
Використання трейтов
Якщо ви використовуєте версію PHP >= 5.4.0, трейти допоможуть вам красивим декларативним способом додати потрібну функціональність у модель.
<?php namespace AppTraits;
trait NullableFields {
protected function nullIfEmpty($input)
{
return trim($input) == '' ? null : trim($input);
}
}
Цей трейт можна використовувати в моделі так:
<?php namespace App;
use AppTraitsNullableFields;
use IlluminateDatabaseEloquentModel;
class UserModel extends Model {
use NullableFields;
public function setNicknameAttribute($nickname)
{
$this->attributes['nickname'] = $this->nullIfEmpty($nickname);
}
}
Висновок
Особисто я не вважаю, що якийсь із методів швидший; також обидва прості у використанні. Тому вибір у будь-якому разі за вами. Використання трейтов у Laravel більш декларативне, адже ви бачите NullableFields одразу в класі, і вам не потрібно шукати, звідки прийшов метод.
Але, на мою думку, використання трейтов більш бажане, тому що ви не завантажуєте базову модель методами обробки вхідних даних або будь-якими іншими методами, які безпосередньо до неї не належать. Перевантажувати клас — не найкраща ідея.