Sprawdzamy istnienie relacji w modelu na kilku przykładach, kontynuacja lekcji poprzednich. Staramy się wyrobić w korzystaniu z baz danych w Laravelu.
Ok, pierwsze podejście:
Artisan::command('person-has-note {id}', function (int $id) {
$person = Person::withCount('notes')->findOrFail($id);
$this->comment($person->notes_count ? 'true' : 'false');
});
Jak to działa – wyjaśniam:
- metoda withCount zwraca w result secie pole notes_count zawierające ilość relacji notes
- gdy ta ilość jest równa 0 to 0 jako falsy value psuje warunek i mamy false
Inny, bardziej toporny przykład:
Artisan::command('person-has-note2 {id}', function (int $id) {
$person = Person::with('notes')->findOrFail($id);
$this->comment($person->notes()->count() ? 'true' : 'false');
});
Jak to działa:
- Tutaj nie ładujemy kolumny notes_count
- Za pomocą with „ochoczo” ładujemy (eager loading) wszystkie notatki (czego w sumie nie potrzebujemy) jako kolekcję
- Zwracany wynik ma kolekcję notes, która jak każda kolekcja ma metodę count
Ok, ciekawsze podejście:
Artisan::command('person-has-note3 {id}', function (int $id) {
$person = Person::withExists('notes')->findOrFail($id);
$this->comment($person->notes_exists ? 'true' : 'false');
});
Wyjaśnienie:
- tutaj nie ładujemy ani kolekcji notes ani pola notes_count, jesteśmy tak oszczędni, jak to możliwe
- za pomocą metody withExists ładujemy pole notes_exists, które zawiera prawdę lub fałsz
Ok, zróbmy jeszcze ćwiczenie z fasadą DB:
Artisan::command('person-has-note4 {id}', function (int $id) {
$sql = DB::table('notes')
->select("id")
->where('person_id', $id)
->count();
$this->comment($sql);
});
Jak widać działa i nawet DB raw nie potrzebowaliśmy. Już tłumaczę dlaczego. Zamieńmy count na toSql i sprawdźmy:
select `id`
from `notes`
where `person_id` = ?
I tylko tyle. Dostajemy kolekcję z numerami id, pod warunkiem że w polu person_id (które nie jest zaciągane) person_id jest równe temu przekazanemu do funkcji.
Dalej metoda ->count() sprawdza, ile wyników dostaliśmy. Ale my chcielibyśmy coś takiego:
SELECT count(*) FROM `notes` WHERE person_id = 1;
I takie coś zwraca:
COUNT(*)
7
Czyli jedna kolumna, jeden rekord, nie jedna kolumna ID i 7 rekordów przekazywanych do Collection tylko po to, by wywołać ->count().
Ok, możemy zrobić to tak:
Artisan::command('person-has-note5 {id}', function (int $id) {
$sql = DB::table('notes')
->select(DB::raw('COUNT(*) as cnt'))
->where('person_id', $id)
->toSql();
$this->comment($sql);
});
//select COUNT(*) as cnt from `notes` where `person_id` = ?
Musimy tylko pamiętać, że ->get() zwróci nam Collection. Ona będzie miała items, które są protected, więc musimy pokombinować z toArray:
Artisan::command('person-has-note5 {id}', function (int $id) {
$sql = DB::table('notes')
->select(DB::raw('COUNT(*) as cnt'))
->where('person_id', $id)
->get();
$this->comment($sql->toArray()[0]->cnt);
});
//7
Mam nadzieję, że jesteśmy na takim poziomie, że to co tu teraz piszę w ogóle nas nie przeraża.