The following method in the models does what a constraint should. I'm using it for the moment, but I was hoping to do this properly.
public function delete()
{
$this->flags()->delete();
return parent::delete();
}
Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.
I have a problem with setting up constraints on polymorphic relationships in laravel. Honestly, I've never worked with polymorphic relationships before, so this is a learning experience for me. Here is what I have so far.
I've got three tables: flags, comments and posts.
I've set up a system for users to flag comments and posts (and more resources will be added in the future that users would be able to flag). I'm trying to make it so if the resource that was flagged got deleted will have the corresponding flag deleted from the database. Below is my flags migration.
public function up(): void
{
Schema::create('flags', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id')->nullable();
$table->morphs('flaggable');
$table->enum('flag_type', ['spam', 'offensive', 'irrelevant', 'other']);
$table->timestamps();
$table->index(['flaggable_id', 'flaggable_type']);
$table->foreign('flaggable_id')
->references('id')
->on('flaggables') // the issue
->onUpdate('cascade')
->onDelete('cascade');
});
}
Which obviously throws the following error upon migrating
SQLSTATE[HY000]: General error: 1824 Failed to open the referenced table 'flaggables' (Connection: mysql, SQL: alter table `flags` add constraint `flags_flaggable_id_foreign` foreign key (`flaggable_id`) references `flaggables` (`id`) on delete cascade on update cascade)
Because I don't have the flaggables table... but everything works without it (minus the constraint). I mean if I flag a post, the post is flagged properly and the correct info is stored in the flags table and the same for comments. The flags table itself handles the polymorphic logic and setting that constraint on itself gives me constraint errors when trying to add flags to flags table.
The following is my flags model.
class Flag extends Model
{
use HasFactory;
protected $fillable = [
'user_id', 'flaggable_id', 'flaggable_type', 'flag_type'
];
protected $attributes = array(
'user_id' => null
);
static $enums = [
'spam','offensive','irrelevant','other'
];
public function comment()
{
return $this->morphTo(Comment::class);
}
public function post()
{
return $this->morphTo(Post::class);
}
public function flaggable()
{
return $this->morphTo();
}
}
The relevant methods in my comment model are
public function flags()
{
return $this->morphMany(Flag::class, 'flaggable');
}
public function isFlagged()
{
if(Auth()->user() !== null && Auth()->user()->id === 1)
{
return $this->flags()->exists();
}
return false;
}
and the relevant methods from the post model
public function flags()
{
return $this->morphMany(Flag::class, 'flaggable');
}
public function isFlagged()
{
if(Auth()->user() !== null && Auth()->user()->id === 1)
{
return $this->flags()->exists();
}
return false;
}
(Going to move these into a trait)
Everything but the constraints are working. I'm guessing I need to set up a pivot table to add the constraints or I would need to add the logic into the PHP (in the delete() method for comments, check if it has flags and delete those flags myself), but I was trying to optimize it to let the database do work as well.
Please or to participate in this conversation.