Poznajemy kilka rzeczy, takich jak dissociate, delete, onDelete – cascade i set null. Są to pewne puste obszary, które musimy poznać, aby mieć pełnię rozeznania w sytuacji.
Ok, a zatem tak:
- Person jest w relacji hasOne do Address
- Address jest w relacji belongsTo do Person
W moim przypadku mam adres o ID 4 przypisany do jakiejś osoby, oraz osobę o ID 10 bez żadnego adresu. Spróbujemy ukraść adres o ID 4 osobie, do której jest przypisany i dopisać go do osoby o ID 10.
Tak to robimy:
Artisan::command('dissociate-try', function () {
$addr = Address::find(4);
$new_person = Person::find(10);
$addr->person()->dissociate();
$addr->person()->associate($new_person)->save();
});
Po wykonaniu komendy powinniśmy zauważyć, że adres o nazwie 4 wskazuje teraz (w swoim person_id) na osobę o id 10. Dissociate go rozłączyło z poprzednią osobą, associate przypisało do osoby o ID 10.
Ok, inny przykład – mam adres o ID 23. Jest on do kogoś przypisany. Chcę ten adres usunąć, ktokolwiek go miał, teraz adresu mieć nie będzie.
Robimy to tak:
Artisan::command('delete-try', function () {
$addr = Address::find(23);
$addr->delete();
});
I już widzimy zmianę w bazie danych. Ok, inna rzecz – chcę usunąć osobę, która ma jakiś adres przypisany. W moim przypadku osoba o ID 53 istnieje w tabeli people zaś w tabeli addresses istnieje adres z person_id ustawionym na 53.
Czy uda się usunąć tę osobę? Zobaczmy:
Artisan::command('delete-hasone', function () {
$person = Person::find(53);
$person->delete();
});
Jeżeli wykonywaliśmy ten projekt razem ze mną to nasza migracja wygląda tak:
public function up(): void
{
Schema::create('addresses', function (Blueprint $table) {
$table->id();
$table->timestamps();
$table->unsignedBigInteger('person_id');
$table->string('city');
$table->string('street');
$table->foreign('person_id')->references('id')->on('people');
});
}
I nie możemy usunąć osoby posiadającej adres (to jest osoby mającej pk id w tabeli people, któremu odpowiada fk person_id w tabeli addresses) bez usunięcia wcześniej adresu.
Robimy to tak:
Artisan::command('delete-hasone', function () {
$person = Person::with('address')->find(53);
$person->address()->delete();
$person->delete();
});
Natomiast gdybyśmy chcieli mieć możliwość usuwania modeli, które mają coś hasOne to musimy to w migracji określić, bo jak patrzyliśmy na error, to mieliśmy foreign key constraint, który dał fail.
Oto prosty przykład:
$table->foreign('term_id')
->references('term_id')->on('terms')
->onDelete('cascade');
To oznacza, że po usunięciu usuwanie ma lecieć „kaskadowo” czyli „CSSowo” 🙂 Nie, żartuję, to oznacza, że leci jak kaskada, usuwa model-rodzic i powiązane z nim dzieci, też uproszczenie.
Można też zrobić, aby przy usuwaniu rodzica dziecko miało foreign key ustawiony na null. Przykład:
$table->...->onDelete('set null');
Musimy tylko pamiętać, aby foreignKey był nullable:
$table->integer('foreign_id')->unsigned()->nullable();
Cóż, dużo z tym zachodu, ale nikt nie obiecywał, że programowanie będzie łatwe jak hello worldy w Pythonie.
Obiecywano, że nie będziemy pisać kodu maszynowego ani przesuwać bitów, chyba że z własnej chęci poznania programowania lepiej