livewire / volt

Volt is an elegantly crafted functional API for Livewire.
https://livewire.laravel.com/docs/volt
MIT License
312 stars 19 forks source link

Volt:route() middleware not working with "can" #104

Closed boptom closed 1 month ago

boptom commented 2 months ago

Volt Version

1.0

Laravel Version

11.7

PHP Version

8.3.6

Database Driver & Version

sqlite

Description

Using 'can:view,post' in middleware in Volt route always returns 403.

e.g.

Volt::route('post/{post}', 'post')
    ->middleware(['auth', 'can:view,post'])
    ->name('post');

A minimal Laravel app to show this can be found here: https://github.com/boptom/volt-route-middleware

A test that fails is: https://github.com/boptom/volt-route-middleware/blob/main/tests/Feature/PostTest.php

The app has 2 routes. The alternate route works, showing the policy is correct. The 2 routes can be found in web.php here: https://github.com/boptom/volt-route-middleware/blob/main/routes/web.php#L19

Steps To Reproduce

In terminal:

git clone https://github.com/boptom/volt-route-middleware
cd volt-route-middleware
compose install

cp .env.example .env
php artisan key:generate
php artisan migrate

php artisan test tests/Feature/PostTest.php

The output shows one test passing, and one failing.

   FAIL  Tests\Feature\PostTest
  ⨯ it can view post                                                                                                                     0.13s  
  ✓ it can view alternate route                                                                                                          0.01s  
  ────────────────────────────────────────────────────────────────────────────
   FAILED  Tests\Feature\PostTest > it can view post                                                                                            
  Expected response status code [200] but received 403.
Failed asserting that 403 is identical to 200.

  at tests/Feature/PostTest.php:11
      7▕     $post = $user->posts()->create();
      8▕ 
      9▕     $response = $this->actingAs($user)->get(route('post', [$post]));
     10▕ 
  ➜  11▕     $response->assertStatus(200);
     12▕ });
     13▕ 
     14▕ it('can view alternate route', function () {
     15▕     $user = User::factory()->create();

  Tests:    1 failed, 1 passed (2 assertions)
  Duration: 0.18s
boptom commented 2 months ago

Upon digging into internals it seems route model binding isn't working. I've tracked it down to here:

https://github.com/laravel/framework/blob/42e6bda679d8a1c56b56c00f9830c4d906812220/src/Illuminate/Routing/RouteSignatureParameters.php#L27

Which returns an empty parameter list when using Volt, and a filled parameter list otherwise. I can't seem to get any further debugging this, sorry.

nunomaduro commented 1 month ago

This is an issue you need to report on the main Livewire repository (https://github.com/livewire/livewire), as it is not working for regular full page components in Livewire either:

Route::get('post/{post}', \App\Livewire\MyRegularLivewireComponent::class)
    ->middleware(['auth', 'can:view,post'])
    ->name('post'); // fails with 403
boptom commented 1 month ago

Full page Livewire components work if the Post type is specified.

i.e.

class extends Component
{
    public Post $post;

    public function mount(Post $post)
    {
        $this->post = $post;
    }
}

However, it still does not work for Volt.

A passing test for the Livewire full page component, as well as the failing Volt test has been added to the test repo here: https://github.com/boptom/volt-route-middleware/blob/main/tests/Feature/PostTest.php

The relevant discussion on the Livewire repo can be found here: https://github.com/livewire/livewire/discussions/8445

Can this issue be re-opened?

boptom commented 1 month ago

Possibly related: Route model binding also isn't working on Volt components written in a functional way.

The following would output "Post View 1", or whatever the id of the post is.

<?php

use function Livewire\Volt\{state};

state(['post' => fn () => $post]);

?>

<div>
    Post View {{ $post }}
</div>

Route model binding does work in Folio if written exactly the same way though.

I've added the page to the test repo here: https://github.com/boptom/volt-route-middleware/blob/main/resources/views/livewire/volt-functional-post.blade.php