+ All Categories
Home > Documents > Multi Tenancy Laravel 4

Multi Tenancy Laravel 4

Date post: 09-Dec-2015
Category:
Upload: gnu2all
View: 28 times
Download: 2 times
Share this document with a friend
Description:
Multi Tenancy Laravel 4
Popular Tags:
19
Culttt Culttt Search... Business Code Design Mobile Random Reviews Social Strategy Multi-Tenancy in Laravel 4 POSTED BY PHILIP BROWN ON MARCH 31ST, 2014 Multi-tenant applications are where you create a single application that is used independently by many different clients. When a client authenticates with your application, they are only able to access the data that they have created in your application and cannot see any data that was created by any of your other clients. A typical example of a multi-tenant application is Basecamp. Basecamp customers can only see their own projects, but Basecamp is a single application that is used for all customers. Multi-tenant applications have become increasingly popular over the last couple of years due to the rise of Software as a Service and the move towards delivering applications through the cloud. It is now much more common for an application to be web based rather than installed on a client’s physical hardware. In this tutorial I’m going to walk you through setting up the core components to allow you to create multi- tenant applications in Laravel 4. You might be thinking, “what has this got to do with building Cribbb?!”. You would be correct in thinking that multi-tenancy has no place in consumer social web applications. It would be extremely weird to build that type of application using a multi-tenant approach. However I think this is an important topic that would be interesting to a lot of you building your own Software as a Service businesses. Seeing as though Join the Culttt Join the Culttt Become an insider and join the Culttt Your email... Join us SUPPORTED BY Become a Become a follower follower Follow us on Twitter Like us on Facebook Circle us on Google Plus Subscribe via RSS Home Home Code Code Multi-Tenancy in Laravel 4 Multi-Tenancy in Laravel 4
Transcript

CultttCulttt Search...

Business

Code

Design

Mobile

Random

Reviews

Social

Strategy

Multi-Tenancy in Laravel4POSTED BY PHILIP BROWN ON MARCH 31ST, 2014

Multi-tenant applications are where you create a

single application that is used independently by many

different clients. When a client authenticates with your

application, they are only able to access the data that

they have created in your application and cannot see

any data that was created by any of your other clients.

A typical example of a multi-tenant application is

Basecamp. Basecamp customers can only see their

own projects, but Basecamp is a single application

that is used for all customers.

Multi-tenant applications have become increasingly

popular over the last couple of years due to the rise of

Software as a Service and the move towards

delivering applications through the cloud. It is now

much more common for an application to be web

based rather than installed on a client’s physical

hardware.

In this tutorial I’m going to walk you through setting up

the core components to allow you to create multi-

tenant applications in Laravel 4.

You might be thinking, “what has this got to do with

building Cribbb?!” . You would be correct in thinking

that multi-tenancy has no place in consumer social

web applications. It would be extremely weird to build

that type of application using a multi-tenant approach.

However I think this is an important topic that would

be interesting to a lot of you building your own

Software as a Service businesses. Seeing as though

Join the CultttJoin the Culttt

Become an insider

and join the Culttt

Your emai l ...

Join us

SUPP ORTED BY

Become aBecome afollowerfollower

Follow us on Twitter

Like us onFacebook

Circle us on GooglePlus

Subscribe via RSS

HomeHome CodeCode Multi-Tenancy in Laravel 4Multi-Tenancy in Laravel 4

I’m doing this in Laravel it also makes sense to

include it in this series.

So for one week only we will diverge from the path of

building a social consumer application, and instead

delve into the murky depths of Software as a Service.

How do Multi-Tenantapplications work?As I mentioned in the introduction to this post, multi-

tenant applications are a single installation of an

application that allows many different clients to

access their data independently.

There are a few different approaches to managing the

separation of data in multi-tenant applications.

Firstly, you could use a separate database for each

client. This means the connection to the correct

database is established on authentication. Using

separate databases ensures that data from one client

is never mixed with the data of another.

Secondly you could use a separate schema. This is

where you use one database but the database is able

to manage the separation of data through the schema.

This basically means that every client has it’s own set

