Vue.js

Multi tenancy in vue js using tenancyforlaravel package

I implement multi tenancy multi database using subdomain in laravel using the tenancyforlaravel package, and now I want to implement it with vue js, but I don't know how the tenant identification work or what changes

Even if you have an idea tell me, thanks!

shadyar
shadyar
0
7
850
alex Member
alex
Moderator

Are you using an entirely separate client, or using Vue within Laravel? If you give me a few more details about how your stack is set up, I'll be able to point you in the right direction.

shadyar
shadyar

Thank you alex, I'm using separate client SPA using vue.

alex Member
alex
Moderator

Thanks. In this case, you’d have pretty much replicate the ‘switching’ of a tenant for Vue specifically.

So, if you’re authenticating as a specific tenant, that authentication token/cookie would work as usual. But, for switching between tenants you’d need to build the mechanism manually (I’m not aware of any packages that automate this).

Could you write out a list of things you need to accomplish? I’ll pop them down in notes for a course and then get the code to you before recording.

shadyar
shadyar

Thanks, as I said I want a way to ndentify tenant by their subdomain and I created this middleware and by that The frontend just send the request, is it a good way in your opinion?

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
use Stancl\Tenancy\Resolvers\DomainTenantResolver;
use Stancl\Tenancy\Contracts\TenantCouldNotBeIdentifiedException;
use Stancl\Tenancy\Middleware\IdentificationMiddleware;
use Stancl\Tenancy\Tenancy;

class InitializeTenancyBySubDomainOrigin extends IdentificationMiddleware
{
    public static $subdomainIndex = 0;

    public static $onFail;

    protected $tenancy;

    protected $resolver;

    public function __construct(Tenancy $tenancy, DomainTenantResolver $resolver)
    {
        $this->tenancy = $tenancy;
        $this->resolver = $resolver;
    }

    public function handle(Request $request, Closure $next)
    {
        $origin = $request->headers->get('Origin');
        $host = parse_url($origin, PHP_URL_HOST);

        if ($host) {
            $subdomain = $this->extractSubdomain($host);

            if ($subdomain instanceof \Exception) {
                $onFail = static::$onFail ?? function ($e) {
                    throw $e;
                };

                return $onFail($subdomain, $request, $next);
            }

            try {
                $tenant = $this->resolver->resolve($subdomain);
                $this->tenancy->initialize($tenant);
            } catch (TenantCouldNotBeIdentifiedException $e) {
                $onFail = static::$onFail ?? function ($e) {
                    throw $e;
                };

                return $onFail($e, $request, $next);
            }

            return $next($request);
        }

        return static::$onFail ? (static::$onFail)($request, $next) : response('Subdomain not found', 400);
    }

protected function extractSubdomain($host)
    {
        $parts = explode('.', $host);

        $isLocalhost = count($parts) === 1;
        $isIpAddress = count(array_filter($parts, 'is_numeric')) === count($parts);

        $isACentralDomain = in_array($host, config('tenancy.central_domains'), true);
        $thirdPartyDomain = !Str::endsWith($host, config('tenancy.central_domains'));

        if ($isLocalhost || $isIpAddress || $isACentralDomain || $thirdPartyDomain) {
            return new \Exception("Not a valid subdomain: {$host}");
        }

        return $parts[$this->subdomainIndex];
    }
}
alex Member
alex
Moderator

Looks good to me! Does this work nicely?

The only thing I’d do differently is the way you extract the details of the host in the extractSubdomain method.

Instead of using explode, I’d use parse_url

shadyar
shadyar

Thank you very much, I couldn't test it because the package api configuration doesn't work as expected and it does not read routes/tenant.php file when a request came

alex Member
alex
Moderator

Can you explain more how it's not working?