lundi 1 mai 2017

How can I make a facade that uses a class that requires several repositories in Laravel?

I have been using Laravel for almost a year now, but I am very new to creating my own packages and using Contracts, Repositories, Facades, etc..., so please bear with me.

I have having issues understanding if I am registering a facade correctly in my service provider. Here is the context (assume namespaces and imports have been correctly done. I am not including them so that this does not get too convoluted):

I want to create a facade called AdminServices to access a class called AdminServices:

class AdminServices implements AdminServicesContract
{
    private $check;

    public function __construct(CheckAdminContract $check)
    {
        $this->check = $check;
    }

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

You'll notice that this class requires a contract, CheckAdminContract. This contract is implemented in the CheckAdmin class. Notice that this class requires a UserRepository:

class CheckAdmin implements CheckAdminContract
{

    private $userRepository;

    public function __construct(UserRepository $userRepository)
    {
        $this->userRepository = $userRepository;
    }

    public function userIsAdmin(User $user)
    {
        return $user->roles()->whereAdmin()->count() > 0;
    }

    public function userIsAdminById($user_id)
    {
        $user = $this->userRepository->getById($user_id);
        return $this->userIsAdmin($user);
    }

    public function userIsSuperAdmin(User $user)
    {
        return $user->roles()->whereSuperAdmin()->count() > 0;
    }

    public function userIsSuperAdminById($user_id)
    {
        $user = $this->userRepository->getById($user_id);
        return $this->userIsSuperAdmin($user);
    }
}

Here is the UserRepository:

interface UserRepository
{
    public function getById($user_id);
}

Here is the EloquentUserRepository that implements the UserRepository:

class EloquentUserRepository implements UserRepository
{
    private $model;

    public function __construct()
    {
        $this->model = new User;
    }

    public function getById($user_id)
    {
        return $this->model->findOrFail($user_id);
    }
}

Here is the Facade I want to register:

use Illuminate\Support\Facades\Facade;

class AdminServices extends Facade
{
    protected static function getFacadeAccessor()
    {
        return 'admin-services';
    }
}

Here is what I have registered in my Service Provider (all of the classes are properly imported via use directives):

public function register()
{
    $this->app->singleton(UserRepository::class, EloquentUserRepository::class);
    $this->app->singleton(CheckAdminContract::class, CheckAdmin::class);
    $this->app->singleton(AdminServicesContract::class, AdminServices::class);
    $this->app->singleton('admin-services', function(){
        $userRepository = new EloquentUserRepository();
        $checkAdmin = new CheckAdmin($userRepository);
        return new AdminServices($checkAdmin);
    });
}

So here is my big question:

Do I really have to explicitly instantiate all the repository and contract implementations when registering the facade accessor? I have already registered them as singletons above, so in my naive mind, I believe that instantiating these things again would be doing the work all over again, and if I decided to use a different implementation of these contracts and repositories, then I would have to change them more than once, which again in my naive mind seems like I am doing something wrong.

Can you please let me know if I am indeed doing this correctly in singleton for the facade accessor? Can you suggest a way that you have done something similar or a better way to do it?

Also, if you see that I am not doing something correctly or that my code is not very well written, please let me know how I can improve. Again, I am very new to these topics but I feel that I have a good enough understanding of them to do them somewhat properly. But I really would like some feedback so that I don't keep doing these things wrong (if I am doing them wrong).

Also, if there is a better way for me to structure or ask this question, again please let me know so that I don't make the same mistake more than once.

Thank you in advance for your help!



via Chebli Mohamed

Aucun commentaire:

Enregistrer un commentaire