laraveleloquentrelational-databaselaravel-models

How to change relational tables fields, when a field of a table changes in Laravel?


I have two tables in my project and there are two relationships between these two tables. One of these two relationships is one-to-one and the other one is a one-to-many relationship.

My tables:

+--------------+-----------------+------+-----+---------+----------------+
| Field        | Type            | Null | Key | Default | Extra          |
+--------------+-----------------+------+-----+---------+----------------+
| id           | bigint unsigned | NO   | PRI | NULL    | auto_increment |
| username     | varchar(255)    | NO   | UNI | NULL    |                |
| password     | varchar(255)    | NO   |     | NULL    |                |
| email        | varchar(255)    | NO   | UNI | NULL    |                |
| common_name  | varchar(255)    | NO   |     | NULL    |                |
| phone_number | varchar(13)     | YES  | UNI | NULL    |                |
| role         | varchar(255)    | NO   |     | NULL    |                |
| created_at   | timestamp       | YES  |     | NULL    |                |
| updated_at   | timestamp       | YES  |     | NULL    |                |
+--------------+-----------------+------+-----+---------+----------------+

+---------------------+-----------------+------+-----+---------+----------------+
| Field               | Type            | Null | Key | Default | Extra          |
+---------------------+-----------------+------+-----+---------+----------------+
| id                  | bigint unsigned | NO   | PRI | NULL    | auto_increment |
| unit_number         | int             | NO   | UNI | NULL    |                |
| owner_id            | bigint unsigned | NO   |     | NULL    |                |
| resident_id         | bigint unsigned | YES  |     | NULL    |                |
| availability_status | varchar(255)    | NO   |     | NULL    |                |
| number_of_rooms     | int             | NO   |     | NULL    |                |
| meterage            | int unsigned    | NO   |     | NULL    |                |
| description         | text            | YES  |     | NULL    |                |
| monthly_rent        | int             | YES  |     | NULL    |                |
| created_at          | timestamp       | YES  |     | NULL    |                |
| updated_at          | timestamp       | YES  |     | NULL    |                |
+---------------------+-----------------+------+-----+---------+----------------+

Relations in my models:

User model:

public function unitOwner()
{
    return $this->hasMany(Unit::class, 'owner_id', 'id');
}

public function unitResident()
{
    return $this->hasOne(Unit::class, 'resident_id', 'id');
}

Unit model:

public function ownerUser()
{
    return $this->belongsTo(User::class, 'owner_id');
}

public function residentUser()
{
    return $this->belongsTo(User::class,'resident_id');
}

I want, for example, when I delete a user, that the deleted user's ID will be deleted from the unit associated with that user (whether he is a resident of the unit or the owner of the unit). And the availability_status column of that unit, for example, can change from occupied to unoccupied.

I have a few ways in mind to implement this mode, but in all of these modes my code becomes very long. What is the shortest way to implement this?


Solution

  • The first thing you need to do is define a migration to set the `owner_id' to null when you delete a user:

    $table->foreignId('owner_id')
        ->nullable()
        ->constrained()    
        ->cascadeOnUpdate()
        ->nullOnDelete();
    

    Then, to handle the availability_status, you can use the model observer like this:

    class UserObserver
    {
        public function deleted(User $user): void
        {
            $user->unitOwner()->update(['owner_id' => null, 'availability_status' => 'unoccupied']);
    
            $user->unitResident()->update(['resident_id' => null, 'availability_status' => 'unoccupied']);
        }
    }