2
votes

I have followed many tutorials of Laravel repository and msot of the tutorial similar.one of the link below

https://itsolutionstuff.com/post/laravel-5-repository-pattern-tutorial-from-scratchexample.html

Step 1: Create Interface

In first step we have to create Interface, before create Repositories(app/Repositories) directory in app folder. Also we need top create User(app/Repositories/User) folder inside Repositories folder.

Ok, now first we will create UserInterface in User directory, so first create UserInterface.php file and put bellow code in that file:

app/Repositories/User/UserInterface.php

namespace App\Repositories\User;


interface UserInterface {


    public function getAll();


    public function find($id);


    public function delete($id);
}

Step 2: Create Repository

Ok, in this step we will create UserRepository.php for write database login, in this file we will write our database login code. so, first create UserRepository.php file in User directory and put bellow code.

app/Repositories/User/UserRepository.php

namespace App\Repositories\User;


use App\Repositories\User\UserInterface as UserInterface;
use App\User;


class UserRepository implements UserInterface
{
    public $user;


    function __construct(User $user) {
$this->user = $user;
    }


    public function getAll()
    {
        return $this->user->getAll();
    }


    public function find($id)
    {
        return $this->user->findUser($id);
    }


    public function delete($id)
    {
        return $this->user->deleteUser($id);
    }
}

Step 3: Create Service Provider

In this step we have to create Service Provider for bind UserInterface and UserRepository class. so let's create UserRepoServiceProvide.php` file in User folder and put following code:

app/Repositories/User/UserRepoServiceProvide.php

namespace App\Repositories\User;


use Illuminate\Support\ServiceProvider;


class UserRepoServiceProvide extends ServiceProvider
{
    /**
     * Bootstrap the application services.
     *
     * @return void
     */
    public function boot()
    {

    }


    /**
     * Register the application services.
     *
     * @return void
     */
    public function register()
    {
        $this->app->bind('App\Repositories\User\UserInterface', 'App\Repositories\User\UserRepository');
    }
}

Now, we have to add server provide in app.php file, so add UserRepoServiceProvide in config/app.php and add bellow line.

config/app.php

return [

....

'providers' => [

......,

App\Repositories\User\UserRepoServiceProvide::class,

]

....

]

Step 4: Create User Model

We have already User Model i think, so you have just need to add getAll(), findUser() and deleteUser() function. But you can also past bellow code too. So, let's put bellow code on your model.

app/User.php

namespace App;

use Illuminate\Foundation\Auth\User as Authenticatable;


class User extends Authenticatable
{
    protected $fillable = [
        'name', 'email', 'password',
    ];


    protected $hidden = [
        'password', 'remember_token',
    ];


    public function getAll()
    {
        return static::all();
    }


    public function findUser($id)
    {
        return static::find($id);
    }


    public function deleteUser($id)
    {
        return static::find($id)->delete();
    }
}

Step 5: Use In Controller

Now we are ready to use Our Repository Pattern in our Controller. So, let's add bellow code in your UserController.php file.

app/Http/Controllers/UserController.php

namespace App\Http\Controllers;


use Illuminate\Http\Request;
use App\Repositories\User\UserInterface as UserInterface;


class UserController extends Controller
{


    public function __construct(UserInterface $user)
    {
        $this->user = $user;
    }


    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function index()
    {
        $users = $this->user->getAll();
        return view('users.index',['users']);
    }


    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function show($id)
    {
        $user = $this->user->find($id);
        return view('users.show',['user']);
    }


    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function delete($id)
    {
        $this->user->delete($id);
        return redirect()->route('users');
    }
}

Now at last just fire bellow command because we have to auto load class.

composer update

php artisan optimize

My question is most of the tutorials injected user model in UserRepository so if do that i need to create repository for all models seperately.Is there any way so that i can use single repository and inject model

3

3 Answers

2
votes

You can, but i'm not sure this is a good solution. I use some kind of repository pattern as well in all my Laravel projects, but i'm setting it differently.

I've got a BaseRepository with all my standard functions as following :

