Skip to main content

archtechx / tenancy: Installation, Configuration and Register Tenant

Premium
8:12

The next package we will check is stancl/tenancy. With this package, you can have single and multi-database tenancy. First, we will take a look at a single database approach.

The starting point is the same CRUD with the Project and Task without any tenancy.


Installation and Configuration

So, first, install the package via composer and then run the tenancy:install command.

composer require stancl/tenancy
php artisan tenancy:install
php artisan migrate

Next, we must add the TenancyServiceProvider.

bootstrap/providers.php:

return [
App\Providers\AppServiceProvider::class,
App\Providers\TenancyServiceProvider::class,
];

Install command created the Migration for the tenants table. Now we must make a Model for that table and replace the content of the Model with the code from the quickstart.

php artisan make:model Tenant

app/Models/Tenant.php:

namespace App\Models;
 
use Stancl\Tenancy\Database\Models\Tenant as BaseTenant;
use Stancl\Tenancy\Contracts\TenantWithDatabase;
use Stancl\Tenancy\Database\Concerns\HasDatabase;
use Stancl\Tenancy\Database\Concerns\HasDomains;
 
class Tenant extends BaseTenant implements TenantWithDatabase
{
use HasDatabase, HasDomains;
}

Next, in the config/tenancy.php, we need to set that package to use...

The Full Lesson is Only for Premium Members

Want to access all of our courses? (36 h 00 min)

You also get:

61 courses
Premium tutorials
Access to repositories
Private Discord
Get Premium for $129/year or $29/month

Already a member? Login here

kiogo avatar

Are there any major advantages to archtechx/tenancy compared to the team multi-tenancy no package solution?

Modestas avatar

As with everything in code - we can't say that one is better than another.

Tenancy has the biggest advantage of being public and used by many, which means it should be relatively bug free. While your custom solution is fresh and might have bugs.

Which is better? Can't tell! This has to be tried and looked at case-by-case (for example, in my projects - I constantly switch between similar packages as they usually offer some key differences)

kfs avatar

what if a team or a user wants to have a diffrent domain, is it possible to have different domains for each tenant

Modestas avatar

It's possible for sure, but that comes with complications.

You need a devops to create a proxy server OR you need to configure your own server to issue correct SSL certificates on top. Then, there is a big logic change oh how your application recognizes the domain and uses it. You have to use https://laravel.com/docs/11.x/routing#route-group-subdomain-routing but instead of subdomain, you have to add full domain and store full domains in database.

From there, it in theory works, but you have to do EXTENSIVE testing :)

kfs avatar

what if its type a like cloudflare type a domain it takes the host ip only wont it work ?

Modestas avatar

No, that's not how it works. If you do a host ip only - you will have to always type the IP to access the tenant.

Keep in mind:

Domain is just a human friendly IP. Seriously, you can access your website via an IP, but domain is just a human friendly version in the URL.

Shadyar Bzhar Othman avatar
Shadyar Bzhar Othman

What's the different between these?

// ...
 
protected function mapRoutes()
{
if (file_exists(base_path('routes/tenant.php'))) {
Route::namespace(static::$controllerNamespace)
->group(base_path('routes/tenant.php'));
}
 
$this->app->booted(function () {
if (file_exists(base_path('routes/tenant.php'))) {
Route::namespace(static::$controllerNamespace)
->group(base_path('routes/tenant.php'));
}
});
}
 
// ...

What does this mean? [tl! add:start]

Modestas avatar

Hi,

The first one just adds routes, but it can cause some problems. That's why on the second example it is wrapped with $this->app->booted(). This prevents issues from appearing.

As for [tl! add:start] - ignore it! This is torchlight malfunctioning (our code highligher) :)

Shadyar Bzhar Othman avatar
Shadyar Bzhar Othman

Thanks!

M avatar

I struggled a bit trying to get the login redirecting to the subdomain using Laravel v12 Livewire Volt starter kit. There is probably an easier way to manually get a user's recent/cached domain but I wasn't able to find it. Any tips?

With the default login it was showing a 404 error as it is redirecting to the central domain's dashboard instead of the subdomain's dashboard.

$domain = auth()->user()->tenants()->firstOrFail()->domains()->firstOrFail()->domain;
 
// $this->redirectIntended(default: route('dashboard', absolute: false), navigate: true);
$this->redirect('//' . Str::of($domain)->rtrim('/') . route('dashboard', absolute: false));

I'm simply picking out the user's first tenant with it's first domain. Moving on.

Modestas avatar

To be fair, this looks like reasonable code. Not sure if it could be improved by a lot (maybe the redirect part, but if it works - it works) :)