Komplex példa 3. rész - Gyakorlás

Attila | 2022. 03. 25. 18:04 | Olvasási idő: 2 perc

Címkék: #Adatbázis (Database) #Adatgyár (Factory) #CRUD #Eloquent #Laravel #Laravel 9 #Tinker

Folytatjuk a komplex példánk bemutatását: a "kiadott házi feladat" megoldását tekintjük át.
Laravel-homework

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.