[Package] Multi-tenant Database Schema Manager for Laravel

Overview

Multi-tenant Database Schema Manager for Laravel

Tenanti allow you to manage multi-tenant data schema and migration manager for your Laravel application.

tests Latest Stable Version Total Downloads Latest Unstable Version License Coverage Status

Version Compatibility

Laravel Tenanti
5.5.x 3.5.x
5.6.x 3.6.x
5.7.x 3.7.x
5.8.x 3.8.x
6.x 4.x
7.x 5.x
8.x 6.x

Installation

To install through composer, run the following command from terminal:

composer require "orchestra/tenanti"

Configuration

Next add the following service provider in config/app.php.

'providers' => [

    // ...
    Orchestra\Tenanti\TenantiServiceProvider::class,
    Orchestra\Tenanti\CommandServiceProvider::class,
],

The command utility is enabled via Orchestra\Tenanti\CommandServiceProvider.

Aliases

To make development easier, you could add Orchestra\Support\Facades\Tenanti alias for easier reference:

'aliases' => [

    'Tenanti' => Orchestra\Support\Facades\Tenanti::class,

],

Publish Configuration

To make it easier to configuration your tenant setup, publish the configuration:

php artisan vendor:publish

Usage

Configuration Tenant Driver for Single Database

Open config/orchestra/tenanti.php and customize the drivers.

<?php

return [
    'drivers' => [
        'user' => [
            'model' => App\User::class,
            'paths' => [
                database_path('tenanti/user'),
            ],
            'shared' => true,
        ],
    ],
];

You can customize, or add new driver in the configuration. It is important to note that model configuration only work with Eloquent instance.

Setup migration autoload

For each driver, you should also consider adding the migration path into autoload (if it not already defined). To do this you can edit your composer.json.

composer.json
{
    "autoload": {
        "classmap": [
            "database/tenant/users"
        ]
    }
}

Setup Tenantor Model

Now that we have setup the configuration, let add an observer to our User class:

<?php 

namespace App;

use App\Observers\UserObserver;
use Orchestra\Tenanti\Tenantor;
use Illuminate\Notifications\Notifiable;
use Orchestra\Tenanti\Contracts\TenantProvider;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable implements TenantProvider
{
    use Notifiable;

    /**
     * Convert to tenantor.
     * 
     * @return \Orchestra\Tenanti\Tenantor
     */
    public function asTenantor(): Tenantor
    {
        return Tenantor::fromEloquent('user', $this);
    }

    /**
     * Make a tenantor.
     *
     * @return \Orchestra\Tenanti\Tenantor
     */
    public static function makeTenantor($key, $connection = null): Tenantor
    {
        return Tenantor::make(
            'user', $key, $connection ?: (new static())->getConnectionName()
        );
    }

    /**
     * The "booting" method of the model.
     */
    protected static function boot()
    {
        parent::boot();

        static::observe(new UserObserver);
    }
}

and your App\Observers\UserObserver class should consist of the following:

<?php 

namespace App\Observers;

use Orchestra\Tenanti\Observer;

class UserObserver extends Observer
{
    public function getDriverName()
    {
        return 'user';
    }
}

Console Support

Tenanti include additional command to help you run bulk migration when a new schema is created, the available command resemble the usage available from php artisan migrate namespace.

Command Description
php artisan tenanti:install {driver} Setup migration table on each entry for a given driver.
php artisan tenanti:make {driver} {name} Make a new Schema generator for a given driver.
php artisan tenanti:migrate {driver} Run migration on each entry for a given driver.
php artisan tenanti:rollback {driver} Rollback migration on each entry for a given driver.
php artisan tenanti:reset {driver} Reset migration on each entry for a given driver.
php artisan tenanti:refresh {driver} Refresh migration (reset and migrate) on each entry for a given driver.
php artisan tenanti:queue {driver} {action} Execute any of above action using separate queue to minimize impact on current process.
php artisan tenanti:tinker {driver} {id} Run tinker using a given driver and ID.

Multi Database Connection Setup

Instead of using Tenanti with a single database connection, you could also setup a database connection for each tenant.

Configuration Tenant Driver for Multiple Database

Open config/orchestra/tenanti.php and customize the drivers.

<?php

return [
    'drivers' => [
        'user' => [
            'model'  => App\User::class,
            'path'   => database_path('tenanti/user'),
            'shared' => false,
        ],
    ],
];

