Skip to content

mehov/cakephp-multitenancy

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

30 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Multitenancy for CakePHP 5

This plugin extends cakedc/users and introduces customer accounts and ability to scope application tables by specific customers (tenants).

For CakePHP 3, see (now archived) pronique/multitenant.

Read more about Multitenancy: en.wikipedia.org/wiki/Multitenancy.

Use case

You're building a SaaS application, and you want records in some tables to belong to multiple users through shared accounts. You want every query to these tables to by default check ownership.

Installation

Require this plugin using composer:

composer require bakeoff/multitenancy

Create required tables:

bin/cake migrations migrate -p Multitenancy

In your application's src/Application.php:

$this->addPlugin(\Bakeoff\Multitenancy\Plugin::class);

Usage

Configuring tables

Add the TenantScope Behavior to a table where records should belong to an account. The account ID may be stored in a column in the same table, or it may be stored in another table, associated with the current one.

  • Account ID is already stored as account_id, or I'm willing to create the column

    By default, TenantScope expects the table where it's added to have a column named account_id. If you already have that column, or if you're willing to create it, you don't have to explicitly provide the column name when adding the behavior.

    $this->addBehavior('Bakeoff/Multitenancy.TenantScope');
  • Account ID is in a different column, but in the same table

    If you want to use a different column, pass it as accountField. Do not prepend it with the name of the table.

    $this->addBehavior('Bakeoff/Multitenancy.TenantScope', [
        'accountField' => 'another_column_with_account_id'
    ]);
  • Account ID is in a different table

    If you need to check against a column in another table, write it in dot notation. The current table where TenantScope is added must be associated with the other table, either directly or through intermediary tables.

    For example, Articles (referred to as $this below) belongsTo Categories belongsTo Users, and we're checking against the column linked_account in Users:

    // in ArticlesTable.php
    $this->addBehavior('Bakeoff/Multitenancy.TenantScope', [
        'accountField' => 'Categories.Users.linked_account'
    ]);

Either of the above will ensure a where() condition is added to every find() call on the current table, except e.g. uniqueness checks which use exists() internally.

User interface

Once the Behavior is added to a table, every find() call to that table will include a condition for accountField. The account it will be looking for needs to be in a user session: either set directly by user, or automatically by just looking up the last accessed account for that user.

Choosing an account

Direct your users to \Cake\Routing\Router::url(['_name' => 'Bakeoff/Multitenancy:ChooseAccount']) where they can choose an existing accout or create a new one.

Use <?= $this->element('Bakeoff/Multitenancy.account') ?> in your view templates to display current account or link to the Choose Account page.

Setting an account

If you wish to manually set a specific account to be used.

// Load the accounts table. If you're in a controller, use fetchTable()
$accountsTable = $this->fetchTable('Bakeoff/Multitenancy.Accounts');
// Select the account
$account = $accountsTable->find('all')
    ->leftJoinWith('Users')
    ->where(['Users.id' => $user->get('id')])
    ->orderBy('accessed DESC')
    ->first();
// Update last accessed timestamp
$accountsTable->setAccessedNow($account);
// Cache a copy of this account we just found to session
\Bakeoff\Multitenancy\Account::set($account);

Automatically picking up last used account (Default)

See \Bakeoff\Multitenancy\Model\Behavior\TenantScopeBehavior::detectAccount()

Stopping the Behavior

In some cases you would want to stop checking the ownership for records in a specific table, and just get all entries instead. To do that, simply remove the behavior from that table.

$this->Articles->removeBehavior('TenantScope');

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages