alexrobinson's avatar

On Delete of Foreign Key Set to Default

I have two tables with a foreignID between them. On delete of the foreignkey in ItemTypes I'd like the itemtype_id for all related items to be set to 1, a default value of "Unassigned" on the item types table. I can't seem to get it to work.

I've managed to get it to work if I set to nullOnDelete, but is there no comparable updateOnDelete to set a value to to 1 or will I have to build a custom function on a class to get this to work as expected? I tried using onDelete('set default') and then having a default value on the column but that didn't work, even if I set the column to nullable.

The only thing that has worked thus far is this migration:

public function up(): void
{
    Schema::create('items', function (Blueprint $table) {
        $table->id();
        $table->foreignId('itemtype_id')->nullable()->constrained()->nullOnDelete();
        $table->string('description');
        $table->string('color')->nullable();
        $table->string('material')->nullable();
        $table->timestamps();
    });
}

Is this possible? Or should I just live with NULL values in my foreign ID column and handle them some other way, like model observers.

0 likes
3 replies
LaryAI's avatar
LaryAI
AI
Best Answer
Level 58

To set the itemtype_id for all related items to a default value of 1 ("Unassigned") on delete of the foreign key in the ItemTypes table, you can use a combination of database constraints and model observers.

First, modify your migration to set the itemtype_id column to nullable and add a default value of 1:

public function up(): void
{
    Schema::create('items', function (Blueprint $table) {
        $table->id();
        $table->foreignId('itemtype_id')->nullable()->default(1)->constrained();
        $table->string('description');
        $table->string('color')->nullable();
        $table->string('material')->nullable();
        $table->timestamps();
    });
}

Next, create a model observer for the Item model. In the observer's deleting method, you can update the related items' itemtype_id to the default value of 1:

namespace App\Observers;

use App\Models\Item;

class ItemObserver
{
    public function deleting(Item $item)
    {
        $item->items()->update(['itemtype_id' => 1]);
    }
}

Don't forget to register the observer in the boot method of your AppServiceProvider or any other service provider:

use App\Models\Item;
use App\Observers\ItemObserver;

public function boot()
{
    Item::observe(ItemObserver::class);
}

With this setup, whenever a foreign key in the ItemTypes table is deleted, the deleting method in the ItemObserver will be triggered, and it will update the related items' itemtype_id to the default value of 1.

Note: Make sure to replace App\Models\Item with the actual namespace and class name of your Item model.

alexrobinson's avatar

Ok great, that worked. Except I needed to observe the ItemType and not the Item itself, and to add a relationship to the model because I hadn't defined one yet. Otherwise, thanks AI!

rsakhale's avatar

You can do it this way too using an Observer

class ItemTypeObserver
{
     public function deleting(ItemType $type)
    {
          $type->items()->update(['itemtype_id' => 1]);
    }
}

and define your relation as

class ItemTye extends Model
{

      //
     public function items():  HasMany
    {
         $this->hasMany(Item::class);
    }
}

Please or to participate in this conversation.