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

arreguialvaro's avatar

Eloquent not excluding soft deleted models

Should a model that is deleted (using soft deletes) be returned when querying it through a related model?

I have a model, User that hasMany Wallet and when I call $user->wallets, that deleted model (Wallet) is listed in the results...

Do I really need to use $user->wallets()->whereNull('deleted_at')->get()?

use Illuminate\Database\Eloquent\SoftDeletes;
class Wallet extends Model
{
    use SoftDeletes;
    protected $dates = ['deleted_at'];
}
0 likes
16 replies
arreguialvaro's avatar

No worries @desloc yes, thats already included. These are the attributes returned by $user->wallets

#attributes: array:8 [
        "id" => 1
        "user_id" => 60
        "token" => "xcZjdEzBzQNYTDy6EtQGRssgtN2LuGa1Vh-F0p79CEcAABhSW9W0gj5k6vzOe8aJBwUZ7AAAAAEAAAHp"
        "masked_pan" => "****************"
        "created_at" => "2017-03-08 11:52:26"
        "updated_at" => "2017-03-17 10:34:41"
        "deleted_at" => "2017-03-17 10:34:41"
        "alias" => "My Wallet"
      ]
Snapey's avatar

What if you comment out your protected $dates line

arreguialvaro's avatar

@Snapey That won´t help...

Here's my complete model:

<?php

namespace App\Models\EWallet;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;

class Card extends Model
{
    use SoftDeletes;
    protected $connection = 'main';
    protected $fillable = ['alias', 'token', 'masked_pan'];
    protected $dates = ['deleted_at'];

    protected static function boot()
    {
        static::deleted(function ($card) {
            $card->top_ups()->delete();
        });
    }

    public function top_ups()
    {
        return $this->hasMany(ScheduledTopUp::class);
    }
}
$ php artisan tinker
Psy Shell v0.8.2 (PHP 5.6.29 — cli) by Justin Hileman
>>> use App\Models\Billpocket\User; $user = User::find(60)->cards;
=> Illuminate\Database\Eloquent\Collection {#708
     all: [
       App\Models\EWallet\Card {#707
         id: 1,
         user_id: 60,
         token: "xcZjdEzBzQNYTDy6EtQGRssgtN2LuGa1Vh-F0p79CEcAABhSW9W0gj5k6vzOe8aJBwUZ7AAAAAEAAAHp",
         masked_pan: "****************",
         created_at: "2017-03-08 11:52:26",
         updated_at: "2017-03-17 10:34:41",
         deleted_at: "2017-03-17 10:34:41",
         alias: "My Card",
       },
     ],
   }
>>>
Snapey's avatar

Why won't it help? and what has the rest of the model got to do with it?

arreguialvaro's avatar

@Snapey If I'm not mistaken, $dates only indicates what fields should be mutated to an instance of Carbon

Anyways, I tried your suggestion and still got the same result.

I added the rest of the model just for clarification, forgive me for being out of line.

Snapey's avatar

ok no worries. it's related to deleted_at so could be linked. for the few seconds it takes to try I thought it might be worth a shot.

I cannot remember adding it to dates when i used soft deletes in the past but i can see it us recommended in the docs.

A few things to try

if you do Card::all() are deleted included?

do you have $with in your User model?

arreguialvaro's avatar

Yes, Card::all(); returns deleted models...

I'm not sure what you mean by $with, this is the relationship in the User model:

public function cards()
    {
        return $this->hasMany(Card::class);
    }
Snapey's avatar

i'm wondering why the scope could be bypassed, so Card::all() is to eliminate any interference from the User model

the other question, with is because you can have a $with array in another model and it will automatically eager load relations. I thought if you had $with(['card']) in your User model it might be bypassing the scope

The only thing I can suggest at this point is to review the sql query that is used

moharrum's avatar

Hi @arreguialvaro ,

I think I encountered this issue my self once, try removing deleted_at from the $dates array.

Snapey's avatar

Just looking through the code... Just out of interest, are your table names standard, e.g. cards and wallets?

Coreation's avatar

Found out why it wasn't working on my end, apparently it does not work well if you have included other traits that modify the scope. The issue is not the same symptom, but it is the same reason: https://github.com/laravel/framework/issues/9349

You can circumvent it by using the soft delete trait in your custom trait that adds a global scope:

use SoftDeletes;

public static function boot()
{
    static::addGlobalScope(function (Builder $builder) {
        // Add custom scope here
    });

    static::bootSoftDeletes();
}
2 likes
warren32's avatar

@Coreation that is correct, you need to boot the soft deletes inside the model if you are overriding the boot method.

protected static function boot()
    {
    parent::boot();

        static::deleted(function ($card) {
            $card->top_ups()->delete();
        });
    }

Please or to participate in this conversation.