Decoupling your code in Laravel using Repositiories and Services

9th March '14

When starting with Laravel there are a number of places where you need to add your own structure, models being a big one. Models, as suggested by Laravel, are Eloquent Objects, designed to tell Laravel about a specific table - this is not a good place to put all your business logic.

This article looks at separating the different uses of models into different places. By decoupling your code, you gain re-usability which can be very important, especially when your app is going to grow and do it fast.

Here we shall be implement the Repository Design Pattern along side Service Oriented Architecture. This is the way I like to separate my logic in a fresh Laravel install, it’s probably worth noting I used to develop a lot on Symfony and this implementation is based heavily on that.

Different types of models

In implementing these elements we will ultimately be left with 3 different types of models:

                Entities: The standard models in Laravel, containing just configuration variables and methods to be used by Eloquent. Relationships, accessors and mutators belong here.

                Repositories:  Using Entities to get your data, they contain functions to gather specific sets of data in specific formats for your app. Though the logic in them might change, the returned data should always be exactly the same.

                Services: The home of global logic, containing functions that are used throughout your app. It calls your Repositories but also validates, creates sessions and contains your logic. These  all help to keep your controllers thin!

So what is Repository Design Pattern?

A Repository is an interchangeable class that talks to your data source (in this case your Entity) and returns a very specific output. If the data source changes (e.g. into an API), you can swap your old Repository class into a new one which will return the exact same output in the same format, meaning the rest of your application doesn’t need to change a bit!

Using this pattern takes only a little extra effort, but one day you might thank your lucky stars you did!

And Service Orientated Architecture?

This is generally considered an alternative to MVC, but it doesn’t have to be. Laravel already uses a lot of Services in its MVC environment; you might know them as Facades. By using this pattern you can easily re-use functions and methods in any part of your site as easily as the Facades.

Interfaces, Service Providers and Facade classes

Before we get started, there are three more types of files worth knowing about, they really give this set up its magic. These are Interfaces, Services Providers and Facade classes.

An Interface is the key behind making the Repositories interchangeable. It contains information on what is needed in a class and throws a paddy if it doesn’t get what it wants. This stops us forgetting any needed methods and protects our application.

Service Providers are scattered around Laravel and normally found in vendors; they tell Laravel about your class and how to create it, very important for Dependency Injection.

Lastly, and simplest of the three, are Facade classes. Whenever you try and use a Facade, Laravel will go to this class just to get the name of the class to return, it’s that simple!

And here we go…

The first step is putting all your models in app/models/entities. These all need to have the namespace ‘Entities’.

Whilst creating folders we will also need an app/models/repositories and app/models/services.

Now, let’s say we have a table containing all the 151 Pokémon (the rest are lies), you will of course have an Entity for this under the namespace ‘\Entities\Pokemon’. In your Repositories folder create a new folder called 'pokemon'.

Before we can build the class, we first have to build an interface. This has the added bonus of letting us think/plan what our Repository will contains.

<?php namespace Repositories\Pokemon;

/**
 * A simple interface to set the methods in our Pokemon repository, nothing much happening here
 */
interface PokemonInterface
{
    public function getPokemonById($pokemonId);
    
    public function getPokemonByName($pokemonName);
}

Whenever we implement this interface on a class we are saying the class has to contain these two methods, each receiving the variables described.

Next let’s create our class.

<?php namespace Repositories\Pokemon;

use Illuminate\Database\Eloquent\Model;
use \stdClass;

/**
* Our pokemon repository, containing commonly used queries
*/
class PokemonRepository implements PokemonInterface
{
    // Our Eloquent pokemon model
    protected $pokemonModel;
    
    /**
    * Setting our class $pokemonModel to the injected model
    * 
    * @param Model $pokemon
    * @return PokemonRepository
    */
    public function __construct(Model $pokemon)
    {
        $this->pokemonModel = $pokemon;
    }

    /**
    * Returns the pokemon object associated with the passed id
    * 
    * @param mixed $pokemonId
    * @return Model
    */
    public function getPokemonById($pokemonId)
    {
        return $this->convertFormat($this->pokemonModel->find($pokemonId));
    }

    /**
    * Returns the pokemon object associated with the pokemonName
    * 
    * @param string $pokemonName
    */
    public function getPokemonByName($pokemonName)
    {
        // Search by name
        $pokemon = $this->pokemonModel->where('name', strtolower($pokemonName));
        
        if ($pokemon) 
        {
            // Return first found row
            return $this->convertFormat($pokemon->first());
        }
        
        return null;
    }
    
    /**
    * Converting the Eloquent object to a standard format
    * 
    * @param mixed $pokemon
    * @return stdClass
    */
    protected function convertFormat($pokemon)
    {
        if ($pokemon == null)
        {
            return null;
        }
        
        $object = new stdClass();
        $object->id = $pokemon->id;
        $object->name = $pokemon->name;
        
        return $object;
    }
}

Three important things are happening here; firstly, we are implementing the interface we just made, secondly, we are injecting our Pokemon Entity into the Repository and finally before returning the relevant eloquent object we convert it to a general object, this way if the data-source changes we can still return an object of the same format (Thank you littleakma for pointing this out).

The last stage before our Repository is ready is telling Laravel about it!

Using the register and bind functions we are telling Laravel to use this class.

<?php namespace Repositories\Pokemon;

use Entities\Pokemon;
use Repositories\Pokemon\PokemonRepository;
use Illuminate\Support\ServiceProvider;

/**
* Register our Repository with Laravel
*/
class PokemonRepositoryServiceProvider extends ServiceProvider 
{
    /**
    * Registers the pokemonInterface with Laravels IoC Container
    * 
    */
    public function register()
    {
        // Bind the returned class to the namespace 'Repositories\PokemonInterface
        $this->app->bind('Repositories\Pokemon\PokemonInterface', function($app)
        {
            return new PokemonRepository(new Pokemon());
        });
    }
}

