
Wstęp
Jeśli masz w Laravel kilka modeli z jednym polem nullable, tworzenie mutatora dla tego pola jest procesem dość trywialnym:
public function setNicknameAttribute($nickname)
{
$this->attributes['nickname'] = trim($nickname) == '' ? null : trim($nickname);
}
Tutaj sprawdzamy dane wejściowe, w tym przypadku $nickname, pod kątem pustki. Jeśli$nickname jest puste, to ustawiamy atrybutowi wartość null, w przeciwnym razie — trim($nickname).
Dlaczego używam trim zamiast empty? Funkcja trim usuwa znaki białe z początku i końca ciągu, a porównanie wyniku jej działania z pustym ciągiem pozwala sprawdzić, czy dane wejściowe są rzeczywiście puste. Dzięki temu możemy upewnić się, że nikt nie próbuje wstawić do bazy danych pustego ciągu. A empty uznaje dowolną liczbę znaków białych za niepusty ciąg.
Jednak przy kilku modelach z polami tego typu w bazie danych pojawia się duplikacja kodu; w każdym takim modelu trzeba ustawiać mutator sprawdzający pustkę. Czy to rzeczywiście najlepszy sposób działania? Widzę dwa sposoby usunięcia duplikacji kodu w tym przypadku, a wybór zależy od Twojego środowiska (serwera).
Użycie modelu bazowego
Jeśli masz w Laravel kilka metod z powtarzalną logiką w modelach, możesz przenieść ją (tę logikę) do modelu bazowego, z którego będą rozszerzane pozostałe modele. Jest to przydatne, jeśli w każdym z Twoich modeli będzie wykorzystywana metoda nullIfEmpty (w naszym przypadku). Jednak rozszerzanie modelu bez używania jego metod może powodować niepotrzebne dodatkowe zużycie zasobów.
<?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);
}
}
Funkcja nullIfEmpty będzie dostępna w każdym modelu rozszerzającym BaseModel:
<?php namespace App;
class UserModel extends BaseModel {
public function setNicknameAttribute($nickname)
{
$this->attributes['nickname'] = $this->nullIfEmpty($nickname);
}
}
Ten sposób działa, ale nie od razu jest jasne, skąd pochodzi metoda nullIfEmpty. Potrzeba trochę czasu, aby ustalić, skąd się wzięła. Mimo to tę niejasność można uniknąć.
Jednak dla osób, które mają wersję PHP < 5.4.0, ten sposób prawdopodobnie będzie jedynym.
Użycie traitów
Jeśli używasz wersji PHP >= 5.4.0, traity pomogą Ci w elegancki, deklaratywny sposób dodać do modelu potrzebną funkcjonalność.
<?php namespace AppTraits;
trait NullableFields {
protected function nullIfEmpty($input)
{
return trim($input) == '' ? null : trim($input);
}
}
Tego traitu można użyć w modelu w następujący sposób:
<?php namespace App;
use AppTraitsNullableFields;
use IlluminateDatabaseEloquentModel;
class UserModel extends Model {
use NullableFields;
public function setNicknameAttribute($nickname)
{
$this->attributes['nickname'] = $this->nullIfEmpty($nickname);
}
}
Wnioski
Osobiście nie uważam, aby którykolwiek z tych metod był szybszy; obie są też proste w użyciu. Dlatego wybór w każdym przypadku należy do Ciebie. Użycie traitów w Laravel jest bardziej deklaratywne, ponieważ od razu widzisz NullableFields w klasie i nie musisz szukać, skąd przyszedł dany metod.
Ale moim zdaniem użycie traitów jest bardziej preferowane, ponieważ nie obciążasz modelu metodami do obsługi danych wejściowych ani żadnymi innymi metodami, które nie mają z nim bezpośredniego związku. Przeciążanie klasy to nie najlepszy pomysł.