Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Closed
boptom opened this issue May 10, 2024 · 5 comments
Closed

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

boptom opened this issue May 10, 2024 · 5 comments
Assignees

Comments

@boptom
Copy link

boptom commented May 10, 2024

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
Copy link
Author

boptom commented May 10, 2024

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
Copy link
Collaborator

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
Copy link
Author

boptom commented May 29, 2024

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: livewire/livewire#8445

Can this issue be re-opened?

@boptom
Copy link
Author

boptom commented May 29, 2024

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

@rvanasperen
Copy link

rvanasperen commented Oct 12, 2024

In case anyone finds this through Google; I ran into the same issue, but also found an acceptable resolution. I'm using Volt functional components.

As previously mentioned Volt does not support implicit route model binding, preventing the model policy from triggering (since the routing system does not have a model to work with).

Setting the route model explicitly will fix this issue:

class AppServiceProvider
{
    public function boot(): void
    {
        Route::model('post', App\Models\Post::class);
    }
}
Route::middleware('can:view,post')->group(function () {
    Volt::get('posts/{post}', 'pages.posts.index')->name('posts.index'); // previously 403, works as intended with explicit route model binding
});

Don't forget to set up your policy.

See: https://laravel.com/docs/11.x/routing#explicit-binding

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants