Blok 3 · rozdział 8
Modele, relacje, seeder
Model to klasa PHP, która odpowiada tabeli. Zamiast sklejać SQL w kontrolerze,
piszesz Szczyt::where(...). Seeder wstawia 28 szczytów z pliku kursowego,
więc cała grupa ma te same dane.
Po tym rozdziale powinieneś umieć
- utworzyć modele
PasmoiSzczytoraz ustawić$fillablei$table; - opisać
hasManyibelongsTo; - załadować listę Korony seederem;
- sprawdzić liczbę rekordów w Tinkerze i w phpMyAdmin.
1. Model Eloquent
php artisan make:model Pasmo
php artisan make:model Szczyt
app/Models/Pasmo.php:
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
class Pasmo extends Model
{
protected $table = 'pasma';
protected $fillable = ['nazwa', 'slug'];
public function szczyty(): HasMany
{
return $this->hasMany(Szczyt::class);
}
}
app/Models/Szczyt.php:
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class Szczyt extends Model
{
protected $table = 'szczyty';
protected $fillable = ['pasmo_id', 'nazwa', 'slug', 'wysokosc_m', 'opis'];
public function pasmo(): BelongsTo
{
return $this->belongsTo(Pasmo::class);
}
}
Szczyt::find(1) czyta rekord, $szczyt->nazwa czyta kolumnę.
$table i $fillable
Laravel od klasy Szczyt zgadłby tabelę szczyts. Dlatego nazwa jest jawna.
$fillable to lista kolumn, które wolno ustawić hurtowo (create, update).
Bez niej masowe przypisanie jest blokowane — to ochrona przed tym, że ktoś dopisze do formularza pole id albo cudze uprawnienie.
2. Relacja 1:N
Pasmo hasMany Szczyt
$pasmo->szczyty — kolekcja szczytów tego pasma.
1 : N
Szczyt belongsTo Pasmo
$szczyt->pasmo — jedno pasmo. W bazie stoi pasmo_id.
Na liście Korony każde pasmo ma dokładnie jeden szczyt, ale w schemacie związek jest 1:N.
Metoda hasMany mówi, że pasmo może mieć wiele szczytów. Nie jest to jedna kolumna w tabeli pasm.
3. Seeder Korony
- Utwórz katalog
database/seeders/data. - Skopiuj tam plik kursu
materialy/korona.php(zostaw nazwękorona.php). - Wygeneruj seeder:
php artisan make:seeder KoronaSeeder.
namespace Database\Seeders;
use App\Models\Pasmo;
use App\Models\Szczyt;
use Illuminate\Database\Seeder;
use Illuminate\Support\Str;
class KoronaSeeder extends Seeder
{
public function run(): void
{
$wiersze = require database_path('seeders/data/korona.php');
foreach ($wiersze as $wiersz) {
$pasmo = Pasmo::query()->firstOrCreate(
['slug' => Str::slug($wiersz['pasmo'])],
['nazwa' => $wiersz['pasmo']],
);
Szczyt::query()->updateOrCreate(
['slug' => Str::slug($wiersz['nazwa'])],
[
'pasmo_id' => $pasmo->id,
'nazwa' => $wiersz['nazwa'],
'wysokosc_m' => $wiersz['wysokosc'],
],
);
}
}
}
W database/seeders/DatabaseSeeder.php w metodzie run zostaw wywołanie:
$this->call(KoronaSeeder::class);
php artisan db:seed
Str::slug('Śnieżka') daje sniezka, Str::slug('Góry Świętokrzyskie') daje gory-swietokrzyskie.
firstOrCreate nie dubluje pasma przy drugim uruchomieniu.
updateOrCreate poprawia wysokość, jeśli odpalisz seeder jeszcze raz.
php artisan migrate:fresh --seed.
To kasuje wszystkie tabele tej bazy i stawia je ponownie. Nie rób tego później na bazie, w której są już konta kolegów, jeśli ich potrzebujesz.
4. Tinker i phpMyAdmin
php artisan tinker
Szczyt::count();
Szczyt::query()->orderByDesc('wysokosc_m')->first()->nazwa;
Pasmo::count();
Wyjście z Tinkera: exit. W phpMyAdmin tabela szczyty ma mieć 28 wierszy,
a pasma tyle, ile różnych pasm w pliku (też 28 — po jednym szczycie na pasmo).
Szczyt::count() kończy się zapytaniem SELECT COUNT(*).
Eloquent nie zastępuje bazy. Układa zapytanie za Ciebie i oddaje obiekty.
Gdy coś nie gra, w phpMyAdmin nadal możesz odpalić SELECT i porównać wynik.
Gdy Szczyt::count() zwraca 28:
git add .
git status
git commit -m "Modele i seeder Korony"
Przed commitem git status nie pokazuje .env.