In this post I will show you how I converted my normal Codeigniter application into a multi-tenant system.(first step to a SaaS implementation)
Note - This implementation is a separate DB multi-tenancy implementation.
Lets say we have an up and running CI application name ci_app, with the directory structure like this
./application
./application/config
./application/...so many other important directories
./asset
./asset/js
./asset/images
./asset/css
./system
./index.php
which is accessed through browser like http://localhost/ci_app
So to implement the multi-tenant arch we are most concerned about the following files, and we will be editing them
Here is what we need to put in tenant_1/config.php
/* CORE APP config */
$_SSS['app']['base_dir'] = $_SERVER['DOCUMENT_ROOT'];
$_SSS['app']['tenant_folder'] = 'tenant_1'; //folder name
$_SSS['app']['app_folder'] = 'ci_app'; //folder name
$_SSS['app']['asset_folder'] = 'tenant_1_asset'; //folder name with a trailing slash only if there is an asset folder else leave blank
$_SSS['app']['system_path'] = $_SSS['app']['base_dir'].'/'.$_SSS['app']['app_folder'] .'/system/'; //will be sed by the CI index file
$_SSS['app']['application_path'] = $_SSS['app']['base_dir'].'/'.$_SSS['app']['app_folder'] .'/application/'; //will be used by the CI index file
$_SSS['app']['base_url'] = 'http://'.$_SERVER["SERVER_NAME"].'/'.$_SSS['app']['app_folder'];
$_SSS['app']['tenant_url'] = 'http://'.$_SERVER["SERVER_NAME"].'/'.$_SSS['app']['tenant_folder'];
///The above config variable are defined to create the basic paths and URLs required for the app to work, which are defined just below
/* Main Paths and urls */
if(! defined('APP_TENANTPATH')){
define('APP_TENANTPATH', $_SSS['app']['base_dir'].'/'.$_SSS['app']['tenant_folder'].'/');//this will be used by ci_app config files to load this config file
define('APP_TENANTURL', $_SSS['app']['tenant_url']);//this the path that will show on the browser and will be used for accessing the controllers and methods
define('APP_ASSETURL', $_SSS['app']['base_url'].'/'.$_SSS['app']['asset_folder']);//this will be required to access tenant specific assets}
/* DB config */
$_SSS['app']['db_host'] = 'my_db_host';
$_SSS['app']['db_user'] = 'tenant_1_user';
$_SSS['app']['db_pass'] = 'tenant_1_pass';
$_SSS['app']['db_name'] = 'tenant_1_db';
$_SSS['app']['db_driver'] = 'mysql';
/* CI specific params*/
$_SSS['ci']['db_cache'] = FALSE;
//include any other config files here which have configurations in $_SSS variable
//like email.php etc
Here are the changes required in the index.php
<?php
require_once('./config.php');//first thing, include the tenant_1/config.php here
$system_path = $_SSS['app']['system_path']; //changed from $system_path = 'system';
$application_folder = $_SSS['app']['application_path']; //changed from $application_folder = 'application';
//the above 2 variables are coming from the included tenant_1/config.php file
So now instead of opening the app like this
http://localhost/ci_app we will access it like this http://localhost/tenant_1
And because we are calling the tenant_1 directory we require to have the Codeigniter framework to be available for this directory and this is exactly what we are achieving by doing the above mentioned changes in the index.php file copied from the ci_app directory
The browser will open the index.php which will
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
if (defined('APP_TENANTPATH'))//lets include the tenant_1/config.php
require(APP_TENANTPATH.'config.php');
And as we did in the index.php change the variable definition as per your business need
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
if (defined('APP_TENANTPATH'))//lets include the tenant_1/config.php
require(APP_TENANTPATH.'config.php');
$db['default']['hostname'] = $_SSS['app']['db_host'];
$db['default']['username'] = $_SSS['app']['db_user'];
$db['default']['password'] = $_SSS['app']['db_pass'];
$db['default']['database'] = $_SSS['app']['db_name'];
$db['default']['dbdriver'] = $_SSS['app']['db_driver'];
//we can have more/different config items as required and set in the tenant config file
This is one way of achieving the Multi-tenancy with CI.
Next thing to do would be to make the asset_url available to the application as the base_url() and the site_url wont be sufficient enough to give the path for tenant linked assets. This can be achieved by
creating a helper function which gets the APP_ASSETURL if it is set. and use this helper function to load the asset files.
Now you just have to replicate the tenant_* folders and change the configs etc to suit the requirements and access the multi-tenancy enabled app like http://localhost/tenant_*
Or create subdomain and link them to tenant_* folders to access something like this
http://tenant_*.myappworld.com
Thanks for reading,
Sandeep
Check my Analytics app here
Note - This implementation is a separate DB multi-tenancy implementation.
Lets say we have an up and running CI application name ci_app, with the directory structure like this
./application
./application/config
./application/...so many other important directories
./asset
./asset/js
./asset/images
./asset/css
./system
./index.php
which is accessed through browser like http://localhost/ci_app
So to implement the multi-tenant arch we are most concerned about the following files, and we will be editing them
- ./index.php
- ./application/config/config.php
- ./application/config/database.php
- Create a tenant folder in your www root directory, lets say tenant_1
- Cut the ./index.php from ci_app and paste it in tenant_1 directory
- Create a blank file config.php in tenant_1 directory
- Create a uploads directory for file uploads
- Create some tenant specific asset directory lets say tenant_1_asset
tenant_1/config.php
The config.php file in tenant_1 folder is the main config file containing vital config data like the system, app and asset path, database configurations, and any other config for that matter which are tenant dependentHere is what we need to put in tenant_1/config.php
/* CORE APP config */
$_SSS['app']['base_dir'] = $_SERVER['DOCUMENT_ROOT'];
$_SSS['app']['tenant_folder'] = 'tenant_1'; //folder name
$_SSS['app']['app_folder'] = 'ci_app'; //folder name
$_SSS['app']['asset_folder'] = 'tenant_1_asset'; //folder name with a trailing slash only if there is an asset folder else leave blank
$_SSS['app']['system_path'] = $_SSS['app']['base_dir'].'/'.$_SSS['app']['app_folder'] .'/system/'; //will be sed by the CI index file
$_SSS['app']['application_path'] = $_SSS['app']['base_dir'].'/'.$_SSS['app']['app_folder'] .'/application/'; //will be used by the CI index file
$_SSS['app']['base_url'] = 'http://'.$_SERVER["SERVER_NAME"].'/'.$_SSS['app']['app_folder'];
$_SSS['app']['tenant_url'] = 'http://'.$_SERVER["SERVER_NAME"].'/'.$_SSS['app']['tenant_folder'];
///The above config variable are defined to create the basic paths and URLs required for the app to work, which are defined just below
/* Main Paths and urls */
if(! defined('APP_TENANTPATH')){
define('APP_TENANTPATH', $_SSS['app']['base_dir'].'/'.$_SSS['app']['tenant_folder'].'/');//this will be used by ci_app config files to load this config file
define('APP_TENANTURL', $_SSS['app']['tenant_url']);//this the path that will show on the browser and will be used for accessing the controllers and methods
define('APP_ASSETURL', $_SSS['app']['base_url'].'/'.$_SSS['app']['asset_folder']);//this will be required to access tenant specific assets}
/* DB config */
$_SSS['app']['db_host'] = 'my_db_host';
$_SSS['app']['db_user'] = 'tenant_1_user';
$_SSS['app']['db_pass'] = 'tenant_1_pass';
$_SSS['app']['db_name'] = 'tenant_1_db';
$_SSS['app']['db_driver'] = 'mysql';
/* CI specific params*/
$_SSS['ci']['db_cache'] = FALSE;
//include any other config files here which have configurations in $_SSS variable
//like email.php etc
tenant_1/index.php
As we have now created the tenant specific configuration file we need a mechanism to load the config variables into our ci_app. For with we need to amend the index.php copied from the ci_app directory.Here are the changes required in the index.php
<?php
require_once('./config.php');//first thing, include the tenant_1/config.php here
$system_path = $_SSS['app']['system_path']; //changed from $system_path = 'system';
$application_folder = $_SSS['app']['application_path']; //changed from $application_folder = 'application';
//the above 2 variables are coming from the included tenant_1/config.php file
So now instead of opening the app like this
http://localhost/ci_app we will access it like this http://localhost/tenant_1
And because we are calling the tenant_1 directory we require to have the Codeigniter framework to be available for this directory and this is exactly what we are achieving by doing the above mentioned changes in the index.php file copied from the ci_app directory
The browser will open the index.php which will
- include the tenant config
- load the variables required by CI
- and finally load CI
ci_app/application/config/config.php
We need to include the tenant specific config file so that the ci_app config file can access the variable defined there, and this we achieve by changing the following<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
if (defined('APP_TENANTPATH'))//lets include the tenant_1/config.php
require(APP_TENANTPATH.'config.php');
And as we did in the index.php change the variable definition as per your business need
ci_app/application/config/database.php
As we did for the config file just above, we need to pass on the DB configuration variables to database.php as well. so here are the changes for it<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
if (defined('APP_TENANTPATH'))//lets include the tenant_1/config.php
require(APP_TENANTPATH.'config.php');
$db['default']['hostname'] = $_SSS['app']['db_host'];
$db['default']['username'] = $_SSS['app']['db_user'];
$db['default']['password'] = $_SSS['app']['db_pass'];
$db['default']['database'] = $_SSS['app']['db_name'];
$db['default']['dbdriver'] = $_SSS['app']['db_driver'];
//we can have more/different config items as required and set in the tenant config file
This is one way of achieving the Multi-tenancy with CI.
Next thing to do would be to make the asset_url available to the application as the base_url() and the site_url wont be sufficient enough to give the path for tenant linked assets. This can be achieved by
creating a helper function which gets the APP_ASSETURL if it is set. and use this helper function to load the asset files.
Now you just have to replicate the tenant_* folders and change the configs etc to suit the requirements and access the multi-tenancy enabled app like http://localhost/tenant_*
Or create subdomain and link them to tenant_* folders to access something like this
http://tenant_*.myappworld.com
Thanks for reading,
Sandeep
Check my Analytics app here
Comments
I will definitely give it a try.
Email: marcosantonioti10@gmail.com
Email: marcosantonioti10@gmail.com
Email: endangsantika@gmail.com
get physiotherapy machine here
Can you send me a sample code please?
dbixxy(at)gmail.com
abdullahmohsensayed@gmail.com
Regarding the assets path, in my situation I found the symlink() function in PHP to be the solution for my use case.