rappasoft / laravel-livewire-tables

A dynamic table component for Laravel Livewire
https://rappasoft.com/docs/laravel-livewire-tables/v2/introduction
MIT License
1.78k stars 335 forks source link

[Feature Request]: Adding Middleware to Routes #1862

Closed N30 closed 2 months ago

N30 commented 2 months ago

Overview

I want to add a custom middleware to the routes. My application is domain based and based on the domain certain things need to happen. When I add the code to my blade it works on the first load cause my middleware are active but subsequent AJAX requests will use the routes within the vendor folder and fail.

Detailed explanation

No response

Notes

No response

lrljoe commented 2 months ago

Which routes are you talking about?

How are you adding in the middleware?

Are you experiencing this issue on any non-table pages?

The Tables themselves are typically added to a page, and then you create a route to that page.

Can you give me an example of the issue you're facing?

N30 commented 2 months ago

No I am not experiencing the issue on non-table pages, yes but normally a livewire route also needs to be defined but the library already takes care of this but it does not have the middleware that I need added.

I am speaking of the specific Livewire route, that defined where AJAX route is handled. normally a custom UsersTable livewire would have to be declared in the routes as:

Route::get('user-table', \App\Http\Livewire\Site1\UserTable::class );

which then routes the ajax requests within /livewire/usertable/

Here is the ResourceConteroller's route which I am placing the compenent inside index.blade.php:

use \App\Http\Middleware\Microsite\ShopifyMiddleware;

Route::middleware([ShopifyMiddleware::class])->group(function () {

    Route::get('/', function () {
        //s\livewire\microsite\review_exchange
         return view('microsite.shopify.home');
    });

    Route::resource('importer', App\Http\Controllers\Microsite\Shopify\ImporterController::class)->except([
        'update', 'destroy'
    ])->names([
        'index' => 'microsite.shopify.importer.index',
        'create' => 'microsite.shopify.importer.create',
        'store' => 'microsite.shopify.importer.store',
        'edit' => 'microsite.shopify.importer.edit',
    ]);

});

Notice I need the ShopifyMiddleware in these because it tells the application what my database name is. DB::connection!

Which works fine because the first render is serverside, but when I want to go to page 2 it fails obviously. Understand?

lrljoe commented 2 months ago

Unless I've massively missed something

This isn't actually a Tables issue, this actually relates to persistence of middleware with Livewire, when a full-page-refresh doesn't occur.

This will happen if you're using wire:navigate, or interacting with a set of data on a page, and not refreshing the page, and have middleware assigned to a route.

How to resolve this is explained here: https://livewire.laravel.com/docs/security#configuring-persistent-middleware

N30 commented 2 months ago

Yeah I think you are missing it, that did not do the trick. This package is automatically adding the routes for livewire instead of letting the user handle them manually in case a basic route does not do the trick...

ok let me make it simpler. What if I want on a routing level the data tables to only load on a specific domain? (obviously I could make an if statement somewhere, but I need to solve it on a route level as what I need is to inject a middlewear)

I find issues with "Hydration" always can be confusing to communicate.

lrljoe commented 2 months ago

Do you mean the injected CSS/JS?

N30 commented 2 months ago

No the livewire handles AJAX through declared routes, for example right now the routes path is:

http://localhost/livewire/message/microsite.shopify.product-table

Where it posts the following JSON data to work during pagination:

{"fingerprint":{"id":"0jKuaAD5szXNtQyeYhzZ","name":"microsite.shopify.product-table","locale":"en","path":"importer","method":"GET","v":"acj"},"serverMemo":{"children":[],"errors":[],"htmlHash":"4bbc2a79","data":{"columnSearch":{"name":null,"photo":null},"table":{"sorts":[],"filters":[],"columns":[]},"theme":null,"bulkActionsStatus":true,"selectAll":false,"bulkActions":[],"selected":[],"hideBulkActionsWhenEmpty":false,"selectedColumns":["id","photo","avatar","name","created-at","updated-at"],"filtersStatus":true,"filtersVisibilityStatus":true,"filterPillsStatus":true,"filterSlideDownDefaultVisible":false,"filterLayout":"popover","filterCount":0,"pageName":null,"perPage":10,"perPageAccepted":[10,25,50],"paginationTheme":"tailwind","paginationStatus":true,"paginationVisibilityStatus":true,"perPageVisibilityStatus":true,"paginationMethod":"standard","paginationCurrentItems":[21,22,23,24,25,26,27,28,29,30],"paginationCurrentCount":10,"paginationTotalItemCount":1082,"page":3,"paginators":{"page":3},"reorderStatus":false,"currentlyReorderingStatus":false,"hideReorderColumnUnlessReorderingStatus":false,"reorderMethod":"reorder","defaultReorderColumn":"sort","defaultReorderDirection":"asc","search":null,"searchStatus":true,"searchVisibilityStatus":true,"searchFilterDebounce":null,"searchFilterDefer":null,"searchFilterLazy":null,"sorts":[],"sortingStatus":true,"singleColumnSortingStatus":true,"sortingPillsStatus":true,"defaultSortColumn":null,"defaultSortDirection":"asc","defaultSortingLabelAsc":"A-Z","defaultSortingLabelDesc":"Z-A"},"dataMeta":[],"checksum":"4e1c792f66f6a3f8b3ebad688be4c1566461ce12e36c6bd32d9d1e7022aee07b"},"updates":[{"type":"callMethod","payload":{"id":"yme6","method":"gotoPage","params":[4,"page"]}}]}

I need this route to have a middleware of my chosing.

lrljoe commented 2 months ago

Which version of Laravel/Livewire/Tables are you using? I'm assuming Livewire v2 and Tables v2.x based on what you've shared...

N30 commented 2 months ago