of tables within the same database.

And thirdly, you could use a shared database with a

shared schema where you select data from the

database using a tenant_id field.

The choice between the three different approaches

really comes down to what type of application you a

building. If you are building a high security application

for a regulated industry, it makes sense to have

physical separation of data through isolated

databases.

However if you are building a low cost Software as a

Service application, you can sacrifice this security

measure for lower cost infrastructure and overheads.

Maintaining separate databases or even a separate

schema will be significantly more costly to run and

maintain.

My chosen approach is the shared database and

shared schema application. I think the benefits of

lower overheads and easier maintainability greatly

outweigh the security implications for the majority of

multi-tenant applications. However, if you were

building software for banks, hospitals or the

government you will probably want to use the

separate database approach.

How do shared database multi-tenant applications work?So now that I’ve established what are multi-tenant

applications and what are the different application

architecture choices you have, I’ll explain how my

chosen approach works.

In a typical Software as a Service application a client

will authenticate and then be presented with their

unique dashboard filled with their data and none of

the data from any of the other clients.

When the client authenticates our application will set

a global context that will scope all database queries

to only return data for that current client. This means

that all the code of the application is unaffected

because the data is scoped at the database.

There are usually many different ways to authenticate

into an application. For example you could require

client credentials for your application but also offer

token based authentication via an API. In either case

we want a solution that will work for any type of

authentication so the database scoping logic is not

repeated and therefore less prone to errors or bugs.

Creating the Context InterfaceThe first thing I need to do is to create the Context

service that will act as the scope of the application.

This is basically just a global object that will be

injected into other aspects of the code (for example

the Repositories) to restrict data to only the current

client.

The Context is simply a wrapper around the entity

object of the current client. However, because

business rules often change over the life of an

application, it’s important to make the context open for

substitution.

To enable this substitution I will create an interface for

the context like this:

123456

<?php namespace Cribbb\Contexts; use Illuminate\Database\Eloquent\Model; interface Context {

?

As you can see above, the client entity will be

injected into the service. The methods on the service

are available as a generic public API for working with

the context in our application. This is important

because, for example, if instead we need to substitute

a $client entity for a $organisation entity, we

would have to replace every instance of client_id

for organisation_id .

Creating the ContextimplementationNext I can create the specific Context implementation.

In this case my context is a Client entity. The

implementation is just a class that fulfils the

requirements of the Context interface:

789

101112131415161718192021222324252627282930313233343536373839404142

/** * Set the context * * @param Illuminate\Database\Eloquent\Model */ public function set(Model $context); /** * Check to see if the context has been set * * @return boolean */ public function has(); /** * Get the context identifier * * @return integer */ public function id(); /** * Get the context column * * @return string */ public function column(); /** * Get the context table name * * @return string */ public function table(); }

123456789

10111213141516171819202122

<?php namespace Cribbb\Contexts; use Illuminate\Database\Eloquent\Model; class ClientContext implements Context { /** * The current context * * @var Illuminate\Database\Eloquent\Model */ protected $context; /** * Set the context * * @param Illuminate\Database\Eloquent\Model */ public function set(Model $context) { $this->context = $context; }

?

The importance of the IoCcontainerNow that I’ve created the generic Context interface

and a specific implementation for the Client

model, I now need to bind the two together in

Laravel’s IoC container so that when I call for an

instance of Cribbb\Contexts\Context I will be

returned an instance of

Cribbb\Contexts\ClientContext . This is

exactly the same as how the

EloquentUserRepository is returned when you

write UserRepository in your Controllers.

However, there is one more important detail. The

Context object should be shared through the

application as a single instance. When I set the

context through the authentication, I want the same

object to be available in the Repositories. To ensure

that the same object is shared throughout the

application for each request I will use the shared

method of the IoC container.

Here is my ContextServiceProvider :

2324252627282930313233343536373839404142434445464748495051525354555657585960616263646566

/** * Check to see if the context has been set * * @return boolean */ public function has() { if($this->context) return true; return false; } /** * Get the context identifier * * @return integer */ public function id() { return $this->context->id; } /** * Get the context column * * @return string */ public function column() { return 'client_id'; } /** * Get the context table name * * @return string */ public function table() { return 'clients'; } }

