Laravel Repository-Service Pattern
Laravel Repository-Service Pattern
Normal Laravel application is based upon MVC (Model-View-Controller) design pattern, which derives that all the database relation are established in Model layer and Controller handles all responses from client and server and give output as per defined logic.
As Software Development Industry grows the maintainability of code became better and design patterns are modified too. One of those design pattern is Repository Pattern. The diagram given below describes the workflow of Repository Pattern.
Repository Layer
The first layer of Repository Pattern is Repository. This layer directly deals with Model. All the database related operations must be performed here.
Example
- Model (User.php)
<?php
namespace App;
use Illuminate\Notifications\Notifiable;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable
{
use Notifiable;
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'name', 'email', 'password',
];
/**
* The attributes that should be hidden for arrays.
*
* @var array
*/
protected $hidden = [
'password', 'remember_token',
];
/**
* The attributes that should be cast to native types.
*
* @var array
*/
protected $casts = [
'email_verified_at' => 'datetime',
];
}
- Repository (UserRepository.php)
Like Model and Controller Repository doesn’t have a command to make one Repository. For that you have to create the directory of the Repository in the App directory like, App\Repositories\UserRepository.php. The code of the repository is like the code mentioned below,
<?php
namespace App\Repositories;
use App\User;
use App\Interfaces\UserInterface;
class UserRepository implements UserInterface
{
protected $user;
public function __construct(User $user)
{
$this->user = $user;
}
public function index()
{
$users = $this->user::all();
return $users;
}
public function store($data)
{
$user = $this->user::create($data);
return $user;
}
public function show($id)
{
$user = $this->user::findOrFail($id);
return $user;
}
public function update($data, $id)
{
$user = $this->user::findOrFail($id);
$user->fill($data);
$user->save();
return $user;
}
public function destroy($id)
{
$user = $this->user::findOrFail($id);
$user->delete();
return $user;
}
}
- Interface (UserInterface.php)
To create an Interface say, UserInterface.php you again have to create a directory and interface manually as App\Interfaces\UserInterface.php. You must declare all functions of your Repository here. For e.g. if you are writing UserInterface.php then all fuctions of UserRepository.php must be declared here first. The code of in this example is as follows,
<?php
namespace App\Interfaces;
interface UserInterface
{
public function index();
public function store($data);
public function show($id);
public function update($data, $id);
public function destroy($id);
}
Interface & Repository bind
This Repository Pattern won’t work if you haven’t bind your Interface and Repository properly. Here in this case an example with step by step is given, how to bind each Repository and Interface. The binding of UserInterface.php and UserRepository.php is as follows,
- Go to
App\Providers\AppServiceProvider.php. - Add a line
$this->app->bind('App\Interfaces\UserInterface', 'App\Repositories\UserRepository');inside register method like below given code.
(AppServiceProvider.php) before
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* @return void
*/
public function register()
{
//
}
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
//
}
}
(AppServiceProvider.php) after adding bind
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* @return void
*/
public function register()
{
$this->app->bind('App\Interfaces\UserInterface', 'App\Repositories\UserRepository');
}
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
//
}
}
- Service (UserService.php)
Add a directory inside App directory like App\Services\UserService.php and add the code in following mannar,
<?php
namespace App\Services;
use App\Interfaces\UserInterface;
class UserService
{
protected $user;
public function __construct(UserInterface $user)
{
$this->user = $user;
}
public function index()
{
$users = $this->user->index();
return $users;
}
public function store($data)
{
$user = $this->user->store($data);
return $user;
}
public function show($id)
{
$user = $this->user->show($id);
return $user;
}
public function update($data, $id)
{
$user = $this->user->update($data, $id);
return $user;
}
public function destroy($id)
{
$user = $this->user->destroy($id);
return $user;
}
}
- Controller (UserController.php) Controller will be generated as per Laravel default rule, in this case using
php artisan make:controller UserController -rfor resourceful UserController. The controller code is as follows,
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Services\UserService;
class UserController extends Controller
{
protected $user;
public function __construct(UserService $user)
{
$this->user = $user;
}
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
$users = $this->user->index();
return view('users.index', [ 'users' => $users ]);
}
/**
* Show the form for creating a new resource.
*
* @return \Illuminate\Http\Response
*/
public function create()
{
return view('users.create');
}
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(Request $request)
{
$this->user->create($request->all());
return redirect('/users');
}
/**
* Display the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function show($id)
{
$user = $this->user->show($id);
return view('users.show', [ 'user' => $user ]);
}
/**
* Show the form for editing the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function edit($id)
{
$user = $this->user->show($id);
return view('users.edit', [ 'user' => $user ]);
}
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param int $id
* @return \Illuminate\Http\Response
*/
public function update(Request $request, $id)
{
$this->user->update($request->all(), $id);
return redirect('/users');
}
/**
* Remove the specified resource from storage.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function destroy($id)
{
$this->user->destroy($id);
return redirect('/users');
}
}
- Helper (Helper.php)
Helper completely justifies its name. Any additional operation other than CRUD operation can be written in helper. Just create a directory as App\Helpers\Helper.php and write your code inside it. For example as the code given below,
<?php
use Illuminate\Support\Facades\DB;
if (!function_exists('user_counts'))
{
function user_counts()
{
return DB::table('users')->count();
}
}
After writing this in Helper.php you can directly call it in controller and return its value directly to the view by storing the return value of the helper method into a variable.
COMMON ISSUES FOR HELPER
- Even if you have done the steps correctly, you can get error like, Seems like
Call to undefined function App\Http\Controllers\user_counts(). To fix this problem, you just have to goto yourcomposer.jsonfile and look for,
"autoload": {
"psr-4": {
"App\\": "app/"
},
"classmap": [
"database/seeds",
"database/factories"
]
},
And add the following lines into "autoload" object
"files": [
"app/helpers/helper.php"
]
After adding this your "autoload" object should look like as follows,
"autoload": {
"psr-4": {
"App\\": "app/"
},
"classmap": [
"database/seeds",
"database/factories"
],
"files": [
"app/helpers/helper.php"
]
},
After this just run composer dump-autoload into your terminal in the root project directory.
Note:
Although, all the fundamentals and procedures of Repository Pattern is described in above instructions but still there is one more standard that developers should follow to write clean code, i.e. “keep your controller as light-weight as possible” for there is one more step that you can include is write your validation in Request for that you can follow Laravel Official Documentation or by searching online “laravel request validation”.
Conclusion
Hope the content of this tutorial is useful for the readers. Happy Coding…
Application Setup Instructions
git clone https://github.com/tridibdawn/Repository-Pattern.gitgit checkout -b "<your-branch>"- copy .env.example into .env
- Setup database in .env
- Change CACHE_DRIVER=file to CACHE_DRIVER=array
- Run
php artisan config:cache - Run
composer install - Run
php artisan key:generate php artisan serve

