archtechx / tenancy

Automatic multi-tenancy for Laravel. No code changes needed.
https://tenancyforlaravel.com
MIT License
3.56k stars 424 forks source link

Identification by Path + Livewire Login Component #628

Closed codetay closed 3 years ago

codetay commented 3 years ago

Describe the bug

I tried to make it work with Identification by Path and a Livewire Login Component. But it keeps showing a message like this: Stancl\Tenancy\Exceptions\RouteIsMissingTenantParameterException The route's first argument is not the tenant id (configured paramter name: tenant).

Steps to reproduce

I already declared the middleware at livewire config:

    'middleware_group' => [
        'web',
        \Stancl\Tenancy\Middleware\InitializeTenancyByPath::class,
    ],

And in routes/tenant.php

Route::prefix('/{tenant}')
    ->middleware([
        'web',
        \Stancl\Tenancy\Middleware\InitializeTenancyByPath::class,
    ])->group(function () {
Route::get('/login', Login::class);
});

My livewire fullpage component:


namespace App\Http\Livewire;

use Livewire\Component;

class Login extends Component
{
    public $form = [
        'email' => null,
        'password' => null,
        'remember' => false,
    ];

    public function render()
    {
        return view('livewire.login');
    }

    public function submit()
    {

        $isSuccess = auth()->attempt([
            'email' => $this->form['email'],
            'password' => $this->form['password']
        ], $this->form['remember']);

    }
}

And then i created a tenant with the name test and access to it via mydomain.com/test, when i submitted the form it got the error like descripted

Expected behavior

If i using idenfication by domains, i will work normally. But i don't want to use domains for some reasons.

Your setup

stancl commented 3 years ago

I don't think you can use LW with path identification. Multi-domain is really the only way to integrate with these packages without pain

vlados commented 3 years ago

I know it's not "elegant" but my workaround is in the component to add:

function __construct()
{
  if(request('fingerprint.path') && !tenant()) {
      $path = explode("/",request('fingerprint.path'));
      tenancy()->initialize($path[1]);
  }
  parent::__construct();
}
Henriquex25 commented 2 years ago

I know it's not "elegant" but my workaround is in the component to add:

function __construct()
{
  if(request('fingerprint.path') && !tenant()) {
    $path = explode("/",request('fingerprint.path'));
    tenancy()->initialize($path[1]);
  }
  parent::__construct();
}

in which file did you add this code?

It worked?

FelipeVeiga commented 2 years ago

@stancl can you update the docs as bellow ?

if you are using InitializeTenancyByPath and Livewire you wil need

config/livewire.php

'middleware_group' => [
        'web',
        InitializeTenancyByPath::class, // or whatever tenancy middleware you use
    ],

add in the tenant route group Route::post('livewire/message/{name}', [HttpConnectionHandler::class, '__invoke']);

In Blade just after @livewireScripts:

@livewireScripts
<script>
    window.livewire_app_url = '{{ tenant()->id}}';
</script>

And in case you are wondering about the config of Livewire, there is no need to change it. Just leave it as it is; null: 'asset_url' => null,

thanks from Brazil!

stancl commented 2 years ago

You can make a PR to stancl/tenancy-docs.

Just click the "Edit" button at the bottom of any docs page.

andreasmatuszewski commented 1 year ago

@FelipeVeiga @stancl this does not work with file uploads (Livewire\WithFileUploads - Trait from Livewire).

stancl commented 1 year ago

@andreasmatu Do you mean this? https://github.com/stancl/tenancy-docs/pull/206/files

andreasmatuszewski commented 1 year ago

@stancl yes! And in https://github.com/stancl/tenancy-docs/pull/206/files row 54 is a duplicate of row 37. Row 54 should be something like routes/tenant.php

osama-98 commented 1 year ago

Hello all,

Since when it's an http request why not to use identification by request data for livewire requests?

I did this and it worked for me

In routes/tenant.php

Route::middleware(['web', InitializeTenancyByRequestData::class])->group(function () {
    Route::post('/livewire/message/{name}', [\Livewire\Controllers\HttpConnectionHandler::class, '__invoke']);
});

In blade page below the livewire scripts

@livewireScripts
<script>
    window.Livewire.connection.headers = {
        ...window.Livewire.connection.headers,
    'X-Tenant': '{{ tenant()->id }}'
    };
</script>

and if you are having the central dashboard, in my case I'm using the prefix admin for it. Like this In routes/web.php

Route::middleware(['web'])->group(function () {
    Route::post('admin/livewire/message/{name}', [\Livewire\Controllers\HttpConnectionHandler::class, '__invoke']);
});

And in admin's blade layout page In blade page below the livewire scripts

@include('partials.scripts')
<script>
    window.livewire_app_url = '/admin';
</script>
ahmedsayedabdelsalam commented 1 year ago

https://gist.github.com/ahmedsayedabdelsalam/ee093a934d0b149b19790fa715f86ce2

i made this script that can handle livewire, axios, fetch, XMLHttpRequest

add this meta tag to your layout

@if(tenant())
    <meta name="tenant" content="{{ tenant('id') }}">
@endif

import it in bootstrap.js in laravel app

/**
 * Set X-Tenant request header for tenant domains.
 */
const tenantTag = document.head.querySelector('meta[name="tenant"]');
if (tenantTag) {
    import('./utils/set-tenant-header')
        .then(module => module.default(tenantTag.content))
}
thoresuenert commented 2 weeks ago

Hey i found a blog post here https://wire-elements.dev/blog/custom-livewire-request-headers

Livewire 3 has hooks for this:

Livewire.hook('request', ({ options }) => {

    // options.headers['Authorization'] = 'Bearer <MY_TOKEN>';
   options.headers['X-Tenant'] = '{{ tenant()->id }}';

})

And you can set a custom Middleware this way in a service provider:

Livewire::setUpdateRoute(function ($handle) {
            return Route::post("/livewire/update", $handle)->middleware([
                "web",
                \App\Http\Middleware\MakeTenantAware::class,
            ]);
        });