?

Finally add the following line to your list of Service

Providers in app/config/app.php :

Authenticating and setting thecontextNow that you have the global Context object in your

application you can set the context when you

authenticate the request by injecting the context and

setting the database entity into the Context object.

This could be as simple as extending the inbuilt

Laravel authentication filter to set the context, or

creating your own API filter to authenticate requests

based upon a token and a secret. The choice of how

you implement authentication is really up to you.

For example, you could modify the existing Laravel

auth filter like this:

Here I’m resolving the context out of the IoC container

and setting the user entity.

This is really open to work however you need it to

work. If you authenticate against an organisation, just

set the organisation entity instead of the user entity.

Creating the Tenant Repository

123456789

1011121314151617181920212223

<?php namespace Cribbb\Contexts; use Illuminate\Support\ServiceProvider; class ContextServiceProvider extends ServiceProvider { /** * Register */ public function register() { $this->app['context'] = $this->app->share(function { return new ClientContext; }); $this->app->bind('Cribbb\Contexts\Context', { return $app['context']; }); } }

1 'Cribbb\Contexts\ContextServiceProvider'

12345678

Route::filter('auth', function(){ $context = App::make('Cribbb\Contexts\Context' if (Auth::guest()) return Redirect::guest('login' $context->set(Auth::user());});

?

?

Now that the Context is set we can use it to scope the

database requests in the Repositories. To do this I

will create another Repository named

TenantRepository which extends the base

AbstractRepository .

For each repository that needs to be scoped per client

I then extend the TenantRepository rather than

the AbstractRepository directly. This enables

my repositories to all inherit the basic blueprint, but

the repositories that need to be scoped can inherit an

extra layer of logic.

In the TenantRepository I create a couple of

methods that wrap my basic building block methods

to scope the query if applicable. A scoped

relationship could either be any of the different types

of database relationship. For example it could be

based upon a foreign id column or it could be through

a pivot table. In the majority of cases you will only

need to scope through a column. I think it is rare that a

multi-tenant application would have resources that

are available to many clients. However I’ve included

those methods in the example below to show you

how you would achieve that using Laravel’s query

builder.

I also don’t want to create different repositories for

scoped access and not scoped access. For example,

if I wanted to create a dashboard to monitor the

application I don’t want to have to create a second set

of repositories that weren’t scoped per client. You will

notice that I check to see if the scope has been set to

achieve this:

123456789

1011121314151617181920212223242526272829

<?php namespace Cribbb\Repositories; use StdClass;use Illuminate\Database\Eloquent\Builder; abstract class TenantRepository extends AbstractRepository { /** * Scope a query based upon a column name * * @param Illuminate\Database\Eloquent\Builder * @return Illuminate\Database\Eloquent\Builder */ public function scopeColumn(Builder $model) { if($this->scope->has()) { return $model->where($this->scope->column(), } return $model; } /** * Scope the query based upon a relationship * * @param Illuminate\Database\Eloquent\Builder * @return Illuminate\Database\Eloquent\Builder */

?

30313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899

100101102103104105106107108109110111112113114115116117118119120121122123

public function scopeRelationship(Builder $model { if($this->scope->has()) { return $model->whereHas($this->scope->table(), { $q->where($this->scope->column(), '=', }); } return $model; } /** * Retrieve all entities through a scoped column * * @param array $with * @return Illuminate\Database\Eloquent\Collection */ public function allThroughColumn(array $with { $entity = $this->make($with); return $this->scopeColumn($entity)->get(); } /** * Retrieve all entities through a scoped relationship * * @param array $with * @return Illuminate\Database\Eloquent\Collection */ public function allThroughRelationship(array { $entity = $this->make($with); return $this->scopeRelationship($entity)->get(); } /** * Find a single entity through a scoped column * * @param int $id * @param array $with * @return Illuminate\Database\Eloquent\Model */ public function findThroughColumn($id, array { $entity = $this->make($with); return $this->scopeColumn($entity)->find($id } /** * Find a single entity through a scoped relationship * * @param int $id * @param array $with * @return Illuminate\Database\Eloquent\Model */ public function findThroughRelationship($id, { $entity = $this->make($with); return $this->scopeRelationship($entity)->find( } /** * Get Results by Page through scoped column * * @param int $page * @param int $limit * @param array $with * @return StdClass Object with $items and $totalItems for pagination */ public function getByPageThroughColumn($page { $result = new StdClass; $result->page = $page; $result->limit = $limit; $result->totalItems = 0; $result->items = array(); $query = $this->scopeColumn($this->make($with $users = $query->skip($limit * ($page - 1)) ->take($limit) ->get(); $result->totalItems = $this->model->count(); $result->items = $users->all(); return $result; }

124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213

/** * Get Results by Page through scoped relationship * * @param int $page * @param int $limit * @param array $with * @return StdClass Object with $items and $totalItems for pagination */ public function getByPageThroughRelationship( { $result = new StdClass; $result->page = $page; $result->limit = $limit; $result->totalItems = 0; $result->items = array(); $query = $this->scopeRelationship($this->make( $users = $query->skip($limit * ($page - 1)) ->take($limit) ->get(); $result->totalItems = $this->model->count(); $result->items = $users->all(); return $result; } /** * Search for a single result by key and value through a scoped column * * @param string $key * @param mixed $value * @param array $with * @return Illuminate\Database\Eloquent\Model */ public function getFirstByThroughColumn($key { $entity = $this->make($with); return $this->scopeColumn($entity)->where( } /** * Search for a single result by key and value through a scoped relationship * * @param string $key * @param mixed $value * @param array $with * @return Illuminate\Database\Eloquent\Model */ public function getFirstByThroughRelationship( { $entity = $this->make($with); return $this->scopeRelationship($entity)->where( } /** * Search for many results by key and value through a scoped column * * @param string $key * @param mixed $value * @param array $with * @return Illuminate\Database\Eloquent\Collection */ public function getManyByThroughColumn($key, { $entity = $this->make($with); return $this->scopeColumn($entity)->where( } /** * Search for many results by key and value through a scoped relationship * * @param string $key * @param mixed $value * @param array $with * @return Illuminate\Database\Eloquent\Collection */ public function getManyByThroughRelationship( { $entity = $this->make($with); return $this->scopeRelationship($entity)->where( } }

Extending the Tenant RepositoryNow that I’ve got the abstract TenantRepository

set up I can extend it to create my individual

repositories.

For example, if this was an application like Basecamp

I might have a ProjectRepository that was

scoped through a column. My repository might look

something like this:

123456789

1011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374

<?php namespace Cribbb\Repositories\Project; use Cribbb\Contexts\Context;use Illuminate\Database\Eloquent\Model;use Cribbb\Repositories\TenantRepository; class EloquentProjectRepository extends TenantRepository /** * @var Model */ protected $model; /** * @var Context */ protected $scope; /** * Construct * * @param Cribbb\Contexts\Context $scope * @param Illuminate\Database\Eloquent\Model $model */ public function __construct(Model $model, Context { $this->model = $model; $this->scope = $scope; } /** * Return all projects * * @param array $with * @return Illuminate\Database\Eloquent\Collection */ public function all(array $with = array()) { return $this->allThroughColumn($with); } /** * Return a single project * * @param array $with * @return Illuminate\Database\Eloquent\Model */ public function find($id, array $with = array { return $this->findThroughColumn($id, $with); } /** * Get Results by Page * * @param int $page * @param int $limit * @param array $with * @return StdClass Object with $items and $totalItems for pagination */ public function getByPage($page = 1, $limit = 10, { return $this->getByPageThroughColumn($page, } /** * Search for a single result by key and value * * @param string $key * @param mixed $value * @param array $with * @return Illuminate\Database\Eloquent\Model */ public function getFirstBy($key, $value, array

?

Testing the contextNow that you have set up everything, we can do a

dirty little test to ensure everything is working

correctly. First seed your database with enough data

to clearly show that your tests are working correctly.

By this I mean a couple of clients and lots of projects.

Next create a new test route you can hit and copy the

following code:

In the example above I’m grabbing the first client and

resolving the Context out of the IoC container. Next

I resolve the ProjectRepository out of the IoC

container and call the all method to select all the

available projects.

Now when you hit the test route in the browser you

should see a list of available projects. However, when

you change which client you select from the database

and hit the route again the project list will

automatically change.

Congratulations! You’ve just set up automatically

scoping repositories for your new Software as a

Service application!

ConclusionPhew! We covered a lot in this tutorial. Hopefully if

757677787980818283848586878889909192

{ return $this->getFirstByThroughColumn($key, } /** * Search for many results by key and value * * @param string $key * @param mixed $value * @param array $with * @return Illuminate\Database\Eloquent\Collection */ public function getManyBy($key, $value, array { return $this->getManyByThroughColumn($key, } }

123456789

101112131415

Route::get('/test', function(){ $client = Client::find(1); $context = App::make('Cribbb\Contexts\Context' $context->set($client); $repository = App::make('Cribbb\Repositories\Project\ProjectRepository' $projects = $repository->all(); foreach($projects as $project) { var_dump($project->title); }});

?

you’ve been following a long with this series you will

see that the individual building blocks of what I’ve

implemented in this tutorial have mostly been covered

in previous tutorials. It just goes to show that if we

learn and understand the individual building blocks,

we can build some pretty powerful applications.

In this tutorial we’ve covered a couple of interesting

things. Firstly, creating a Context that wraps an

existing object and provides an easily accessible

public API. This approach makes it really easy to

substitute how you want to scope your application if

the business rules of your company change in the

future.

Secondly we looked at setting the scope through

authentication. There are many different ways to

authenticate an application. You now have the basic

simple building blocks for authenticating and setting a

global scope that can be used through the

application.

And thirdly I showed you how to add another layer of

inheritance to add scoping logic to the repositories in

your application that need to be scoped. This can

optionally be applied to whichever repositories that

you want to be scoped, but also offers you the

flexibility to ignore the scope or to scope different

types of database relationships.

As I mentioned at the top of this post, this multi-tenant

architecture has no place in Cribbb. However

hopefully you can use this as a building block or

inspiration to build your own multi-tenant applications

for your company or for your clients.

This is a series of posts on building an entire Open

Source application called Cribbb. All of the tutorials

will be free to web, and all of the code is available on

GitHub.

To view a full listing of the tutorials in this series, click

here.

Philip BrownHey, I'm Philip Brown , a designer and developer from

Durham, England. I create websites and web based

applications from the ground up. In 2011 I founded a

company called Yellow Flag. If you want to find out more

33

TweetTweet

8 1111

Join the CultttJoin the Culttt

Become an insider and join the Culttt

Your emai l ...

Join us

Comments Community Login 1

Sort by Best

Join the discussion…

• Reply •

John Carter • a year ago

Please Please Please Please Please Please witha watermelon and cherry on top of thewatermelon, create a tutorial that dives into multi-tenancy for multi databases! I want to useLaravel fluently with Multitenancy with testing,etc. I will pray that God makes you live the bestlife every if you do this!!!

4

• Reply •

Philip Brown • a year ago

Mod > John Carter

Hi John, sorry no plans to write tutorial(s)on multi tenancy with multiple databases.Perhaps in the future.

• Reply •

Eduardo WB • a year ago

This post came in good time as we will build aSoftware as Service application. Nice approachto solve the multi-user problem. Thank you!

4

• Reply •

Philip Brown • a year ago

Mod > Eduardo WB

Thank you Eduardo :)

vince • a year ago

I really must have missed something big in thistutorial. I do not understand all the complexitywhen all you want to do is isolate the data thatbelongs to a specific tenant based on their logincredentials. What is meant by "Context" - do youmean the id of the user and their data when youmight have 200 people all called John Smith ? Igot thoroughly lost on this tutorial. Regardless Iwould really, really like to be put straight as this isa very important topic for me. Thanks !!

Recommend 3

Share ›

Share ›

Share ›

Share ›

about me, you can follow me on Twitter or Google Plus.

29

LikeLike

• Reply •

a very important topic for me. Thanks !! 1

• Reply •

Neel • 2 months ago> vince

I agree with vince.. The first 2 para madesense and I though geez its easy. Whenthe context part came, my head startedspinning and didnt make much sense.Unfortunately for a newbie in laravel, itwas a bit too hard to understand. Thanksfor the tutorial though since I got theoverview. However, I feel its not newbiefriendly though.

• Reply •

Philip Brown • 2 months ago

Mod > Neel

Yeah Multi-tenancy isn't really anewbie topic. I'd come back to thisonce you've spent more time withLaravel.

• Reply •

Philip Brown • a year ago

Mod > vince

Yes the "Context" is the currentauthenticated User / Organisation.

By using this approach you scope thedata at the data access layer so only datafor the current Context is returned. Thismeans you don't have to have any logic inany of your Controllers or Services forrestricting data retrieval.

• Reply •

vince • a year ago

> Philip Brown

ok got it. Can you give me abullited list of things I should learnin order to understand this topic toit's best. Thanks !

• Reply •

Philip Brown • a year ago

Mod >vince

Hmm, well everything youneed is in this blog post.

I would take a look at thistalk

The code is Ruby, but it'sthe exact same principle.

Share ›

Share ›

Share ›

Share ›

Share ›

Share ›

• Reply •

vince • a year ago

> Philip Brown

heah Philip, that's great . Iam watching it already.However, as I am aLaravel Newbie. I havealready done a lot ofstudying on Laravel,however, as a best andbraces, can you pleasegive be a list of core**Laravel** technologies Ineed to understand well inorder to get the best out ofyour article.

thanks !

• Reply •

Philip Brown • a year ago

Mod >vince

Well there isn't anythingthat is specific to Laravelreally. I guess you justneed to understand thatthe Context is set duringauthentication. You thenresolve the Context fromthe IoC container andinject it into the Repository.The Repository thenscopes all databasequeries so you don't haveto deal with that logic inyour Controllers orServices.

• Reply •

Daniel Bethel • a year ago

Where is the AbstractRepository that the tenantrepo extends?

1

• Reply •

Philip Brown • a year ago

Mod > Daniel Bethel

It would just be a generic abstractrepository, like the one in this tutorialhttp://culttt.com/2014/03/17/e...

• Reply •

Mike Fuller • a year ago

Thank you for post, very helpful. However, I juststarted working with Laravel so pardon me if thisis a stupid question. Does Laravel's globalscopes http://laravel.com/docs/eloque... makesome of this code unnecessary?

Thanks 1

Philip Brown • a year ago

Mod > Mike Fuller

Thanks Mike :)

Hmm, I'm not 100% sure. I know thatglobal scopes are used for soft deletes,

Share ›

Share ›

Share ›

Share ›

Share ›

• Reply •

global scopes are used for soft deletes,but I haven't really looked into them toomuch to be honest.

• Reply •

Fasil K K Cholakkara • a year ago

This is what im looking for.Thank you verymuch..

Why cant put a sample application in github? + ademo. All can use this as a base for their simpleSAAS applicatins.

1

• Reply •

Philip Brown • a year ago

Mod > Fasil K KCholakkara

Hmm, I guess I could. Everything youneed is in this post though :)

1

• Reply •

Jhaura Wachsman • a year ago

> PhilipBrown

Nice post :-) I'd like to see theschema or migrations. I think thatwould be super helpful.

1

• Reply •

Philip Brown

• a year ago

Mod >Jhaura Wachsman

Hmm, well it would just bethe normal schema andmigrations but with atenant_id, nothingcomplicated :)

• Reply •

Fasil K K Cholakkara • a year ago

> PhilipBrown

Trouble in username validation.:( Ihave to keep it like uniqueusername for whole application.(Cant do for each tenancy inshared db)

• Reply •

Philip Brown

• a year ago

Mod >Fasil K K Cholakkara

Hmm, yeah you wouldhave to either write yourown validation rule (couldbe tricky) or implement itas a separate check inyour code.

1

Fasil K K Cholakkara

• a year ago> Philip Brown

I cant do uniquenessbased on tenant. Becausethere is a chance forgetting same username inother tenancy. Accidentallyif those 2 users(sameusername) used samepassword, then the big

Share ›

Share ›

Share ›

Share ›

Share ›

Share ›

Share ›

• Reply •

password, then the bigissue will get while login.The only solutions is i thinkis to pass Tenant id also,while login.

• Reply •

bmadigan

• a year ago

> Fasil K KCholakkara

I thought of this as well, butI think if you usedsubdomains for eachtenant that may help

1

• Reply •

Philip Brown

• a year ago

Mod >Fasil K K Cholakkara

Well when youauthenticate users youneed to be checking toensure that they are amember of the currenttenant. You wouldn't wantto allow a user to sign intoto another customer'saccount.

• Reply •

Guest • a year ago

Anyone have any guidance on going down theroad of custom domains for clients under thismodel? For example if I give every user asubdomain what would be the best method forallow them to set a DNS record on their owndomain to be masked back to the SaaS appsubdomain? CNAME record on their end but anyideas on how to handle it on the server side?

1

• Reply •

Justin • a year ago> Guest

A wildcard vhost/nginx configuration iswhat you're looking for. So that your webserver/app responds to ANY domaintrying to access it and then setting whichtenant/customer it is. Hopefully that helps.:)

• Reply •

Philip Brown • a year ago

Mod > Guest

Hmm, I'm not sure actually. I guess youcould just set the scope in the same wayas you would for a subdomain, but youare using the whole domain instead.

John Hamman • a year ago

Above and beyond outstanding series! I havelearned so much...So my question is: instead of a client_id, I havean account_id with an account holding multipleusers (many users to one account). And so Iwould like to put the account ID in the url as indomain.com/123456/ and use that to identify the

Share ›

Share ›

Share ›

Share ›

Share ›

Share ›

• Reply •

domain.com/123456/ and use that to identify thescope. How do you suggest I go about doing thatafter handling the context in auth?

1

• Reply •

Philip Brown • a year ago

Mod > John Hamman

Thanks John :D

I normally create a filter and attach it tothe routes I want to set the scope on. Thefilter will just take the id from the URL, andfind the entity from the database and thenset the scope.

I've only ever done that usingsubdomains, but it will work in the exactsame way for url params.

Something like this perhaps...

Route::filter('auth.scope',

function($route, $request)

{

$repository = App::make('your

repository');

$id = Request::segment(1);

$entity = $repository->find($id)

if(! $entity)

{

return Redirect::route('login');

}

$scope = App::make('your scope');

$scope->set($entity);

});

• Reply •

John Hamman • a year ago

> Philip Brown

Amazing, thanks!

• Reply •

Carlos • a year ago

This is exactly what i was looking for. Thanks abunch!

1

• Reply •

Philip Brown • a year ago

Mod > Carlos

No problem, glad it helped you out! 1

• Reply •

Michael • 2 months ago

Maybe I'm missing something here but why don'tyou just use eloquent relationships all tied backto your User model? The foreign keyrelationships will already scope your data for you.

• Reply •

Philip Brown • 2 months ago

Mod > Michael

This is essentially what is happeninghere. This approach means you don'thave to be constantly scoping eachquery.

Share ›

Share ›

Share ›

Share ›

Share ›

Share ›

Share ›

• Reply •

moimichel • 5 months ago

Just want to thank you for this "rich" tutorial.

• Reply •

Philip Brown • 5 months ago

Mod > moimichel

No problem, glad you found it useful!

• Reply •

Sanket Sahu • 10 months ago

Great Article there! It helped me a lot. I did aquick hack, instead of overloading all thefunctions, I just overloaded the newQuery()function.

• Reply •

Philip Brown • 10 months ago

Mod > Sanket Sahu

Thanks Sanket :) Glad you liked it :)

Share ›

Share ›

Share ›

Share ›

Y E L L O W F L A G


Recommended