Building a Multi-Tenancy Laravel App With Multi-Database using hyn/multi-tenant

Eduardo Geschonke
7 min readMay 24, 2018

--

Hi, In this tutorial I will show how i was able to create an app with multiple databases and visualization of data of each client in an administrative area.

First, some important information:

  • My English in writing mode is not the best (I’m Brazilian);
  • Let’s use the package https://github.com/hyn/multi-tenant
  • Laravel Version: 5.6.23
  • hyn/multi-tenant version: ^5.1
  • The database is MariaDB.

Application setup and package installation

Before we get started, let’s clear some things about the hyn/multi-tenant package:

Directly from the documentation:

Website

You can think of a website as a single mirror of the code base, re-using your default app code. In addition it is also possible to have very tenant specific logic, for instance routes, a vendor folder, media and language files.

Hostname

A hostname is a Fully Qualified Domain Name (for instance sub.example.com). Your application handles incoming requests to specific hostnames. Tenancy inspects these requests and sets up the tenancy environment according to a matching hostname or default fallback.

Customer

A customer is the binding entity between websites and hostnames. They allow freely combining the two. A website and hostname can have a customer, they don’t need to be the same by the way.

In broader terms: A Customer can have many hostnames (subdomains), can also have many websites (each website consists of a database) and a hostname is linked to a website, as a website is linked to a hostname

Let’s start!?

Access the terminal and install your laravel application as usual:

laravel new multi-tenancy

If you are using Laravel Valet, an valet open in the terminal will open the project for you :)

Before installing the multi-tenant package, we need to make some adjustments to the initial setup of laravel.

Inside config/database.php we will change the default connection of mysql to system if not, when installing the package, the application will throw informing that such a database was not properly configured.

Change the default connection to use system connection. This is required by the hyn/multi-tenant package

After changing the configuration, let’s add/change some of the variables inside the .env

Just for convenience I named the database as system_tenancy but you can give the name it fits to you. The variables of lines 8, 9 and 10 will be explained later.

Installing and configuring hyn/multi-tenant

And we’re going to the terminal again. Run the command:

composer require hyn/multi-tenant

If all of the above settings are correct, installation has occurred normally without any warnings.

Now the part that really matters:

php artisan vendor:publish --tag=tenancy

Access the file in config/tenancy.php and we will make some modifications.

All items are well described, but we are only interested in these here:

Disabling abort-without-identified-hostname we will be able to access the application without the need for a subdomain (in the main domain that would be the administrative dashboard).

Here we will also find the variables listed in our .env. Basically they are to auto remove a user and their database whenever we remove a client from the application.

Below we will change the migrations path of each customer/tenant.
It is suggested migrations/tenant but I believe that migrations/customers is more intuitive since the whole application works based on customers /websites/hostnames (explained at the beginning of the tutorial).

With everything properly adjusted, let’s turn the command

php artisan tenancy:install

The command will migrate all existing tables in database/migrations directly into the system_tenancy database. In addtion with these tables the package will add another 03 (customers, Hostnames and Websites).

If everything went well, then now we can configure our customers o/

Creating and configuring our customers

Customers are the soul of the application. Also known as tenants (in the concept of multi-tenancy), each customer must have its database, with its tables and one customer must be isolated from another. Luckily, hyn/multi-tenant has already taken care of this for us. We just need to create a seeder and leave some sample customers properly configured.

This seeder above is responsible for doing all the configuration of the databases. As you can see, we are only using the hyn/multi-tenant repositories.

NOTE: I am using the .job TLD, most likely you are using the .test, so do not forget to change it in the seeder.

After that, go to the terminal and run the command:

php artisan db:seed --class="BuildDatabasesForTenants"

If no error occurs (hopefully), you will see that there are 3 databases created in addition to 3 customers, 3 hostnames and 3 websites in the main database.

websites list
customers list
hostnames list

READY. You can now access the following addresses:

The welcome screen of laravel will appear for both projects, but make no mistake, in every link you are connecting to different database.

Working with customers

With everything in place, let’s create some migrations for customers and test if everything is working accordingly.

Let’s create some folders within the app. You can ignore the files, just create the folders. Oh, I hide the other laravel folders just for easy viewing.

Created the folder structure, let’s create migrations and customers’ factories.

Lots of Commands

php artisan make:migration customer_create_posts_table --path="database/migrations/customers"

Simple migration, nothing unusual. It was just created inside the customers folder.

php artisan make:model Customer/Models/Post

The only difference from this model to the Laravel pattern is that we are using the hyn trait that identifies this model as belonging to a customer connection. Of course, we are relating to the user who is also in the same namespace (exemplified namespace as complete for visualization only).

php artisan make:factory PostFactory

The factory is in the default folder database/factories the only difference is that we are using the customer model.

php artisan make:migration customer_create_users_table --path="database/migrations/customers"
Change the default user factory that is already created.
php artisan make:model Customer/Models/User

Here comes the cool part, this model extends App\Shared\Models\User as Shared but uses the tenant trait as a form of connection. More details of the model below:

php artisan make:model Shared/Models/User

Yes, I know what you’re thinking, “There’s nothing different than the namespace.” That’s right, models within App\Shared\Models have methods, properties and other codes that both (system and customer) will use, however be careful of each model to set the connection (trait) that will use.

php artisan make:model System/Models/User

At this point you should know that UsesSystemConnection means that this model will connect to the main database. Oh, any customer can has relationships to models of the system because it is the main database.

Okay, now let’s create the customer seeder and feed the databases.

php artisan make:seeder TenancyDatabaseSeeder

Simple seeder, just creating some users and adding 3 posts to each of them.

Testing the application and viewing the results

Let’s run the customer seeds and see the databases with all records.

php artisan tenancy:db:seed --class=TenancyDatabaseSeeder

Now let’s visualize the results in the browser.

Create some routes to view the customers and also view the users of each customer.

Go to http://multi-tenancy.job/customers (in my case it is .job) and view all the customers that have been created in the system_tenancy database.

Go to http://foo.multi-tenancy.job/users and view the users, with their related posts

Go to http://bar.multi-tenancy.job/users and view the users, with their related posts

Go to http://baz.multi-tenancy.job/users and view the users, with their related posts

We can say that everything is ready, and from here you can already work. Of course, You have to read the package documentation for more details (https://laravel-tenancy.com/docs/hyn/5.x/index).

BONUS: How to access customer data from the admin dashboard.

Super simple, let’s create an “api” and return the user data using libraries like guzzlehttp/guzzle or kitetail/zttp.

I believe this was a good introduction to how to work with multi-tenants.

In a next tutorial I will teach you how to work with authentication and permissions management on each tenant.

A big hug.

--

--