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

shaunoza's avatar

Adding soft deletes to older code

Hi all

I have an existing project that I need to add soft deletes to. That's as simple as adding new migrations to add the db columns, and adding the SoftDeletes trait to the models.

But in some of my older migrations, there are queries using models: eg SomeModel::where('thing', '=', 'foo')->first().

In prod that's fine, cause those migrations have already run and will never run again. But in dev and automated tests, the db is being torn down and migrated from scratch a lot. And when those "old" migrations are run they fail because the query automatically now adds the deleted_at column check. It all makes sense as to why, I just don't know what the best fix is.

As I can see it, there are a number of options:

  • Update the old migrations to add the soft delete columns when the table was first created (in addtion to the new migration for prod). Seems a bit sketch updating old migrations like that?
  • Update the queries in the old migrations to use DB and not models directly. But then I lose nice model helpers like firstOrCreate()
  • Add withTrashed() to the old migration queries so they don't try add the deleted_at column
  • "Squash" the migrations so the old migrations don't run even in dev or test

Other than squashing, these options involve editing old migrations which is obviously not ideal. Is there a more conventional or recommended way of dealing with this situation? (there probably shouldn't be eloquent queries in the migrations to be fair, but I can't fix the past 😊)

0 likes
2 replies
Snapey's avatar

there probably shouldn't be eloquent queries in the migrations to be fair

yup!

The problem is because the model is enforcing the soft delete trait on the earlier queries. Assuming its not simple to override this, perhaps you could change those Eloquent queries to Query Builder so that the model is not used?

Sorry, reading back, I see you considered this.

Could you test for the existence of the deleted_at column and use that to add withTrashed where no column exists?

shaunoza's avatar

@Snapey Thanks for the reply.

There is no need to check for the deleted_at in the old migrations, cause it's guaranteed not to be there.

Moving to the query builder is one of the options listed. As pointed out, that means I need to somewhat significantly update old migrations (things like manually dealing with firstOrCreate() instances), and that make me uncomfortable.

Adding the withTrashed() is the easiest thing to do, and doesn't change those old migrations as much.

So for now, that's what I've settled on. As well as making a note to not use eloquent in the migrations going forward.

I guess what I was hoping is that there was some "laravel way" that I didn't list that I just don't know about yet.

Please or to participate in this conversation.