tenancy / multi-tenant

Run multiple websites using the same Laravel installation while keeping tenant specific data separated for fully independent multi-domain setups, previously github.com/hyn/multi-tenant
https://tenancy.dev
MIT License
2.55k stars 392 forks source link

Environment singleton on "booted" callback #841

Open bert-w opened 5 years ago

bert-w commented 5 years ago

I am trying to change my tenant for testing purposes in a service provider's boot() method, but any tenant I change in the service provider seems to be set to null once i reach the controller.

So to change the hostname, i use the following code:

$hostname = Hostname::where('fqdn', 'test.mydomain.com')->first();
TenancyFacade::hostname($hostname);
TenancyFacade::tenant($hostname->website);;

Instead of the TenancyFacade i've also used app(Environment:class) which did not make a difference.

I've tried to track it down and found this line of code, for which I do not exactly know why it is done this way: https://github.com/tenancy/multi-tenant/blob/5.x/src/Providers/TenancyProvider.php#L45

 $this->app->booted(function ($app) {
            $app->singleton(Environment::class, function ($app) {
                return new Environment($app);
            });
        });

This boots the environment singleton on a booted callback, but this seems to reset the hostname/tenant.


So in short, how do I set a tenant in a service provider so that everything uses that tenant?

fletch3555 commented 4 years ago

So you want everything to use a single tenant? That seems counter-intuitive.

The reason it's in that booted callback is because we needed to guaranteed everything was loaded first.

I don't think a service provider is the right spot to make your change. Perhaps try in middleware?

bert-w commented 4 years ago

well, I have this serviceprovider where I fill in various config/mail.php properties with settings from the current tenant database, but I couldnt figure out why switching the tenant in that provider did not persist properly, and seemed to reset in the same request after it reached the controller.

In addition, reading the Laravel docs about register() and boot() method (https://laravel.com/docs/5.7/providers#the-register-method) it says:

You should never attempt to register any event listeners, routes, or any other piece of functionality within the register method. Otherwise, you may accidentally use a service that is provided by a service provider which has not loaded yet.

Doesn't this mean that registering the Hyn\Tenancy\Environment actually fits better in the boot() method so everything has been loaded? The current register() method is already saying if $this->app->booted(callback) thus putting it at the end of the callstack, while we might want to use it earlier?