Yes v2

lrljoe commented 2 months ago

I'll have to spin up a version of v2 to validate, as I've not worked with v2 for Livewire or Tables in over a year.

The Tables themselves will not care about middleware, as they rely on the parent blade/view/route

Have you added your middleware as Livewire Persistent? If so - where?

lrljoe commented 2 months ago

Version 2 is 100% agnostic, so it just runs entirely within the blades/views that are included.

Any calls that it makes, are entirely subject to how Livewire v2.0 handles them.

Middleware does not persist with Livewire, at all, unless you specify it as persistent middleware.

lrljoe commented 2 months ago

https://laravel-livewire.com/docs/2.x/security

Explains it for Livewire 2.0

N30 commented 2 months ago

I tried that after you sent the link I placed in the AppServiceProvider level.

Your statement about table not caring about middleware is relative. In my application models have a different DB:Connection so based on the user so ServiceProviders and Middleware take care of this, assigning this on the page that renders the blades is not doing the job even when told to persist.

For now I've just redefined my middlewear inside the DataTableComponent class created with the php artisan command. I will see what I can find out later.

N30 commented 2 months ago

The v2 documentation explained it better, so basically that is what I need but addPersistentMiddleware is actually not working in my case so I'll have to figure out why. Thank you so much for that info.

lrljoe commented 2 months ago

Can you share what you've set in your AppServiceProvider please?

May be able to give you a pointer.

Do keep in mind that Livewire 2.0 is getting to the unsupported point now!

It's unlikely as well that I'll backport much into Tables v2.0 other than security fixes

lrljoe commented 2 months ago

Also, just for my own sanity:

use \App\Http\Middleware\Microsite\ShopifyMiddleware;

Route::middleware([ShopifyMiddleware::class])->group(function () {

    Route::get('/', function () {
        //s\livewire\microsite\review_exchange
         return view('microsite.shopify.home');
    });

    Route::resource('importer', App\Http\Controllers\Microsite\Shopify\ImporterController::class)->except([
        'update', 'destroy'
    ])->names([
        'index' => 'microsite.shopify.importer.index',
        'create' => 'microsite.shopify.importer.create',
        'store' => 'microsite.shopify.importer.store',
        'edit' => 'microsite.shopify.importer.edit',
    ]);

});

That is living in routes/web.php correct?

Does that also have a web middleware added to it somewhere further up the routes/web.php?

N30 commented 2 months ago

I want to upgrade to Livewire 3 when I have the time, challenge is my Laravel is V9 and I was having issues with composer finding a way to upgrade with all my extra libraries working.

My AppService Provider is basically:

use Livewire;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        LuServiceProvider("App");
    }

    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        Livewire::addPersistentMiddleware([ 
            App\Http\Middleware\Microsite\ShopifyMiddleware::class,
        ]);

But I think what you wanted to see was my middleware.

    define('LU_MICRO_SHOPIFY_DB_NAME', 'www_shopify');
        $db_connection_data = \Config::get('database.connections.mysql');
        $db_connection_data['database'] = LU_MICRO_SHOPIFY_DB_NAME;
        \Config::set('database.connections.www_shopify', $db_connection_data);

It basically created a config/database.php info for a new connection based on user that is logged in. But during pagination the database connection ends up not being defined.

N30 commented 2 months ago

routes

Yes in web,php and I assume all non-api routes have a web but I manually have not added anything further up

lrljoe commented 2 months ago

Hmm

Try forcing it, i.e:

Route::middleware(['web', ShopifyMiddleware::class])

And adding it to the namespace for both routes/web.php and your AppServiceProvider

use App\Http\Middleware\Microsite\ShopifyMiddleware;

And reference using "ShopifyMiddleware::class"

Just in case there's a mismatch somewhere.

lrljoe commented 2 months ago

by the way https://tenancyforlaravel.com/

Is great for swapping out databases etc based on domain, and has capabilities for syncing resources/models between instances. I believe it's still open source, haven't used it in a little while

N30 commented 2 months ago

The problem is I don't want it in web, this is microservice and the middleware should only be run in very specific routes for users and is 1% of my entire application. It would actually cause problems if it was run on any unwanted pages. I think once I figure out how to upgrade to version 3 it should work. I think this persistent middleware in v2 isn't working as well.

N30 commented 2 months ago

still

ooh that seems really interesting I didn't find anything like it so I built my own over the years, its turned into a whole thing now that would seem impossible to change but this might become really useful in future projects. Thanks for the info. very interested as I am always building things in such manner. (Reuse code for clients)

lrljoe commented 2 months ago

The official Livewire discord (text chat) is very active btw, and has a dedicated channel for v3 upgrade issues.

I'm on there sporadically but there's a fair few other contributors to Livewire core who will be able to give you pointers for upgrade issues you may be facing.

You can also always ping me on the Tables discord if you're not having much luck.

lrljoe commented 2 months ago

And yeah, I have had to adjust the Stancl Tenancy for Laravel package, as there's a real mix in my environment, hundreds of VMs spinning up/down, and some dedicated environments, so I had to butcher it somewhat!

But out of the box, for a typical SaaS/Multi-Client solution, it's pretty decent

N30 commented 2 months ago

Thank you, will definitely get on Discord then. Hard to stay up to date these with where the cool kids are at.

Right now I am pretty much loading a ton of composer dependencies for every page/domain load. I think eventually it can become a problem. With your setup it seems you are able to load dependencies as needed.

lrljoe commented 2 months ago

I have some deferred service providers where things aren't needed consistently.

For Modals etc, I use the WIre Elements Modals approach, so that I can dynamically load in the Modal as I need to.

I do the same for the Tables

Using Livewire Forms (v3 only I'm afraid), and that approach, I get very performant apps