Search code examples
phplaravelinterfacerepository

laravel repository - why need to call to interface instead of calling directly to repository file?


I've read about repository pattern.So, I created UserRepositoryInterface.php file

namespace App\Interfaces;

use Prettus\Repository\Contracts\RepositoryInterface;

interface UserInterface extends RepositoryInterface
{
    // Code
}

Then I created UserRepository.php:

<?php

namespace App\Repositories;

use Prettus\Repository\Eloquent\BaseRepository;
use App\Interfaces\UserInterface;

class UserRepository extends BaseRepository implements UserInterface
{
    public function model()
    {
        return User::class;
    }
}

Finally, I bind interface to class in RepositoryServiceProvider.php

    public function boot()
    {
        $this->app->bind(UserInteface::class, UserRepository::class);
    }

When inject repository to class, I wonder that should I inject with UserRepository or UserInterface. I've read that UserInterface should be injected, but I don't understand why we not just using UserRepository, it can be faster, isn't it? Someone help?

Thanks.


Solution

  • The whole point of injecting interface instead concrete class is to have it easier for change/extend/maintenance/test.

    Now, in your case here, you have injected UserRepositoryInterface in some controller method or constructor let's say. But UserRepository class is still tightly coupled to Eloquent's code (since it's extending Eloquent's class).

    Now imagine you are getting users from another provider/source (maybe from 3rd party through API call). That code you can set in separate class \App\Repositories\ApiCallUserRepository (for instance).

    You would also set ApiCallUserRepository (newly created class) to implement \App\Interfaces\UserInterface.

    When you have all of this, only change you should make is change in provider or in other words you would just need to instruct application which concrete class to use when interface has been injected dependently. Also, this means that same structure of data should be provided from both concrete classes (repository providers) to class that uses repository (i.e. controller's method), or at least receiving data class/code should expect providing structure whether it was Eloquent Collection whether it's some other type of collection.

    This way you have nicely set service that gets users for example. And you can easily choose from which provider you want to get users.

    It's not all: in time of execution (i.e. when request is made) you can set appropriate concrete class or make additional code regarding by any arbitrary rules. In Laravel's service container check when()->needs()->give() but also I warmly recommend you to go again through full (page) docs.

    Also don't limit yourself, but go through other generic and specific articles about DI:

    php-di

    designpatternsphp

    Symfony DependencyInjection Component

    laminas-di

    Maybe all of this seems like overhead but in reality it is a good starting position for extending application in good, standard, maintainable, and testable way.