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