laravellaravel-9

Let show method of resource controller to show soft-deleted model using policy


Steps to reproduce the issue I'm facing

1- Create the Item:

php artisan make:model Item --all

2- Create the resource in web.php:

Route::resource('items', ItemController::class);

3- Then, in the ItemController's constructor, link the ItemPolicy:

public function __construct()
{
    $this->authorizeResource(Item::class);
}

4- Return true in all of the ItemPolicy's methods (so you get authorized)

public function view(User $user, Item $item)
{
    return true;
}

5- Add SoftDeletes trait in Item model:

namespace App\Models;

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

class Item extends Model
{
    use HasFactory, SoftDeletes;
}

6- Add SoftDeletes in Item migration. Run it.

public function up()
{
    Schema::create('items', function (Blueprint $table) {
        $table->id();
        $table->timestamps();

        $table->softDeletes();
    });
}

7- Write a dd in show method in ItemController to check out if you are actually entering inside the method:

public function show(Item $item)
{
    dd('You are inside the show function');
}

8- Create a item in the db and go to GET /items/1. You should see the dd message.

Route::get('/testCreate', function () {
    $item = Item::create();

    return redirect("/items/$item->id");
});

9- Delete the item. Now, in GET /items/1, the message doesn't appear anymore (instead, I get 404).

Route::get('/testDelete', function () {
    $item = Item::firstOrFail();

    $item->delete();

    return redirect("/items/$item->id");
});

The question

How to enter the show method in GET /items/1 despite the model is soft-deleted?

Notes

public function show($id)
{
    dd($id);
    // dd($item);
}

Solution

  • It was as that easy as adding the withTrashed() function at the end of the route resource route defined in routes/web.php file.

    Before:

    Route::resource('items', ItemController::class);
    

    After:

    Route::resource('items', ItemController::class)->withTrashed(['show']);
    

    Related docs here & here.

    Update

    In an older project I had, despite of doing the explained above, I was getting this error:

    Method Illuminate\Routing\PendingResourceRegistration::withTrashed does not exist.
    

    I solved it by updating the project's composer packages:

    composer update
    

    Now works fine.