By introducing a migration config, you can now setup the migration table name to be tenant_migrations instead of user_{id}_migrations.

Database Connection Resolver

For tenanti to automatically resolve your multiple database connection, we need to setup the resolver. You can do this via:

<?php namespace App\Providers;

use Orchestra\Support\Facades\Tenanti;

class AppServiceProvider extends ServiceProvider
{
    public function boot()
    {
        Tenanti::connection('tenants', function (User $entity, array $config) {
            $config['database'] = "acme_{$entity->getKey()}"; 
            // refer to config under `database.connections.tenants.*`.

            return $config;
        });
    }
}

Behind the scene, $config will contain the template database configuration fetch from "database.connections.tenants" (based on the first parameter tenants). We can dynamically modify the connection configuration and return the updated configuration for the tenant.

Setting Default Database Connection

Alternatively you can also use Tenanti to set the default database connection for your application:

use App\User;
use Orchestra\Support\Facades\Tenanti;

// ...

$user = User::find(5);

Tenanti::driver('user')->asDefaultConnection($user, 'tenants_{id}');

Most of the time, this would be use in a Middleware Class when you resolve the tenant ID based on Illuminate\Http\Request object.

Comments
  • Too Many Connections

    Too Many Connections

    I'm trying to migrate to 1500+ database by this command php artisan tenanti:migrate

    but all the connection still opened and make usage of ram very high

    and the connections is more than 1500+ and still opened.

    I want after each migration database the connection is closed

    open for contribution nice to have 
    opened by ghost 16
  • Support uuid as tenant database id

    Support uuid as tenant database id

    I see that your implementation bind the database with Entity Id, which easily be conflicted after a reset migration. I propose to implement the uuid method instead, which can be randomize uniquely, or an option to connection methods (asConnection) on Orchestra\Tenanti\Migrator\Operation trait so that developer can by pass their own database name, instead of restrictedly following the '_{id}' pattern.

    opened by nguyenhaiphan 11
  • Broken setupDriverConfig

    Broken setupDriverConfig

    I'm not sure if this will affect normal installation of tenanti since I'm using it in more complex way than the standard behavior. But judging from the code in the TenantiManager::connection

    the array set for the $this->config will never have driver key thus when TenantiSetupDriverConfig is called it will always return null

            // This will always return null since there are no array key by driver name ever set
            if (isset($this->config[$driver])) {
                return;
            }
    
            // this will also always return null since no drivers key ever set
            if (is_null($config = Arr::pull($this->config, "drivers.{$driver}"))) {
                return;
            }
    
    

    When changed to :

            if (is_null($config = Arr::get($this->config, "connection.template"))) {
                return;
            }
    

    it will work again as expected.

    not sure if this is a bug or just my installation that need this, so I didnt make proper fork and pull request.

    Thank you for the great plugin btw

    question 
    opened by duckzland 11
  • Issue with laravel 6.x/7.x/8 Tenanti Version 5.0&6

    Issue with laravel 6.x/7.x/8 Tenanti Version 5.0&6

    • Tenanti Version: ^5.0
    • Laravel Version: 7.x
    • PHP Version: 7.4
    • Database Driver & Version: mysql-5.7.31

    Description:

    When I install tenanti version getting an error in service provider.

    Illuminate\Contracts\Container\BindingResolutionException Unable to resolve dependency [Parameter #1 [ array $config ]] in class App\Providers\AppServiceProvider

    Steps To Reproduce:

    need feedback 
    opened by muralibobby35 10
  • Add dynamic migrations

    Add dynamic migrations

    Usecase

    User many to many Modules For each User I want to migrate just the modules that the user owns, for that I would need to call loadMigrationsFrom however that's not possible since tenanti:migrate runs it's own separate migrator.

    This PR add's a method loadMigrationsFrom to the Operation trait (Factory class), and also injects the Factory class on the ServiceProvider callback, this way we can load migrations dynamically, example:

    Tenanti::connection('tenants', function (User $entity, array $config, $database, $factory) {
                User::$tenant = $entity;
    
                $this->mapMigrations($entity, $factory);
    
                $config['database'] = $entity->database;
    
                return $config;
            });
    
    public function mapMigrations($entity, $factory) {
            $modules = $entity->modules;
    
            if($modules->first() !== null) {
                foreach ($modules as $m) {
                    $factory->loadMigrationsFrom($m->migrationPath, $entity);
                }
            }
        }
    
    opened by fernandobandeira 10
  • Migrations in Tenant Databases

    Migrations in Tenant Databases

    maybe i'm short in knowledge but i'm having problems with the migrations of the tables in the tenant databases. my primary database is main and the tenant databases are names of companies, i get the value from a custom field in the table users (company).

    I have the driver migrations in this path.

    'drivers' => [
            'user' => [
                'model'  => App\User::class,
                'path'   => database_path('tenanti/user'),
                'shared' => false,
            ],
        ],
    

    And i want to migrate with this sentence php artisan tenanti:migrate user but i get this error.

    [ErrorException]
    Creating default object from empty value
    
    

    do you know what is happening? do you need more information?

    I thank you in advance. David

    question 
    opened by TorresDavid 5
  • Give devs a better Tenanti install experience

    Give devs a better Tenanti install experience

    Add laravel providers and aliases to extra key in composer.json. This will allow for Laravel to easily auto-discover the packages and remove the requirement for developers to manually add the providers and aliases to their app.

    opened by dongilbert 4
  • How to queue a specify tenant

    How to queue a specify tenant

    I have a multi database tenanti using orchestral, i want to work with queue, i'm current using database driver, but the problem is that everytime i run the queue fail with message of "No database Selected"

    opened by gabrielbuzziv 4
  • [3.3] Migration runDown isn't working

    [3.3] Migration runDown isn't working

    When using reset, or refresh, for example, the package isn't running the runDown migration, instead it's always pretending to run the migration and dumps the result on the console.

    I've checked and the content that is being passed to the $pretend variable is

    [
        'pretend' => false,
    ]
    

    However on Migrator.php it's checking it like:

    if ($pretend) {
        return $this->pretendToRun($instance, 'down');
    }
    

    I'll try to create a PR for this, but i'm not sure if this also happens with lower versions of the package so I'm posting here beforehand so you can check the issue too...

    opened by fernandobandeira 4
  • Error with Middleware

    Error with Middleware

    I'm getting an InvalidArgumentException thrown when I try to use the example in the docs for a multi-database setup:

        public function handle($request, Closure $next)
        {
            // Get account id
            $accountId = $request->route()->parameter('accountId');
    
            // Get account from id
            $account = Account::findOrFail($accountId);
    
            \Tenanti::driver()->asDefaultConnection($account, 'tenants_{id}');
    
            return $next($request);
        }
    

    I get

    InvalidArgumentException in TenantiManager.php line 52:
    Default driver not implemented.
    

    Am I doing this the wrong way?

    question 
    opened by Azuka 4
  • Dump-Autoload

    Dump-Autoload

    screen shot 2015-04-13 at 1 59 28 am

    Upon running php artisan tenanti:make {driver} {migration-name} I get the above. Seems to stem from line 67 in tenanti/src/Console/MigrateMakeCommand.php.

    I changed line 67 from: $this->call('dump-autoload');

    to: $this->call('clear-compiled');

    This fixed the issue on Laravel 5.0.16. I can PR a fix for this if you like.

    bug 
    opened by aejnsn 4
Releases(v6.3.0)
  • v6.3.0(Aug 14, 2021)

  • v6.2.0(May 5, 2021)

  • v6.1.0(Apr 18, 2021)

  • v6.0.0(Nov 17, 2020)

  • v5.0.3(Nov 17, 2020)

  • v5.0.2(Apr 6, 2020)

  • v5.0.1(Apr 3, 2020)

    Changes

    • Throw exception when trying to make migration file without --table option on shared database configuration.

    Fixes

    • Fixes migration stub files.
    Source code(tar.gz)
    Source code(zip)
  • v5.0.0(Apr 3, 2020)

    Added

    • Added Orchestra\Tenanti\Migrator\MigrationWriter.
    • Added usingConnection() and outputUsing() helper method to Orchestra\Tenanti\Migrator\Migrator.

    Changes

    • Update support for Laravel Framework v7.
    • Replace the following on Orchestra\Tenanti\Migrator\Operation:
      • executeFor() with find().
      • executeForEach() with each().
      • getModel() with model().
      • getModelName() with modelName().
      • resolveMigrator() with migrator().
      • asConnection with connectionName()
      • bindWithKey() with nomalize().
      • resolveConnection() with connection().
      • resolveMigrationTableName() with migrationTableName().
      • getTablePrefix() with tablePrefix().
    Source code(tar.gz)
    Source code(zip)
  • v4.1.0(Jan 4, 2020)

  • v4.0.0(Sep 3, 2019)

    Changes

    • Update support for Laravel Framework 6.0+.
    • Improves support for Lumen Framework.

    Breaking Changes

    • Configuration file options for path need to be updated to paths which only access an array or migration paths.
    • Rename Orchestra\Tenanti\TenantiManager::getConfig() to Orchestra\Tenanti\TenantiManager::config().
    Source code(tar.gz)
    Source code(zip)
  • v3.8.3(Aug 4, 2019)

    Changes

    • Use static function rather than function whenever possible, the PHP engine does not need to instantiate and later GC a $this variable for said closure.
    Source code(tar.gz)
    Source code(zip)
  • v3.8.2(Jul 6, 2019)

  • v3.8.1(Apr 28, 2019)

  • v3.8.0(Mar 31, 2019)

  • v3.7.1(Mar 13, 2019)

    Changes

    • Improve performance by prefixing all global functions calls with \ to skip the look up and resolve process and go straight to the global function.
    Source code(tar.gz)
    Source code(zip)
  • v3.7.0(Nov 19, 2018)

    Changes

    • Update support for Laravel Framework v5.7.
    • Disconnect database after preparing migrations table for each tenant.
    • Allow tenanti queue connection to be configurable via config and environment file.
    Source code(tar.gz)
    Source code(zip)
  • v3.6.6(Nov 8, 2018)

    Added

    • Add Orchestra\Tenanti\TenantiManager::config() helper method.

    Changes

    • Disconnect database after preparing migrations table for each tenant.
    Source code(tar.gz)
    Source code(zip)
  • v3.5.2(Nov 7, 2018)

  • v3.6.5(Aug 11, 2018)

  • v3.6.4(Aug 11, 2018)

  • v3.6.3(Aug 1, 2018)

    Changes

    • Add --delay options to tenanti:queue command.

    Fixes

    • Readd missing --force options to tenanti:queue command due to Illuminate\Console\ConfirmableTrait usage.
    Source code(tar.gz)
    Source code(zip)
  • v3.6.2(Jul 30, 2018)

    Added

    • Added Orchestra\Tenanti\Contracts\TenantProvider.

    Changes

    • Allow Orchestra\Tenanti\Model::tenant to accept Orchestra\Tenanti\Contracts\TenantProvider.
    Source code(tar.gz)
    Source code(zip)
  • v3.6.1(Jul 28, 2018)

  • v3.6.0(May 2, 2018)

  • v3.5.1(May 2, 2018)

    Added

    • Added Orchestra\Tenanti\Tenantor.
    • Added Orchestra\Tenanti\Eloquent\Tenantee trait.

    Fixes

    • Fixes Orchestra\Tenanti\Contracts\Factory contracts.
    Source code(tar.gz)
    Source code(zip)
  • v3.5.0(Nov 13, 2017)

    Changes

    • Update support for Laravel Framework v5.5.
    • Utilize fetching instance of model collection via cursor().

    Fixes

    • Tenant creation and deletion job should attempt to use given model instead of querying the database again.
    • Reset database connection after migration if possible.
    Source code(tar.gz)
    Source code(zip)
  • v3.4.2(Nov 13, 2017)

    Fixes

    • Tenant creation and deletion job should attempt to use given model instead of querying the database again.
    • Reset database connection after migration if possible.
    Source code(tar.gz)
    Source code(zip)
  • v3.4.1(Sep 17, 2017)

    Added

    • Allow to load dynamic migration path via Orchestra\Tenanti\Migrator\Factory::loadMigrationsFrom(). (#44)

    Changes

    • Re-enable to use php artisan tenanti:queue with --queue name option.

    Deprecated

    • Deprecate --force option on php artisan tenanti:queue.
    Source code(tar.gz)
    Source code(zip)
  • v3.4.0(Mar 29, 2017)

  • v3.3.5(Mar 10, 2017)

Owner
Orchestra Platform
Orchestra Platform provide all the boilerplate for your application, so you can create awesomeness.
Orchestra Platform
Laravel Migrations Generator: Automatically generate your migrations from an existing database schema.

Laravel Migrations Generator Generate Laravel Migrations from an existing database, including indexes and foreign keys! Upgrading to Laravel 5.4 Pleas

Bernhard Breytenbach 3.3k Dec 30, 2022
An easy-to-use Artisan command to create a new database schema.

Laravel Create DB This package adds an easy-to-use Artisan command to your application that allows you to create a new database schema. The package is

Aron Rotteveel 11 Dec 29, 2022
This package provides a framework-agnostic database backup manager for dumping to and restoring databases from S3, Dropbox, FTP, SFTP, and Rackspace Cloud

Database Backup Manager This package provides a framework-agnostic database backup manager for dumping to and restoring databases from S3, Dropbox, FT

Backup Manager 1.6k Dec 23, 2022
Pure PHP NoSQL database with no dependency. Flat file, JSON based document database.

Please give it a Star if you like the project ?? ❤️ SleekDB - A NoSQL Database made using PHP Full documentation: https://sleekdb.github.io/ SleekDB i

Kazi Mehedi Hasan 745 Jan 7, 2023
SleekwareDB is a NoSQL database storage service. A database storage service that can be used for various platforms and is easy to integrate.

SleekwareDB is a NoSQL database storage service. A database storage service that can be used for various platforms and is easy to integrate. NoSQL API

SleekwareDB 12 Dec 11, 2022
A mysql database backup package for laravel

Laravel Database Backup Package This package will take backup your mysql database automatically via cron job. Installing laravel-backup The recommende

Mahedi Hasan Durjoy 20 Jun 23, 2021
Driver to seamlessly integrate the Backup Manager into Laravel applications.

Laravel Driver for the Database Backup Manager This package pulls in the framework agnostic Backup Manager and provides seamless integration with Lara

Backup Manager 636 Dec 30, 2022
A package for using Google Datastore as a database driver

Laravel Eloquent for Google Datastore A package for using Google Datastore as a database driver. By using this package, you can use query builder and

A1 Comms Ltd 3 Apr 26, 2022
PHP Object Model Manager for Postgresql

POMM: The PHP Object Model Manager for Postgresql Note This is the 1,x version of Pomm. This package is not maintained anymore, the stable Pomm 2.0 is

Grégoire HUBERT 161 Oct 17, 2022
Satis composer repository manager with a Web UI

Satisfy Satis Composer repository manager with a simple web UI. Introduction Satisfy provides: a Web UI: A CRUD to manage your satis configuration fil

Ludovic Fleury 470 Dec 28, 2022
Laravel Thermite is an extended PostgreSQL Laravel database driver to connect to a CockroachDB cluster.

Laravel Thermite Laravel Thermite is an extended PostgreSQL Laravel database driver to connect to a CockroachDB cluster. ?? Supporting If you are usin

Renoki Co. 9 Nov 15, 2022
[READ ONLY] Subtree split of the Illuminate Database component (see laravel/framework)

Illuminate Database The Illuminate Database component is a full database toolkit for PHP, providing an expressive query builder, ActiveRecord style OR

The Laravel Components 2.5k Dec 27, 2022
Adjacency List’ed Closure Table database design pattern implementation for the Laravel framework.

ClosureTable This is a database manipulation package for the Laravel 5.4+ framework. You may want to use it when you need to store and operate hierarc

Yan Ivanov 441 Dec 11, 2022
A drop-in library for certain database functionality in Laravel, that allows for extra features that may never make it into the main project.

Eloquence Eloquence is a package to extend Laravel's base Eloquent models and functionality. It provides a number of utilities and classes to work wit

Kirk Bushell 470 Dec 8, 2022
Laravel 5 - Repositories to abstract the database layer

Laravel 5 Repositories Laravel 5 Repositories is used to abstract the data layer, making our application more flexible to maintain. See versions: 1.0.

Anderson Andrade 4k Jan 6, 2023
A Redis based, fully automated and scalable database cache layer for Laravel

Lada Cache A Redis based, fully automated and scalable database cache layer for Laravel Contributors wanted! Have a look at the open issues and send m

Matt 501 Dec 30, 2022
Adminer database management tool for your Laravel application.

Laravel Adminer Adminer database management tool for your Laravel application. Table of Contents Introduction Features Installation CSRF token middlew

Khalid Moharrum 45 Jul 25, 2022
Laravel Code Generator based on MySQL Database

Laravel Code Generator Do you have a well structed database and you want to make a Laravel Application on top of it. By using this tools you can gener

Tuhin Bepari 311 Dec 28, 2022
Tablavel - A simple Database Client for Laravel

Tablavel - A simple Database Client for Laravel Table of Contents About Getting Started Usage Contributing About This solves a simple problem. Know th

null 13 Feb 27, 2022