Introduction to Repository Design Pattern
Now a days, there is a lot of buzz about software design patterns, and one of the most frequently asked questions is “How can I use some pattern with some technology“. According this question the important thing you must remember is that design patterns do not depend on specific technology, framework or programming language. In Software Engineering a design pattern is a reusable solution to a general problem occurring in a given context in software design. A design pattern is not a design which is directly transferred into code(source or machine).
If you have really understood Repository Pattern then it does not matter what framework or programming language you are going to use. What is important is that you understand the principle behind the Repository pattern. Then you can implement it in whatever technology you want. With that in mind, let’s start with the definition of the Repository pattern:
“A Repository mediates between the domain and data mapping layers, acting like an in-memory domain object collection. Client objects construct query specifications declaratively and submit them to Repository for satisfaction. Objects can be added to and removed from the Repository, as they can from a simple collection of objects, and the mapping code encapsulated by the Repository will carry out the appropriate operations behind the scenes.”
Repository pattern separates the data access logic and maps it to the business entities in the business logic. Communication between the data access logic and the business logic is done through interfaces.
To put it simply, Repository pattern is a kind of container where data access logic is stored. It hides the details of data access logic from business logic. In other words, we allow business logic to access the data object without having knowledge of underlying data access architecture.
The separation of data access from business logic have many benefits. Some of them are:
- Centralization of the data access logic makes code easier to maintain
- Business and data access logic can be tested separately
- Reduces duplication of code
- A lower chance for making programming errors
Repository design pattern is fully stick onto interfaces. An interface acts like a contract which specify what an concrete class must implement. Let’s explore it a little bit. Suppose we have two data objects Uploader and Video, what are common set of operations that can be applied to these two data objects? In most situations we want to have the following operations:
- Get all records
- Get paginated set of records
- Create a new record
- Get record by it’s primary key
- Get record by some other attribute
- Update a record
- Delete a record
If we implement these operations for each object, you can imagine that the number of duplicate code in the entire application. For small application it doesn’t matter, but for larger applications it is a bad news.
As we know what is a repository, we can use it for flexible controller methods implementation.
Illustration of problem that we are not using Repositories
It is better to know the problem with an example. For example, suppose we have the following index method in the UserController.php file.
Code:
/** * Display a listing of the resource. * * @return Response */ public function index() { return User::all(); }
The controller method index() simply lists all the records from the database. It is not flexible, since User::all() fully rely on Eloquent ORM and it doesn’t support such databases. What would you do if you needed to switch databases to use Redis or Mongo instead? You would have to find all of the instances that you used Eloquent in your application and update them. This isn’t very flexible in a larger application.
There’s no need to tightly couple your application to one particular ORM or database if you don’t have to. You should seize any opportunity to build future flexibility into your application!
Flexibility through Repositories
In order to separate our Controllers from the database in right manner, we are going to abstract that interaction into repositories. A repository is simply an interface between two things.
So instead of referencing Eloquent directly, we can reference UserRepository. We can then bind UserRepository to EloquentUserRepository so that Laravel knows that whenever we mention UserRepository we want an instance of EloquentUserRepository. Now that we have abstracted the database layer into repositories it makes it much easier to switch database ORM.
For example, if you wanted to use Mongo instead, you would simply create a MongoUserRepository and bind UserRepository to it rather than EloquentUserRepository.
Now, whenever Laravel wants a UserRepository it will return MongoUserRepository.
So you don’t have to change any of the code in your Controllers on a database technology change.
What do we need to build?
In order for our application to use Repositories, first we need to set things up.
We are going to need:
- UserRepository
- EloquentUserRepository
- A way to bind UserRepository and EloquentUserRepository
We can use Service Providers to bind things together. Service Providers are just like bootstrap classes that allow you to set things up in a certain way.
Project structure
It’s pretty bad practice to just dump stuff in a random file or leave things in the wrong directory. As your project gets bigger, things will become a mess and everything will be unmaintainable.
Instead, we are going to create a new directory called app/lib to store all of this kind of stuff.
In order for this directory to be included in the autoload, you also need to add it to your composer.json file.
In the classmap array, add your new directory:
Code:
"autoload": { "classmap": [ "app/lib" ] }
Run the following command in Terminal to update your autoload classmap:
Code:
composer dump-autoload
Next, in the app/lib directory, I’m going to create another directory MyApp to keep all of the MyApp specific things together.
Next, we are going to create another directory under app/lib/MyApp called Storage to keep all of my database repositories together. And finally, we are going to separate each resource into its own directory.
So our final directory structure is: app/lib/MyApp/Storage/User.
Creating the User Repository
The first thing to create is the UserRepository.php interface inside app/lib/myapp/storage/User directory.
Code:
Creating the Eloquent User Repository
Next we will create the EloquentUserRepository.php file. Remember, this is simply an abstraction from the database that implements UserRepository:
Code:
Creating the Service Provider
Next we need to create the Service Provider which will bind the two repositories together.
In app/lib/myapp/storage create a new file called StorageServiceProvider.php, and copy the following code:
Code:
app->bind( 'MyApp\Storage\User\UserRepository', 'MyApp\Storage\User\EloquentUserRepository' ); } }
The register method is automatically called on the Service Provider. This allows you to bootstrap your files so everything is loaded correctly.
Finally you need to make Laravel aware of this Service Provider by placing it in the providers array under app/config/app.php:
Code:
'providers' => array( … 'MyApp\Storage\StorageServiceProvider' ),
Implementing the Repository in the Controller
Now we can start using the Repository in the UserController. Open up UserController.php and add the use line to the top of your file:
Code:
Next you need to create a __construct method that injects an instance of the UserRepository into the Controller and sets it to the $this->user property:
Code:
public function __construct(User $user) { $this->user = $user; }
And finally, you can set the index method to return all of the users:
/** * Display a listing of the resource. * * @return Response */ public function index() { return $this->user->all(); }
Setting up a route and testing in the browser
Now all we need to do to ensure that everything is working correctly is to set up a route to hit so we can see what is being returned in the browser.
Open up your routes.php file and copy the following to define a new route to the UserController:
Code:
Route::resource(‘user’, ‘UserController’);
Now if you fire up the server and hit “/user” in your browser, you should see a JSON array displayed on the screen (as long as you actually have users in your database!).
Switching Repositories
Now if you ever need to switch ORM or database in the future, all you have to do is to create a new database Repository and update the bindings in your Service Provider.
For example, to switch to Mongo, all you would have to do is to copy the EloquentUserRepository.php and create MongoUserRepository.php. You would then replace the Eloquent code with Mongo code so that the same data is returned.
In your Service Provider, you would simply update the binding to use the Mongo repository instead of the Eloquent repository:
Code:
$this->app->bind( 'MyApp\Storage\User\UserRepository', //'MyApp\Storage\User\EloquentUserRepository' 'MyApp\Storage\User\MongoUserRepository' );
Now you have completely switched databases without having to change any of your Controller code!
Wrapping Up
Repositories allow you to create a flexible abstraction layer between your database and your Controller. Doing this enables you to separate those concerns and it prevents your Controllers being too tightly coupled with your Database.
Your Controllers don’t care what storage facility you are using to persist data, and so by using Repositories, you are able to make a clean abstraction.
This makes it beautifully simple to switch database types at some point in the future.
Credits: https://bosnadev.com/