Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

Bogey's avatar
Level 1

Constraints on plymorphic relationships

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.

0 likes
3 replies
Bogey's avatar
Level 1

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();
    }
afrasiyab_haider's avatar

@bogey if your migration is throwing error then it means you don't have foreign key relations with flaggables table. You should create flaggables migration first then create flags migration so your foreign key relationship can be formed.

Bogey's avatar
Level 1

if your migration is throwing error then it means you don't have foreign key relations with flaggables table. You should create flaggables migration first then create flags migration so your foreign key relationship can be formed.

I know that that's what it means. My problem is that it works with my current set-up and adding a new table, while sets up the constraint, doesn't do anything since the new table isn't getting used anyways.

Please or to participate in this conversation.