天天看點

Laravel Repository Pattern

laravel repository pattern

Laravel Repository Pattern

the repository pattern can be very helpful to you in order to keep your code a little cleaner and more readable. in fact, you don’t have to be using laravel in order to use this particular design pattern. for this episode however, we will use the object oriented php framework laravel to show how using repositories will make our controllers a bit less verbose, more loosely coupled, and easier to read. let’s jump in!

using repositories is not mandatory! you can accomplish many great things in your applications without using this pattern, however, over time you may be painting yourself into a corner. for example by choosing not to use repositories, your application is not easily tested and swapping out implementations would be cumbersome. let’s look at an example.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

<?php

class housescontroller extends basecontroller {

public function index()

{

$houses = house::all();

return view::make('houses.index', compact('houses'));

}

public function create()

return view::make('houses.create');

public function show($id)

$house = house::find($id);

return view::make('houses.show', compact('house'));

this would be pretty typical code for using eloquent to interact with the database which holds listings of houses for sale. it will work just fine, but the controller is now tightly coupled to eloquent. we can inject a repository instead to create a loosely coupled version of the same code. this loose coupling makes it easy to swap implementations at a later time.

there are a fair number of steps to complete the entire repository pattern, but once you go through it a few times it becomes second nature. we’re going to cover every step here.

we recently looked at a common laravel file structure you might be using. this creates a folder in the <code>app</code> directory to hold all of your domain specific files. for this example we’ll create the <code>repotutrepositories</code> within our <code>app</code> folder to contain our files. this also sets up our namespace structure which we will need to keep in mind for the files we create.

the next step is to create the interface which will determine the contract our repository must implement. this just lays out the methods that must be present in our repository. our interface will look like the following. note the namespace and methods we will use.

houserepositoryinterface.php

namespace repotutrepositories;

interface houserepositoryinterface {

public function selectall();

public function find($id);

we can now create the repository which will do all of the heavy lifting for us. it is in this file that we can put all of our detailed eloquent queries, no matter how complex they may become. each method simply has a custom name so that in our controller, we can just write some very short code to get the desired result. again note the namespace and the <code>use house;</code> statement.

dbhouserepository.php

use house;

class dbhouserepository implements houserepositoryinterface {

public function selectall()

return house::all();

public function find($id)

return house::find($id);

for our controller, we are going to type hint an interface. we are going to be doing dependency injection, but by way of an interface essentially. what this means is that we need to register the interface with laravel so that it knows which implementation of our interface we want to use. we’ll first use an eloquent implementation, but later we’ll move to a file based implementation to show how we can swap implementations easily using an interface. we place this service provider in the same namespace as our other files so far.

backendserviceprovider.php

use illuminatesupportserviceprovider;

class backendserviceprovider extends serviceprovider {

public function register()

$this-&gt;app-&gt;bind('repotutrepositorieshouserepositoryinterface', 'repotutrepositoriesdbhouserepository');

this code basically says, when you see the controller type hinting <code>houserepositoryinterface</code>, we know you want to make use of the <code>dbhouserepository</code>.

now that we have created a new service provider, we need to add this to the <code>providers</code> array within <code>app/config/app.php</code>. it may look something like this once complete:

27

28

29

30

31

'providers' =&gt; array(

'illuminatefoundationprovidersartisanserviceprovider',

'illuminateauthauthserviceprovider',

'illuminatecachecacheserviceprovider',

'illuminatesessioncommandsserviceprovider',

'illuminatefoundationprovidersconsolesupportserviceprovider',

'illuminateroutingcontrollerserviceprovider',

'illuminatecookiecookieserviceprovider',

'illuminatedatabasedatabaseserviceprovider',

'illuminateencryptionencryptionserviceprovider',

'illuminatefilesystemfilesystemserviceprovider',

'illuminatehashinghashserviceprovider',

'illuminatehtmlhtmlserviceprovider',

'illuminateloglogserviceprovider',

'illuminatemailmailserviceprovider',

'illuminatedatabasemigrationserviceprovider',

'illuminatepaginationpaginationserviceprovider',

'illuminatequeuequeueserviceprovider',

'illuminateredisredisserviceprovider',

'illuminateremoteremoteserviceprovider',

'illuminateauthremindersreminderserviceprovider',

'illuminatedatabaseseedserviceprovider',

'illuminatesessionsessionserviceprovider',

'illuminatetranslationtranslationserviceprovider',

'illuminatevalidationvalidationserviceprovider',

'illuminateviewviewserviceprovider',

'illuminateworkbenchworkbenchserviceprovider',

'repotutrepositoriesbackendserviceprovider'

),

we have most of the groundwork in place. we can now update the controller to facilitate injecting an implementation of the houserepositoryinterface. this will all us to remove any calls to eloquent directly in the controller, and replace those with simple custom method calls. our updated controller might look something like this:

housescontroller.php

32

33

34

35

use repotutrepositorieshouserepositoryinterface;

public function __construct(houserepositoryinterface $house)

$this-&gt;house = $house;

$houses = $this-&gt;house-&gt;selectall();

$house = $this-&gt;house-&gt;find($id);

for this example we simply set up a route resource like so:

/*

|--------------------------------------------------------------------------

| application routes

|

| here is where you can register all of the routes for an application.

| it's a breeze. simply tell laravel the uris it should respond to

| and give it the closure to execute when that uri is requested.

*/

route::resource('houses', 'housescontroller');

if you have not done so already, make sure that the namespace we are referencing is in your composer.json. note the addition of <code>"psr-4":{"repotut\": "app/repotut" }</code> which tells composer to autoload the classes within the <code>repotut</code> namespace.

36

37

38

39

40

"name": "laravel/laravel",

"description": "the laravel framework.",

"keywords": ["framework", "laravel"],

"license": "mit",

"require": {

"laravel/framework": "4.2.*"

},

"autoload": {

"classmap": [

"app/commands",

"app/controllers",

"app/models",

"app/database/migrations",

"app/database/seeds",

"app/tests/testcase.php"

],

                "psr-4":{

                     "repotut\": "app/repotut"

                }

"scripts": {

"post-install-cmd": [

"php artisan clear-compiled",

"php artisan optimize"

"post-update-cmd": [

"post-create-project-cmd": [

"php artisan key:generate"

]

"config": {

"preferred-install": "dist"

"minimum-stability": "stable"

don’t forget to run <code>composer dump</code> after updating <code>composer.json</code>!

whoa! nice work partner, let’s test it in the browser. we can visit <code>http://localhost/repotut/public/houses</code> and we can see that we have 3 houses for sale, each a different color.

Laravel Repository Pattern

let’s say in the future you decide that eloquent is not the way you want to handle storing data with your app. no problem! since you already laid out the ground work for using an interface, you can simple create a new repository and change the service provider. let’s see how we can swap implementations.

we’ll just use a quick example here. let’s pretend this is a whole file system class which provides data storage via flat files. in our case, we’ll just put some simple logic in to test swapping implementations. note that this class implements the same exact methods as the eloquent version we tested prior.

filehouserepository.php

class filehouserepository implements houserepositoryinterface {

$houses = new stdclass;

$house1 = new stdclass;

$house1-&gt;color = 'olive';

$house2 = new stdclass;

$house2-&gt;color = 'yellow';

$house3 = new stdclass;

$house3-&gt;color = 'brown';

$houses = array($house1,$house2,$house3);

return $houses;

return 'here is a single house listing, again using the file system';

now in the service provider, all we have to do is change one single line of code! we simply tell laravel that now when you see the <code>houserepositoryinterface</code>, you will use the filehouserepository instead of the dbhouserepository.

$this-&gt;app-&gt;bind('repotutrepositorieshouserepositoryinterface', 'repotutrepositoriesfilehouserepository');

when we test it in the browser at <code>http://localhost/repotut/public/houses</code> we can see that the new implementation has indeed taken effect, very cool!

Laravel Repository Pattern

as you can see, it seems like a lot of steps to get repositories working in your application. there are a few steps involved, no doubt about it. if you are going to be responsible for maintaining a piece of code for the long term however, you are going to reap the benefits of taking the time to correctly architect your app in the beginning. consider it a form of delayed gratification, which in this day and age seems like a forgotten art.