Multi-Tenancy for Laravel and Laravel-Doctrine.

This library provides the necessary infra-structure for a complex multi-tenant application. Multi-tenancy allows an application to be silo'd into protected areas by some form of tenant identifier. This could be by sub-domain, URL parameter or some other scheme.

Article image for: Multi-Tenancy for Laravel and Laravel-Doctrine

Types of Tenancy.

Terminology
Types of Tenancy
Getting Started
Security Models
Routing
Middleware & Views
Issues / Links

Github Print

Forms of Tenancy

This library provides the following tenant setups, in increasing order of complexity:

  • multi-account (single App), URI tenancy
  • multi-site, domain name tenancy
  • multi-site with multi-account tenancy

Multi-Account, URI Tenancy

The simplest case is a single App that has multi-account tenants. All users must be registered and the tenancy is defined by the tenant_creator_id in the route URI. The tenancy is resolved on User login meaning that this offers the smallest impact in your application.

If you need to serve static, non-tenant pages or your app does not need theme support, this is the preferred tenancy model.

Multi-Site, Domain Name Tenancy

Increasing in complexity, the next level is domain-name based tenancy. Multiple sites running from a single app folder. This is usually some form of white-labelling setup i.e. the same application is re-skinned with different branding but the underlying app is practically the same.

Note: this is a substantial increase in difficulty from single app tenancy. You will need to change the Application instance in /bootstrap/app.php to use:

Somnambulist\Tenancy\Foundation\TenantAwareApplication

Note: you have to remove RouteServiceProvider and add TenantRouteResolver middleware.

Note: you must ensure that any caches you use can handle per-site caching.

In addition, this form of tenancy requires a middleware to run all the time to resolve the current tenant information before any users login or the main app actually runs. If using a database for the tenant source, this could increase site overhead and a high-performance cache is highly recommended for production environments e.g.: APCu or an in memory-cache that persists between requests to reduce the overhead of the tenant resolution.

A file-system repository can be easily created instead of using the database, or a combination of both where a cache file is generated when the tenant sources change.

In multi-site, changes must be made to your app config:

  • view.paths: should have the default path changed to views/default
  • view.compiled: should have the default path changed to views/default

When creating your app, you will need to create a "default" view theme and then mirror this for each domain you serve from the app. The view folder should be named after the domain that is bound to the tenant.

www.example.com -> resources/views/www.example.com

Your views folder will end up looking like:

resources/views/default
resources/views/www.example.com
resources/views/store.example2.com
resources/views/store.example3.com

Once the tenant information has been resolved, several updates are made to the container configuration:

  • app.url is replaced with the current host domain (not resolved domain name)
  • template paths are re-computed as a hierarchy and the finder reset

Template path order is reset to:

  • tenant creator domain
  • tenant owner domain (if different)
  • default / existing paths

This way templates should be evaluated from most specific to least specific.

Note: auth.tenant is initialised with the tenant owner / creator and a NullUser.

Multi-Site with Multi-Account Tenancy

Note: this is the most complex scenario. TenantAwareApplication is required.

Note: you have to remove RouteServiceProvider and add TenantRouteResolver middleware.

Note: you must ensure that any caches you use can handle per-site caching.

This is a combination of both methods where there are multiple tenants per multi-site. In this configuration there are limitations on the security that can be implemented unless a custom implementation is made:

  • there is only one tenant owner per domain
  • all tenant owners should have the closed security model
  • all tenant creators should have the closed security model

It is possible to allow further tenanting however this would have to be a custom implementation as your tenant creator would have to allow child tenants and implement a security model that is appropriate in this situation. One possible example would be to cascade up through the parents to set the tenant owner (which would be the domain tenant owner).

This setup has the highest impact on site performance and requires users login to resolve their tenancy. As such, this essentially results in double tenancy resolution.

This setup is not recommended as it could lead to hard to diagnose issues, but is included as it is technically feasible with the current implementation.

Note: auth.tenant is initialised with the tenant owner / creator and a NullUser but after User authentication will be updated with the current, authenticated user and any changes to the creator tenant as needed. The owner tenant should still be the same as the creator must be a child of the owner.