Home > Blockchain >  How to use Method Injection with interfaces
How to use Method Injection with interfaces

Time:08-09

interface UserRepositoryInterface {
  public function getUser($userType, $login): Builder;
}

class UserRepository implements UserRepositoryInterface {
  public function getUser('clientA', 'user-login', EmailValidatorInterface $emailValidator, PhoneValidatorInterface $phoneValidator): Builder {} 
}

Method UserRepository@getUser throws an error because he is not abiding by the contract UserRepositoryInterface@getUser. How can I remove an error, while using method injection?

CodePudding user response:

There are several ways how to solve this kind of error. I 'm not a big fan of overriding the signature of an interface provided method. I prefer DI over the constructor of a class.

Dependency Injection with the constructor

This one makes more sence in my eyes, because it is cleaner. Before overriding interface method signatures you 'll always have to check if the additional parameters are used in more than that one method. If this is the case, just inject the dependency over the constructor.

<?php
declare(strict_types=1);
namespace Marcel;

class UserRepository implements UserRepositoryInterface
{
    protected EmailValidatorInterface $emailValidator;
    protected PhoneValidatorInterface $phoneValidator;
    
    public function __construct(
        EmailValidatorInterface $emailValidator,
        PhoneValidatorInterface $phoneValidator
    ) {
        $this->emailValidator = $emailValidator;
        $this->phoneValidator = $phoneValidator;
    }

    public function getUser(string $userType, string $login): Builder
    {
        // $this->emailValidator and $this->phoneValidator are available
    }
}

As you can see this one is exact what the interface implements. No additional parameters. Just clean and simple dependency injection. This type of injection needs a simple factory or something else, that initializes the dependencies.

Extending an interface implemented method

If you can not use dependency injection - for whatever reason - you can extend the method signature from the interface by providing a default value for each additional parameter.

<?php
declare(strict_types=1);
namespace Marcel;

class UserRepository implements UserRepositoryInterface
{
    public function getUser(
        string $userType, 
        string $login,
        ?EmailValidatorInterface $emailValidator = null,
        ?PhoneValidatorInterface $phoneValidator = null
    ): Builder
    {
        // $emailValidator and $phoneValidator are available
        // just validate them against null
    }
}

This is ugly af but it will work. What happens, when you check if a class implements the UserRepositoryInterface interface? It just secures, that there is a method getUser, which takes two parameters. The interface knows nothing about any other parameters. This is inconsistency in its purest form.

CodePudding user response:

In most DI systems you’d solve this in the constructor instead.

interface UserRepositoryInterface {
  public function getUser($userType, $login): Builder;
}

class UserRepository implements UserRepositoryInterface {
  public function __construct(
    public readonly EmailValidatorInterface $emailValidator,
    public readonly PhoneValidatorInterface $phoneValidator
  ){}

  public function getUser('clientA', 'user-login'): Builder {} 
}
  • Related