We have now binded our PokemonRepository to the PokemonInterface. Once we have added this Service Provider into your app/config/app.php file (more information about this later) we can inject our Repository anywhere we like and Laravel will inject this class.

If we decide to make a new PokemonRepository, we can simply tell Laravel about it here and all injected references in our app will start using this one!

Let’s Create a Service!

Like the Repository, there are three stages to this implementation. We don’t have to worry about an interface as we won’t need to swap this class out, but we will need another service provider, a facade class and the service itself.

Since we just made one for our repository, let’s start with the service provider. Like your Repository, we need to create a new folder in services for this Service.

<?php namespace Services\Pokemon;

use Illuminate\Support\ServiceProvider;

/**
* Register our pokemon service with Laravel
*/
class PokemonServiceServiceProvider extends ServiceProvider 
{
    /**
    * Registers the service in the IoC Container
    * 
    */
    public function register()
    {
        // Binds 'pokemonService' to the result of the closure
        $this->app->bind('pokemonService', function($app)
        {
            return new PokemonService(
                // Inject in our class of pokemonInterface, this will be our repository
                $app->make('Repositories\Pokemon\PokemonInterface')
            );
        });
    }
}

So just like before we are telling Laravel about this Service at this location and creating the class and then, wait… what’s that?

That, my friend, is the genius of Laravel! It can see we need a class implementing the PokemonInterface, so it injects one.

Now we can create our Service. It should look something like this:

<?php namespace Services\Pokemon;

use Repositories\Pokemon\PokemonInterface;

/**
* Our PokemonService, containing all useful methods for business logic around Pokemon
*/
class PokemonService
{
    // Containing our pokemonRepository to make all our database calls to
    protected $pokemonRepo;
    
    /**
    * Loads our $pokemonRepo with the actual Repo associated with our pokemonInterface
    * 
    * @param pokemonInterface $pokemonRepo
    * @return PokemonService
    */
    public function __construct(pokemonInterface $pokemonRepo)
    {
        $this->pokemonRepo = $pokemonRepo;
    }

    /**
    * Method to get pokemon based either on name or ID
    * 
    * @param mixed $pokemon
    * @return string
    */
    public function getPokemon($pokemon)
    {
        // If pokemon variable is numeric, assume ID
        if (is_numeric($pokemon))
        {
            // Get pokemon based on ID
            $pokemon = $this->pokemonRepo->getPokemonById($pokemon);
        }
        else 
        {
            // Since not numeric, lets try get the pokemon based on Name
            $pokemon = $this->pokemonRepo->getPokemonByName($pokemon);
        }
        
        // If Eloquent Object returned (rather than null) return the name of the pokemon
        if ($pokemon != null)
        {
            return $pokemon->name;
        }

        // If nothing found, return this simple string
        return 'Pokemon Not Found';
    }
}

A very simple class to show use of the Repository in your Service, of course these methods can get a lot more complicated with a lot less emphasis on the Repository, but since this pokemon Metaphore (like the attack abilities of Metapod) are wearing a bit thin, this will do for now.

The last file to create is the Facade class, this is very simple and doesn’t require much explanation:

<?php namespace Services\Pokemon;

use \Illuminate\Support\Facades\Facade;

/**
* Facade class to be called whenever the class PokemonService is called
*/
class PokemonFacade extends Facade {

    /**
     * Get the registered name of the component. This tells $this->app what record to return
     * (e.g. $this->app[‘pokemonService’])
     *
     * @return string
     */
    protected static function getFacadeAccessor() { return 'pokemonService'; }

}

Service Provider  - check

Service Class – check

Facade Class – check

Before we finish this, we need to autoload all the classes we have just made, in your composer.json we need to register the new directories in your class map:

"autoload": {
    "classmap": [
        "app/models/entities",
        "app/models/repositories",
        "app/models/repositories/pokemon",
        "app/models/services",
        "app/models/services/pokemon",
    ]
},

And run 'composer dump-autoload' in your root directory.

Now all that’s left is to add this to our app config file.

In app/config/app.php you will see see a providers array, add the namespace of your service provider here:


'providers' => array(
    'Repositories\Pokemon\PokemonRepositoryServiceProvider',
    'Services\Pokemon\PokemonServiceServiceProvider',
),

Then we need to register the Facade in the same file:

'aliases' => array(
    'Pokemon' => 'Services\Pokemon\PokemonFacade',
),

And we are done.

See this demo in action

I have created a repository showcasing this example, feel free to have a look. There will also be a database migration on there to test this tutorial out.

Using those migrations you can simply make a route as shown below that tries to grab a pokemon based on name or id.

// A nice simple route to show a pokemons name if we can find it using our Service
Route::any('/pokemon/{pokemon}', function($pokemon) {
    return Pokemon::getPokemon($pokemon);
});

Note about Facades

There are valid opinions that Facades should not be used in Laravel. By using them you are making your application Laravel specific and harder to detach. A good solution to this is injecting your Services into your Controller. Read more about that here.

Conclusion

Well, I have definitely learnt a lot about the reasoning behind using these patterns, but hopefully  you have too. Using Repositories and Services we can properly decouple our code, making it more maintainable, re-usable, and sexier; all of this makes our App better. I welcome all comments and suggested improvements behind these.

As mentioned at the beginning, this is just how I like to work, there are many alternatives out there. If this style suits you then let me know!

Sign Up For My Newsletter

Every week I put together an article digest of web related articles I found interesting and wanted to share, if you would like to receive this email please subscribe below!

* indicates required
comments powered by Disqus