
Czym jest Eloquent ORM?
Eloquent ORM jest dostarczany razem z frameworkiem Laravel, żeby dać prosty i bezproblemowy sposób pracy z bazą danych. Funkcje, które przyniosły mu rozgłos, to soft delete, timestampy, implementacja Active Record, obsługa wielu baz danych, eager loading, obserwatory modeli, zdarzenia modeli i wiele innych. Relacje Eloquenta to zwykłe metody klas modeli. Zdefiniowane jako metody, stają się potężnymi konstruktorami zapytań: można na nich łańcuchowo wywoływać kolejne metody i budować naprawdę mocne zapytania.
Jak działa Eloquent ORM?
Eloquent ORM zasłynął implementacją wzorca Active Record do pracy z bazami danych. Active Record to wzorzec architektoniczny, w którym każdy model architektury MVC odpowiada jednej tabeli w bazie. Dzięki Eloquentowi łatwo tworzysz powiązane dane i pracujesz z nimi obiektowo. Ręczne pisanie zapytań SQL jest żmudne i pochłania mnóstwo czasu, a Laravel Eloquent pozwala wykonywać typowe operacje na bazie bez długich zapytań. Modele bardzo ułatwiły wstawianie, aktualizowanie, usuwanie i synchronizowanie wielu baz danych. Wystarczy zdefiniować tabele i relacje między nimi, i po robocie.
Pierwsze kroki z Eloquentem
Laravel ma wbudowany interfejs wiersza poleceń o nazwie Artisan Console. Napędza go komponent Console z Symfony, dzięki czemu wygodnie korzysta się z linii poleceń w trakcie budowania aplikacji.
Zanim pójdziemy dalej, skonfiguruj połączenie z bazą danych w pliku config/database.php.
Zanim zaczniesz korzystać z modelu Eloquent, sprawdź, czy masz zainstalowanego Laravela. Jeśli nie, pobierzesz go z getcomposer.org
Żeby zobaczyć listę poleceń dostępnych w Artisanie, uruchom:
php artisan listNa ekranie pojawią się wszystkie polecenia z krótkim opisem. Jeśli potrzebujesz pomocy do któregoś z nich, wpisz je poprzedzone słowem „help”. Na przykład:
php artisan help migrateTworzenie modeli Eloquent
Zanim zrobisz cokolwiek innego, potrzebujesz modelu dla swojej tabeli. Modele przydają się przy seedowaniu, fabrykach i całej reszcie. To model rozmawia z bazą danych: pozwala odpytywać tabele i wypełniać je danymi. Modele trzyma się zwykle w App\Models i chodzi wyłącznie o porządek w kodzie. My też wolimy tę konwencję, ale wybór należy do ciebie, jedyny warunek to autoloading klasy zgodny z plikiem composer.json. Każdy model Eloquent rozszerza klasę Illuminate\Database\Eloquent\Model. Podstawowe polecenie do tworzenia modeli to polecenie Artisana `make:model` :
php artisan make: model StudentPodstawowa składnia definicji modelu wygląda tak:
class User extends Model {}Migrację można wygenerować razem z modelem, dopisując do poprzedniego polecenia `-m` albo `–migration`.
php artisan make:model Student--migration
php artisan make:model Flight -mSeedery, fabryki, kontrolery i inne klasy generuje się, przekazując odpowiednie opcje do polecenia `make:model` . Kilka przykładów:
php artisan make:model Flight --factory
php artisan make:model Flight -f
php artisan make:model Flight --seed
php artisan make:model Flight -s
php artisan make:model Flight --controller
php artisan make:model Flight -cTe opcje można też łączyć, żeby utworzyć kilka klas naraz.
php artisan make:model Flight -mfscKilka podstawowych konwencji modeli, o których warto pamiętać:
- Nazwa tabeli: zgodnie z konwencją nazwy tabel zapisuje się małymi literami i w liczbie mnogiej, w każdej bazie danych. Jeśli model nazywa się Student, tabela powinna nazywać się students. Kiedy nazwa modelu składa się z kilku słów, rozdziel je podkreśleniem.
- Klucz główny: Eloquent zakłada, że kluczem głównym jest atrybut id. Możesz to nadpisać właściwością `$primaryKey`.
- Timestampy: domyślnie `created_at` i `updated_at` są obsługiwane automatycznie przez Eloquenta. Jeśli wolisz zająć się nimi sam, ustaw `$timestamps` na false. A żeby zmienić format daty i godziny, użyj w modelu właściwości `$dateFormat`.
Aktualizowanie i usuwanie rekordów
Aktualizowanie
Żeby zaktualizować model, pobierz go, zmień wybrany atrybut i wywołaj metodę save. Kolumna `updated_at` aktualizuje się sama, więc nie musisz jej ruszać ręcznie.
$student = Student::find(1);
$student->email = ‘xyz@example.com';
$student>save();Aktualizacje masowe da się wykonać na wszystkich modelach pasujących do danego zapytania.
Usuwanie istniejącego modelu
Żeby usunąć model, wystarczy wywołać metodę delete:
$student = Student::find(1);
$student>delete();Usuwanie po kluczu:
Student::destroy(1);
Student::destroy([1, 2, 3]);
Student::destroy(1, 2, 3);Usuwać można również na podstawie zapytania.
$affectedRows = Student::where('votes', '>', 100)->delete();Powiązane modele
W każdej bazie danych mogą istnieć powiązane modele. Kiedy dwa modele albo więcej zależą od siebie wartościami, mówimy o modelach powiązanych. Na przykład dodając nowy komentarz do wpisu, zamiast ręcznie ustawiać post_id możesz zapisać komentarz prosto z modelu nadrzędnego
$comment = new Comment(['message' => 'A new comment.']);
$post = Post::find(1);
$comment = $post->comments()->save($comment);Wiązanie modeli
Modele aktualizuje się też metodą associate, która ustawia na modelu klucz obcy. W ten sposób da się wiązać modele w kilku relacjach naraz.
Zdarzenia modelu
Za każdym razem, gdy chcesz wpiąć się w etapy cyklu życia modelu, zapis, aktualizację czy usunięcie, wywoływane jest zdarzenie modelu. Dostępne zdarzenia to saving, saved, deleting, deleted, updating, updated, restoring i restored. Wstawienie nowego rekordu uruchamia zdarzenie creating/created, a rekord, który już istnieje, uruchamia updating/updated.
Anulowanie zapisu ze zdarzenia
Jeśli zdarzenie zwróci false, akcja zostanie anulowana. Zadziała to z dowolnym zdarzeniem: deleting, updating, creating i tak dalej.
Student::creating(function($student)
{
if ( ! $student>isValid()) return false;
});Jak rejestrować listenery zdarzeń
Jak w każdym języku, zdarzenie potrzebuje service providera, żeby dało się je zarejestrować, i z listenerami jest tak samo. Laravel dostarcza EventServiceProvider i to tam rejestruje się powiązania zdarzeń modeli.
Na przykład:
public function boot(DispatcherContract $events)
{
parent::boot($events);
Student::creating(function($student)
{
//
});
}Obserwatory modelu
Obserwatory modeli pomagają obsłużyć zdarzenia modeli. Klasa obserwatora może mieć po jednej metodzie na każde zdarzenie.
class StudentObserver {
public function saving($model)
{
//
}
public function saved($model)
{
//
}
}Obserwator rejestruje się także metodą observe
User::observe(new UserObserver);Generowanie adresów URL modelu
Adresy URL modelu dają adres pojedynczego rekordu: wystarczy przekazać model do helpera route albo action. Kiedy model trafia do route lub action, w URI wstawiany jest jego klucz główny.
Route::get('student/{student}', 'StudentController@show');
action('StudentController@show', [$student]);Tutaj w adresie znajdzie się id studenta. Jeśli w wygenerowanym adresie ma się pojawić inna właściwość, nadpisz metodę getRouteKey w swoim modelu.
public function getRouteKey()
{
return $this->slug;
}Więcej o funkcjach Laravel Eloquent
Konwersja na tablice i JSON
Kiedy budujesz API, odpowiedź prawie zawsze jest w JSON-ie, więc modele i ich relacje trzeba zamienić na JSON albo tablicę. Laravel Eloquent obsługuje i to. Żeby zamienić model wraz z relacjami na tablicę, użyj metody toArray().
$student = Student::with('roles')->first();
return $student->toArray();Żeby zamienić na tablicę całą kolekcję modeli, można użyć takich metod:
return Student::find(1)->toJson();Zobaczmy teraz, jak zwrócić model z trasy. Model rzutowany na łańcuch znaków zamienia się w JSON, więc obiekty Eloquenta możesz zwracać prosto z tras.
Route::get('student', function()
{
return Student::all();
});Część wartości, jak `personal_id` czy hasło, trzeba ukryć. Dodaj w tym celu do modelu `$hidden`.
Rzutowanie atrybutów
Jeśli chcesz zmienić typ danych atrybutu, jedną z opcji jest napisanie mutatora dla każdego z nich, co zajmuje czas i sprzyja błędom. Druga opcja to rzutowanie danego atrybutu: dopisz go do właściwości casts swojego modelu. Pozostałe akceptowane typy rzutowania to integer, float, double, real, object, string, array.
Oto przykład.
protected $casts = [
'is_student' => 'boolean',
];W tym przykładzie, mimo że is_student jest przechowywana z innym typem danych, przy odczycie zawsze dostaniesz boolean.
Rzutowanie na tablicę bardzo się przydaje przy kolumnie zawierającej serializowany JSON. Serializowany JSON to po prostu obiekt zakodowany jako łańcuch znaków. Jeśli któraś z kolumn go trzyma, rzutowanie na tablicę zamieni ją automatycznie w tablicę PHP, gdy tylko odczytasz ją z modelu Eloquent.
protected $casts = [
'options' => 'array',
];Mutatory dat
Carbon to międzynarodowe rozszerzenie klasy DateTime z PHP. Eloquent zamienia created_at i updated_at na instancje Carbona, które rozszerzają klasę DateTime i dokładają kilka przydatnych metod. Jeśli nie chcesz automatycznej mutacji, dostosowanie jest proste: nadpisz w swojej klasie metodę getDates . Żeby wyłączyć mutację dat całkowicie, zwróć pustą tablicę z metody `getDates` . Oto przykład:
public function getDates()
{
return ['created_at'];
}Kiedy kolumna jest traktowana jak data, jej wartością mogą być cztery rzeczy: timestamp UNIX, łańcuch z datą (Y-m-d), łańcuch z datą i godziną albo instancja DateTime/Carbon.
Akcesory i mutatory
Podobnie jak odczyt i zapis wartości w dowolnym języku, akcesory i mutatory pozwalają formatować atrybuty Eloquenta, zanim zostaną odczytane z instancji modelu albo do niej zapisane. Różnica jest taka, że akcesory służą do odczytu danych, a mutatory odpowiadają za ich zmianę.
Żeby zdefiniować akcesor, zadeklaruj w modelu metodę `getFooAttribute` , jej nazwa musi być zapisana w camelCase, nawet jeśli kolumna jest zapisana małymi literami.
class User extends Model {
public function getFirstNameAttribute($value)
{
return ucfirst($value);
}
}Mutator definiuje się tak samo: użyj `setFooAttribute` i tak, camelCase obowiązuje również tutaj.
class User extends Model {
public function setFirstNameAttribute($value)
{
$this->attributes['first_name'] = strtolower($value);
}
}Soft delete
Soft delete nie usuwa wiersza z bazy, tylko zapisuje osobny timestamp. Na rekordzie wypełniana jest kolumna `deleted_at` . Soft delete włączasz w modelu, dodając do niego trait SoftDeletes.
use Illuminate\Database\Eloquent\SoftDeletes;
class User extends Model {
use SoftDeletes;
protected $dates = ['deleted_at'];
}softDeletes() dodaje w migracji kolumnę deleted_at. Migracja to nic innego niż zarządzanie bazą danych w PHP zamiast w SQL-u.
$table->softDeletes();Czasem chcesz, żeby rekordy usunięte miękko pojawiły się w wynikach zapytania. Wystarczy dodać withTrashed() do zapytania.
Jeśli w wynikach mają się znaleźć wyłącznie modele usunięte miękko, użyj onlyTrashed() w zapytaniu.
$student = Student::onlyTrashed()->where('account_id', 1)->get();Po tych wszystkich operacjach, jeśli chcesz przywrócić modele usunięte miękko do aktywnego użycia, wywołaj metodę restore.
$student->restore();restore() można też wywołać bezpośrednio w zapytaniu.
Student::withTrashed()->where('account_id', 1)->restore();Teraz, po miękkim usunięciu, jeśli chcesz skasować model z bazy na dobre, użyj forceDelete() na modelu.
$student->posts()->forceDelete();Żeby sprawdzić, czy model został usunięty, sięgnij po metodę trashed().
if ($student->trashed())
{
//Do zrobienia
}Podsumowanie
Laravel to jeden z najbardziej znanych frameworków PHP, a Laravel Eloquent daje bardzo prosty sposób rozmawiania z bazami danych. W tym artykule omówiłem część ważnych funkcji Eloquenta. Jest ich znacznie więcej i poczytasz o nich tutaj. Wejdź na ten link i sprawdź wszystko, co potrafi Laravel Eloquent.