<?php
namespace App\Repositories;
use Carbon\Carbon;
class BaseRepository {
    public $model;
    public function __construct($model){
        $this->model = $model;
    }
    public function all(){
        return $this->model->all();
    }
    public function getById($id){
        return $this->model->findorFail($id);
    }
    public function store($model){
        $model->created_at = Carbon::now();
        return $model->save();
    }
    public function update($model){
        $model->updated_at = Carbon::now();
        return $model->save();
    }
    public function destroy($model){
        return $model->delete();
    }
}

This way, in my controller, if i only need basics functions (those in my BaseRepository), i'm doing this :

use App\Models\MyModel;
use App\Repository\BaseRepository;

class XXX extends Controller {
    protected MyModelRepository;
    public function __construct(BaseRepository $baseRepository){
        $this->MyModelRepository = $baseRepository;
    }
}

This could fit your needs, but i don't think it's a good way to do this because you can need some specific functions depending on your models. So i'm creating dedicated repositories (one for each model) this way :

<?php
namespace App\Repository;
use App\Model\Maj;
class MajRepository extends BaseRepository {
    public function __construct(Maj $maj){
        $this->model = $maj;
    }
    public function all(){
        return $this->model->with('medias')->with('plugins')->get();
    }
    public function getById($id){
        return $this->model->with('medias')->with('plugins')->findorFail($id);
    }
}

So this specific repository related to my specific model extends the BaseRepository and is so allow to use all BaseRepositories functions. But it can also have it's own specific functions as you can see. Then i call it this way in my controllers :

<?php
namespace App\Http\Controllers;
use App\Model\Maj;
use App\Repository\MajRepository;
use Illuminate\Http\Request;
use Carbon\Carbon;
class WpMajController extends Controller {
    protected $majRepository;

    public function __construct(MajRepository $majRepository){
        $this->majRepository = $majRepository;
    }

 /**
  * Permet d'afficher la liste des suivi de mises à jour WP
  * @return view
  */
    public function index(){
        $majs = $this->majRepository->all();
        return view('wpMaj.index', compact('majs'));
    }
2
votes

I've seen these tutorials around a lot. It's very much an over engineered approach. It's entirely possible to do what you want.

The simplest is approach is as follows;

First, you want to set yourself up with a base repository, that all other repositories will extend. I use a common one for myself, which you can see here: https://github.com/ollieread/toolkit/blob/master/src/Repositories/BaseRepository.php (I'm linking because it's fairly large). The important bit is the following;

abstract class BaseRepository {
    protected $model;
    protected function make() {
        return new $this->model;
    }
    // rest of the code here
}

Now I can create myself a UserRepository as follows;

class UserRepository extends BaseRepository {
    protected $model = User::class;
    public function getAll(): Collection {
        return $this->make()->newQuery()->get();
    }
}

There's no messing around with interfaces (which 9 times out of 10 are not needed), which means you don't have to bind this to the IoC. You can type hint UserRepository and get an instance.

I'm also not injecting the model, because simply put, you only need to know the name of the class. When you actually need an instance you can run $this->make().

Notes About my BaseRepository

Through the wonderfulness of magic methods, you can call things like getOneById($id) and getByCategoryId($categoryId), without defining the methods yourself.

getOneById($id) => getOneBy('id', $id)
getByCategoryId($categoryId) => getBy('category_id', $categoryId)

However, if you're going to use these methods a lot, I would always suggest adding them to the docblock. So for example, the UserRepository would become;

/**
 * @method User make()
 * @method null|User getOneById(int $id)
 * @method Collection getBySurname(string $surname)
 */
class UserRepository extends BaseRepository {
    protected $model = User::class;
    public function getAll(): Collection {
        return $this->make()->newQuery()->get();
    }
}

This way IDEs will auto-suggest and detect return types.

There's also a delete method, but you can override that yourself if you wish.

0
votes

Repository Pattern is pretty awesome. (NB I think u should only use the repository pattern where necessary not for all even small implementations of your models to avoid being overkill and over-engineered projects)

I guess the Repository Pattern should be used where future maintenance of the project models is critical, not for all small CRUD implementations.