A legutóbbi komplex példával foglalkozó blogbejegyzésben javasoltam,
hogy készítsünk egy légitársaság (airline) Model osztályt, migrációs
fájllal és a hozzá tartozó gyárral együtt.
php artisan make:model Airline -mf
Azt
írtam, hogy a légitársaságnak bármennyi járata lehet, de egy
repülőjárat pontosan egy légitársasághoz tartozik. Mit mond nekünk ez a
mondat? Értelmezzük! Az első felében az új Airline nevű osztályunkra
utalunk, aminek lesz egy flights() metódusa és benne a hasMany()
visszatérési értékkel, míg a már meglévő Flight Model osztályunkban lesz
egy airline() metódus és benne a belongsTo() visszatérési érték. Ha még
nem tettük volna meg, akkor készítsük el ezeket. Kezdjük az Airline
osztállyal:
public function flights()
{
return $this->hasMany(Flight::class);
}
Majd folytassuk a Flight osztály bővítésével:
public function airline()
{
return $this->belongsTo(Airline::class);
}
Az airline migrációs fájljában plusz oszlopként csak a szokás nevet (name) tároljuk el az id-n és a timestaps mezőkön kívül:
$table->string('name');
Hajtsuk végre a migrálást:
php artisan migrate
Mivel
ez egy "1-n"-es vagy "n-1"-es kapcsolat, attól függően, honnan nézzük
(az "n" jelenti a "több"-et), ezért a tényleges kapcsolatot egy idegen
kulcson keresztül kell megvalósítani. Az idegen kulcsot az "1"-es
oldalra kell létrehozni, azaz jelen esetben a repülőjáratok táblát kell
bővíteni egy airline_id mezővel és külső kulcs hivatkozással (mindig használjuk a már megszerzett tudásunkat!). Új migrációs fájl létrehozása:
php artisan make:migration add_airline_id_to_flights_table
Ebbe
az új migrációs fájlba pedig az up metódusban lévő Schema::table()
metódus magjába helyezzük el a külső kulcsos mező és a hivatkozás
létrehozását (ha frissítjük vagy töröljük a légitársaságot, akkor a
hozzá kapcsolódó repülőjáratok is frissülnek vagy törlődnek):
$table->unsignedBigInteger('airline_id')->after('captain_id')->nullable();
$table->foreign('airline_id')->references('id')->on('airlines')->onDelete('cascade')->onUpdate('cascade');
(Megjegyzés:
kipróbáltam az előző bejegyzésben javasolt kulcslétrehozást, de mivel
az airlines táblában még nincsenek légitársaságok, ezért hibát adott a
migráció során, viszont így a nullable módosító hozzáadásával működött.)
Ez volt tehát az up() metódusban, de most figyelnünk kell már a down
metódusra is, hiszen bármikor előfordulhat, hogy vissza szeretnénk lépni
a migrációs folyamatban. Itt most már viszont nem lenne elég a sima
oszlop eldobás, mivel ez egy külső hivatkozás.
$table->dropForeign('flights_airline_id_foreign');
$table->dropColumn('airline_id');
Fontos a sorrend, mert előbb a külső kulcs hivatkozást kell törölni, majd utána lehet csak magát az oszlopot is törölni.
Hajtsuk végre a migrálást:
php artisan migrate
Ezután
létre szeretnénk hozni légitársaságokat, hogy majd a repülőjáratokat
hozzájuk tudjuk rendelni. Ehhez viszont a Flight és Airline Model-eket
is bővítenünk kell, méghozzá a $fillable mezőjüket. Kezdjük az Airline
Model osztállyal:
protected $fillable = ['name'];
A Flight osztályban már megvan a $fillable mező, így abban csak a tömböt bővítsük a 'airline_id' mezővel.
protected $fillable = ['number', 'name', 'price'
, 'captain_id', 'airline_id'];
Ezután indíthatjuk a Tinker-t, hogy fel tudjunk vinni új elemeket és akár a régi repülőjáratokat is frissíthetjük.
php artisan tinker
App\Models\Airline::create(['name'=>'Malev']);
App\Models\Airline::create(['name'=>'Turul']);
Ezzel
létrehoztunk két légitársaságot. Most a meglévő három repülőjáratomat
hozzárendelem ezekhez. Az elsőt az első légitársasághoz, a
második-harmadikat pedig a második légitársasághoz.
App\Models\Flight::first()->update(['airline_id'=>1]);
App\Models\Flight::where('id', '>', 1)->update(['airline_id'=>2]);
Ezekután most már lekérhető a repülőjárathoz tartozó légitársaság és viszont.
App\Models\Flight::first()->airline;
App\Models\Airline::orderByDesc('id')->first()->flights;
Gyárak
Elkészíthetjük
gyárakkal is a megoldást. Kezdjük a
database/factories/AirlineFactory.php fájllal, annak is a definition
részéhez adjuk hozzá ezt:
'name' => $this->faker->company(),
Ez ugye vállalatokat fog majd létrehozni, ha a Tinker-ben a következőképpen használjuk (indítsuk újra a Tinker-t, ha futna):
Airline::factory()->count(3)->create();
A
Flight ehhez képest már nehezebb ügy, de megoldjuk ezt is, viszont még
nem létezik a Flight Model-hez gyárunk, úgyhogy hozzuk ezt létre:
php artisan make:factory FlightFactory
A
névkonvenció betartása miatt, a Laravel már tudja is, hogy mi a Flight
Model-hez hoztuk létre ezt a gyárat. Csináljuk meg a Flight gyárunk
magját úgy, hogy amikor ezt használjuk az új repülőjáratok
létrehozásához, akkor mindig hozzon létre hozzá új légitársaságot is.
Bővítsük így a definition tömböt:
'number' => $this->faker->word(),
'name' => $this->faker->userName(),
'price' => $this->faker->numberBetween(1000, 9000),
'captain_id' => 1,
'airline_id' => Airline::factory()->create(),
(Aki nem emlékezne, hogy a faker-es dolgok hogyan is használhatók, azoknak javaslom ezt az oldalt ismét.) Működését pedig az újraindított Tinker-ben tudjuk kipróbálni:
Flight::factory()->count(2)->create();
Létrehozunk két repülőjáratot, ugyanazzal a kapitánnyal.
A bejegyzésben végrehajtott változásokhoz tartozó Github commit itt érhető el.