{"tenancy":{"slug":"tenancy","name":"Tenancy","description":"The next-gen SaaS toolkit extending Laravel to service multiple tenant applications from the same code base. Scalable, increased flexibility and modularity.\n","repository":"https:\/\/github.com\/tenancy\/tenancy","downloads":null,"stargazers":{"2018-02":2,"2018-03":12,"2018-04":20,"2018-05":35,"2018-06":243,"2018-07":323,"2018-08":360,"2018-09":379,"2018-10":394,"2018-11":409,"2018-12":424,"2019-01":447,"2019-02":462,"2019-03":478,"2019-04":497,"2019-05":514,"2019-06":533,"2019-07":558,"2019-08":580,"2019-09":600,"2019-10":620,"2019-11":639,"2019-12":655,"2020-01":669,"2020-02":684,"2020-03":699,"2020-04":719,"2020-05":760,"2020-06":781,"2020-07":811,"2020-08":825,"2020-09":833,"2020-10":848,"2020-11":865,"2020-12":877,"2021-01":893,"2021-02":899,"2021-03":905,"2021-04":916,"2021-05":928,"2021-06":934,"2021-07":938,"2021-08":948,"2021-09":954,"2021-10":963,"2021-11":975,"2021-12":980,"2022-01":988,"2022-02":993,"2022-03":1002,"2022-04":1007,"2022-05":1013,"2022-06":1023,"2022-07":1028,"2022-08":1033,"2022-09":1037,"2022-10":1041},"versions":{"2.x":{"slug":"2.x","name":"2.x","status":"Stable","suggestion_using":true,"branch":"2.x","package":"tenancy","tree":[{"name":"getting started","links":["introduction","requirements","installation","architecture"],"slug":"getting-started","articles":[{"title":"Introduction","icon":"fal fa-clipboard-check","excerpt":"An introduction to the Tenancy ecosystem.","path":"docs\/tenancy\/2.x\/introduction.md","slug":"introduction","package":"tenancy","version":"2.x","contents":"
Tenancy is developed as a small ecosystem. It's a set of products\/packages that are all focused on one simple thing: Providing you the best way to get multi-tenancy working in your application.<\/p>\n
The general idea of Tenancy is to give a really powerful modular way of getting multi-tenancy working in any<\/strong> Laravel application.<\/p>\n By using a modular approach we allow you to select only the components you need for your specific application. This allows you to only implement the specific functions you need without being forced to implement additional functionality changing how your application works.<\/p>\n","updated_at":{"date":"2022-06-14 06:44:26.000000","timezone_type":3,"timezone":"UTC"},"suggestionsLink":"https:\/\/github.com\/tenancy\/docs\/edit\/master\/docs\/tenancy\/2.x\/introduction.md"},{"title":"Requirements","icon":"fal fa-clipboard-check","excerpt":"System and package requirements you need to take care of before installation.","path":"docs\/tenancy\/2.x\/requirements.md","slug":"requirements","package":"tenancy","version":"2.x","contents":" Multi-tenancy can be really hard to understand, let alone apply in an application. That's why we recommend everybody to first be fluent with Laravel application development before starting with Tenancy.<\/p>\n Tenancy is always looking to support the latest Laravel version for their packages. This version of Tenancy supports<\/p>\n As docs can sometimes be outdated, we highly recommend you to have a look at the most recent Github Actions<\/a>.<\/p>\n Depending on which Tenancy modules are being used, there may be additional module specific requirements. Be sure to check each module that you are installing to ensure you meet the requirements.<\/p>\n","updated_at":{"date":"2022-06-14 06:44:26.000000","timezone_type":3,"timezone":"UTC"},"suggestionsLink":"https:\/\/github.com\/tenancy\/docs\/edit\/master\/docs\/tenancy\/2.x\/requirements.md"},{"title":"Installation","icon":"fal fa-arrow-alt-to-bottom","path":"docs\/tenancy\/2.x\/installation.md","slug":"installation","package":"tenancy","version":"2.x","contents":" There are two methods for getting the base package installed, Simplified<\/a> and Selective<\/a>.<\/p>\n The simplified install method will install the base package and all of the additional modules, but will not register all of the providers.<\/p>\n The selective install method will only install the base package, and each additional module will need to be installed on its own.<\/p>\n We would highly recommend using the selective installation method as it ensure that only the modules you need are installed, and it will automatically register the appropriate providers.<\/p>\n For a quick, simplified installation you can install everything at once:<\/p>\n IMPORTANT: You will need to manually enable your database driver of choice<\/a>, by adding the related service provider to CAUTION: This will load specific non-intrusive Affects by default. You can check which are loaded by looking in the This is an easy way of giving this toolkit a spin!<\/p>\n We recommend selectively installing the packages you need.<\/p><\/div>\n After you've installed tenancy\/tenancy make sure you register the Affects and Hooks you wish to use. You do this by simply registering the respective Providers.\nHere is the non-exhaustive list of providers that can be added to Instead of loading all tenancy packages at once, you can selectively install\nwhat you need. You need at least the framework:<\/p>\n Now that the base package is installed you will need to determine what your tenant object will be<\/a> and perform setup of the tenant object(s)<\/a>.<\/p>\n After that selectively add and\/or configure:<\/p>\n The architecture of Tenancy is broken up into three main component types.<\/p>\n These components focus on what happens when a tenant is created, updated, or deleted in the system.\nThings as simple as ensuring that the domain a tenant sign up with is valid, to creating databases and registering\/creating services to handle the needs to the tenant occur in these components.<\/p>\n Read More<\/a><\/p>\n The identification components of tenancy are responsible for identifying the tenant before application logic\noccurs regardless if that logic stems from an HTTP request, a job running in a queue, or a command being run in the console.<\/p>\n Read More<\/a><\/p>\n The Affect components are responsible for changing the application for the tenant that has been identified.\nSetting up connections to databases, changing logging settings, and the configuration of other services\noccur in these components.<\/p>\n Read More<\/a><\/p>\n","updated_at":{"date":"2022-06-14 06:44:26.000000","timezone_type":3,"timezone":"UTC"},"suggestionsLink":"https:\/\/github.com\/tenancy\/docs\/edit\/master\/docs\/tenancy\/2.x\/architecture.md"}]},{"name":"tenants","links":["tenant-what-is","tenant-setup"],"slug":"tenants","articles":[{"title":"What is a tenant?","icon":"fal fa-id-badge","excerpt":"How to determine the selection of your tenant, what are valid\nsubjects and how do you configure these inside tenancy.\n","tags":["tenant"],"path":"docs\/tenancy\/2.x\/tenant-what-is.md","slug":"tenant-what-is","package":"tenancy","version":"2.x","contents":" Whether to separate data based on the requested hostname, the logged\nin user or the team the user belongs to, is entirely up to you.<\/p>\n The subject of tenancy, the tenant<\/strong>, can be any eloquent Model\nin your application you wish to build your business logic around.<\/p>\n The most important decision in building a multi-tenant application\nis choosing your tenant. In order to help you with this, ask yourself the\nfollowing questions.<\/p>\n To which entity in my business logic does the tenant data belong to?<\/p>\n Do I have companies with employees signing up? Then most likely that\ncompany is the tenant, it holds all the information we want to keep separated\nfrom any other company in the application. This is a very common\nchoice visible with applications using a vanity url, eg yourteam.saas.app.<\/p>\n Or perhaps we can keep it simple by marking the user as a tenant. This will\nconnect all data to a single account instead. A great example of this is\nGMail. You log in and see only the emails of your account.<\/p>\n A hybrid version is also well known, GitHub offers personal namespaces, for instance\ngithub.com\/luceos and team namespaces like github.com\/tenancy.<\/p>\n Tenancy offers a solution for any scenario as there's no limitation to how\na tenant is identified, nor how many tenants can be configured. To give you an idea\nusing the hybrid example from above the tenants would be both a User model\nand an Organization model. They can be marked as a valid tenant entity by applying\na contract and implementing the required methods.<\/p>\n Once you have identified what object(s) will be your tenant you will need to setup those tenants. To get started continue to Tenant Setup<\/a><\/p>\n","updated_at":{"date":"2022-06-14 06:44:26.000000","timezone_type":3,"timezone":"UTC"},"suggestionsLink":"https:\/\/github.com\/tenancy\/docs\/edit\/master\/docs\/tenancy\/2.x\/tenant-what-is.md"},{"title":"Tenant Setup","icon":"fal fa-id-card-alt","excerpt":"General tenant setup.\n","tags":["tenant"],"path":"docs\/tenancy\/2.x\/tenant-setup.md","slug":"tenant-setup","package":"tenancy","version":"2.x","contents":" The tenant contract This will force your User model to implement some methods\nrequired for tenancy to do its work.<\/p>\n Of course tenancy offers an easy way of applying the methods\nrequired by the contract to a model by using a trait for those specific functions.<\/p>\n Your first valid tenant is a fact. Now we need to make sure our application\nis aware it exists.<\/p>\n In order for the package to know a valid tenant is available, you will need\nto register it on the tenant identification resolver. The best to do so is inside\nyour Lifecycle Hooks<\/a> allow you to take specific actions when a Tenant is created, updated, or deleted.<\/p>\n","updated_at":{"date":"2022-06-14 06:44:26.000000","timezone_type":3,"timezone":"UTC"},"suggestionsLink":"https:\/\/github.com\/tenancy\/docs\/edit\/master\/docs\/tenancy\/2.x\/tenant-setup.md"}]},{"name":"lifecycle","links":["hooks-general","hooks-database","hooks-migrations","hooks-hostname","hooks-custom"],"slug":"lifecycle","articles":[{"title":"About lifecycle hooks","icon":"fal fa-heartbeat","excerpt":"How tenancy hooks into tenant lifecycle events\n","tags":["hooks","tenant"],"path":"docs\/tenancy\/2.x\/hooks-general.md","slug":"hooks-general","package":"tenancy","version":"2.x","contents":" Lifecycle hooks are executed whenever a tenant is created, updated or deleted.\nThey allow simple bootstrapping of a newly created tenant, like provisioning a new\ndatabase virtual machine, registering domains or setting up a S3 bucket.<\/p>\n When the Lifecycle hooks listen for any of the following events:<\/p>\n You will have to fire these events in your own codebase, for instance:<\/p>\n Or through Laravel's Some pointers you need to take into consideration:<\/p>\n For hooks to be executed in the right sequence (eg migrations running after the database is created),\nthe hooks require a priority. Make sure your hooks use the correct value. Hooks are ran from lowest\nto highest priority.<\/p>\n As a result if you want to set up and configure a database server when a tenant is created, make sure to\ndo so with a priority lower than -100. If you want to configure a database value dynamically after the\nmigrations and seeds are done, use a value higher than -50.<\/p>\n Database<\/a><\/p>\n Migrations<\/a><\/p>\n Hostname<\/a><\/p>\n Identification Drivers<\/a> will be how your application determins which tenant should be loaded during a request, command, or job.<\/p>\n","updated_at":{"date":"2022-06-14 06:44:26.000000","timezone_type":3,"timezone":"UTC"},"suggestionsLink":"https:\/\/github.com\/tenancy\/docs\/edit\/master\/docs\/tenancy\/2.x\/hooks-general.md"},{"title":"Hooks Database","icon":"fal fa-database","excerpt":"How tenancy works with the Tenant lifecycle for Database mutations.\n","tags":["hooks","tenant","database"],"path":"docs\/tenancy\/2.x\/hooks-database.md","slug":"hooks-database","package":"tenancy","version":"2.x","contents":"<\/a>Requirements<\/h1>\n
<\/a>Knowledge<\/h2>\n
<\/a>Software<\/h2>\n
\n
<\/a>Module Specific Requirements<\/h2>\n
<\/a>Installation<\/h1>\n
\n
<\/a>Base Installation<\/h2>\n
<\/a>Simplified Install<\/h3>\n
composer require tenancy\/tenancy\n<\/code><\/pre>\n
app.php<\/code>.<\/p><\/div>\n
composer.json<\/code> of the repository.<\/p><\/div>\n
config\/app.php<\/code>, make sure you comment out the ones you don't need.\nThe exact provider needed is included in each component's documentation.<\/p>\n
'providers' => [\n \/\/ ...\n\n \/*\n * Package Service Providers...\n *\/\n Tenancy\\Affects\\Broadcasts\\Provider::class,\n Tenancy\\Affects\\Cache\\Provider::class,\n Tenancy\\Affects\\Configs\\Provider::class,\n Tenancy\\Affects\\Connections\\Provider::class,\n Tenancy\\Affects\\Filesystems\\Provider::class,\n Tenancy\\Affects\\Logs\\Provider::class,\n Tenancy\\Affects\\Mails\\Provider::class,\n Tenancy\\Affects\\Models\\Provider::class,\n Tenancy\\Affects\\Routes\\Provider::class,\n Tenancy\\Affects\\URLs\\Provider::class,\n Tenancy\\Affects\\Views\\Provider::class,\n\n Tenancy\\Hooks\\Database\\Provider::class,\n Tenancy\\Hooks\\Migration\\Provider::class,\n Tenancy\\Hooks\\Hostname\\Provider::class,\n\n Tenancy\\Database\\Drivers\\Mysql\\Provider::class,\n Tenancy\\Database\\Drivers\\Sqlite\\Provider::class,\n \/\/ ...\n ]\n<\/code><\/pre>\n
<\/a>Selective Install<\/h3>\n
composer require tenancy\/framework\n<\/code><\/pre>\n
<\/a>Next Steps<\/h2>\n
\n
<\/a>Architecture<\/h1>\n
\n
<\/a>Lifecycle Hooks<\/h2>\n
<\/a>Identification<\/h2>\n
<\/a>Affects<\/h2>\n
<\/a>What is a Tenant?<\/h1>\n
\n
<\/a>Overview<\/h2>\n
<\/a>Deciding on your Tenant<\/h2>\n
<\/a>Next Step<\/h2>\n
<\/a>Tenant Setup<\/h1>\n
\n
\n
\n
<\/a>Tenant Contract<\/h2>\n
Tenancy\\Identification\\Contracts\\Tenant<\/code> marks a specific\nClass as a valid tenant. Have the class implement the contract methods to get started:<\/p>\n
use Illuminate\\Database\\Eloquent\\Model;\nuse Tenancy\\Identification\\Contracts\\Tenant;\n\nclass User extends Model implements Tenant\n{\n \/**\n * The attribute of the Model to use for the key.\n *\n * @return string\n *\/\n public function getTenantKeyName(): string\n {\n return 'id';\n }\n\n \/**\n * The actual value of the key for the tenant Model.\n *\n * @return string|int\n *\/\n public function getTenantKey()\n {\n return $this->id;\n }\n\n \/**\n * A unique identifier, eg class or table to distinguish this tenant Model.\n *\n * @return string\n *\/\n public function getTenantIdentifier(): string\n {\n return get_class($this);\n }\n}\n<\/code><\/pre>\n
<\/a>Tenant Model Trait<\/h3>\n
use Illuminate\\Database\\Eloquent\\Model;\nuse Tenancy\\Identification\\Concerns\\AllowsTenantIdentification;\nuse Tenancy\\Identification\\Contracts\\Tenant;\n\nclass User extends Model implements Tenant\n{\n use AllowsTenantIdentification;\n}\n<\/code><\/pre>\n
<\/a>Tenant Registration<\/h2>\n
app\/Providers\/AppServiceProvider<\/code> or alternatively a dedicated
app\/Providers\/TenantProvider<\/code>\nwhich you created. You do this by providing the Tenant Resolver with the tenants using the
addModel<\/code> function.<\/p>\n
namespace App\\Providers;\n\nuse App\\User;\nuse Illuminate\\Support\\ServiceProvider;\nuse Tenancy\\Identification\\Contracts\\ResolvesTenants;\n\nclass AppServiceProvider extends ServiceProvider\n{\n \/**\n * Bootstrap any application services.\n *\n * @return void\n *\/\n public function boot()\n {\n \/\/\n }\n\n \/**\n * Register any application services.\n *\n * @return void\n *\/\n public function register()\n {\n $this->app->resolving(ResolvesTenants::class, function (ResolvesTenants $resolver) {\n $resolver->addModel(User::class);\n \n return $resolver;\n });\n }\n}\n<\/code><\/pre>\n
<\/a>Next Steps<\/h2>\n
<\/a>Lifecycle Hooks<\/h3>\n
<\/a>Lifecycle Hooks<\/h1>\n
\n
<\/a>Overview<\/h2>\n
HookResolver<\/code> fires the hooks, it will:<\/p>\n
\n
for()<\/code> method on the hook with the specific lifecycle event<\/a>.<\/li>\n
fires()<\/code>.<\/li>\n
priority()<\/code> method, see priorities<\/a>.<\/li>\n
fire()<\/code> method either:\n
\n
queue()<\/code> method when
queued()<\/code> is true.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n
<\/a>Events<\/h2>\n
\n
Tenancy\\Tenant\\Events\\Created<\/code>\n<\/li>\n
Tenancy\\Tenant\\Events\\Updated<\/code>\n<\/li>\n
Tenancy\\Tenant\\Events\\Deleted<\/code>\n<\/li>\n<\/ul>\n
event(new \\Tenancy\\Tenant\\Events\\Created($tenant));\n<\/code><\/pre>\n
$dispatchesEvents<\/code>:<\/p>\n
use Illuminate\\Database\\Eloquent\\Model;\n\nclass Tenant extends Model\n{\n protected $dispatchesEvents = [\n 'created' => \\Tenancy\\Tenant\\Events\\Created::class,\n 'updated' => \\Tenancy\\Tenant\\Events\\Updated::class,\n 'deleted' => \\Tenancy\\Tenant\\Events\\Deleted::class,\n ];\n}\n<\/code><\/pre>\n
\n
<\/a>Priorities<\/h2>\n
\n
-100<\/code>\n<\/li>\n
-50<\/code>\n<\/li>\n<\/ul>\n
<\/a>Available Hooks<\/h2>\n
<\/a>First Party<\/h3>\n
<\/a>Next Steps<\/h2>\n
<\/a>Identification<\/h3>\n
<\/a>Lifecycle Hook: Database<\/h1>\n
\n
\n