todi's avatar
Level 1

Calling withTrashed() inside global scope fails

Hi,

I'm trying to call withTrashed() on the QueryBuilder within a global scope. This is what the global scope looks like:

public function apply(Builder $builder, Model $model)
    {
    [... some stuff not related to the $builder or $model ...]
    return $builder->withTrashed();        
    }

I already check if the scope actually gets called.

I use a universal index function to show models(inside my base controller):

public function indexModel($model, Request $request) {
        // check if pagination is enabled
        if(!is_null($this->limit)) {
            $data = $model::paginate($this->limit);
            $data->appends($request->except(['page']));
        } else {
            $data = $model::get();
        }

        return $data;
    }

A call of this function looks something like this:

    $data = $this->indexModel(SomeModel::class, $request);

Even though there is no error when calling the index function of a controller, the response does not include any trashed objects. It's the same response i get when not calling withTrashed() at all.

If i manually add withTrashed() to the queries in the indexModel() function (e.g. use $data= $model::withTrashed()->get() instead of $data = $model::get() and let the global scope handle withTrashed) the response includes all trashed objects. So soft deleting seems to work fine.

I feel like I'm doing something horribly wrong here. Can someone give me any advice on how to fix this ?

Thanks in advance.

0 likes
3 replies
todi's avatar
todi
OP
Best Answer
Level 1

After inspecting the returned $builder i noticed that calling withTrashed() somehow only removed the scope SoftDeletingScope but not the "where deleted_at = null". So i ended up looping through all wheres of the builder and removing the where clause:

public function apply(Builder $builder, Model $model) {
    // remove global scope
        $builder = $builder->withTrashed();

        // remove "where deleted_at = null"
        $wheres = $builder->getQuery()->wheres;

        foreach($wheres as $key => $data) {
            if($data['column'] ==  $model->getTable() . '.deleted_at' && $data['type'] == "Null") {
                unset($builder->getQuery()->wheres[$key]);
            }
        }
        
        return $builder;er;
}

This seems like a really dirty solution and I still have absolutely no idea why calling withTrashed() does not remove the where clause. So if someone knows a better solution or why this didnt work as expected, feel free to post your answer :P

1 like
elias's avatar

Seems like withTrashed can't be applied to the builder object, this worked for me.

class WithTrashedScope implements Scope
{
    /**
     * Apply the scope to a given Eloquent query builder.
     *
     * @param  \Illuminate\Database\Eloquent\Builder  $builder
     * @param  \Illuminate\Database\Eloquent\Model  $model
     * @return void
     */
    public function apply(Builder $builder, Model $model)
    {
        $builder->orWhereNotNull('deleted_at');
    }
}
1 like

Please or to participate in this conversation.