1
\$\begingroup\$

I'm trying to implement Dependency Injection in one of my projects. It's a project that when I started I didn't had much experience with sotware development, but now I feel like it's time to do a bit of refactoring and improve it. I was going to start working with Unit Tests using PHPUnit, but the very first thing I saw is that I would need to do Dependency Injenction first.

I'm using PHP 8.2 and MySql 10.4.28

Today my code looks like this (very simplified for demo purposes):

Note: The application serves only as an API, there is no view, that is done with Angular in the Frontend.

$router = new Router();

$router->set404(function () {
  header('HTTP/1.1 404 Not Found');
  Response::error(ConstResponse::NOTFOUND);
});

$router->mount('/api/v1', function () use ($router) {
  $router->setNamespace('AppName\Module\Auth');

  $router->post('/auth/login', 'AuthController@login');
});

$router->run();
class AuthController extends Controller {
  public function login(): Response {
    try {
      $this->checkFields(BaseAuth::LOGIN);
  
      $response = AuthService::login($this->post->password, $this->post->email);
    } catch (Exception $error) {
      return $this->gerenciarExcecao($error);
    } finally {
      $this->dbh->closeConnection();
    }
  
    return Response::success('Successfull login', $response);
  }
}
class AuthService {
  public static function login(string $password, string $email): DtoAuthLoginResponse {
    $authRepository = new AuthRepository();
    $user = $authRepository->login($email);

    // This is indeed a static class, with just methods that uses native PHP functions to validate the password
    PasswordService::checkPasswordMatch($password, $user->password);

    $authRepository->logAccess($user->id);

    if (!$user->is_valid) {
      AppUserService::validateUser($user->id);
    }

    $token = JwtService::generateJwt($user->id, $user->type);

    return new DtoAuthLoginResponse($user, $token);
  }
}
class AppUserService {
  public static function validateUser(int $user_id): Void {
    $repository = new AppUserRepository();
    $repository->validateUser($user_id);
  }
}
class JwtService {
  public static function gerarJwt(int $user_id, int $type): String {
    $repository = new JwtRepository();
    $user = $repository->getUser($user_id, $type);

    $hashMd5 = self::generateHashMd5($user);

    $jwt = [
      'iss' => $_ENV[ConstEnv::JWT_DOMAIN],
      'iat' => time(),
      'exp' => self::generateExpire(),
      'qsh' => $hashMd5,
      'context' => [
        // ...
      ],
    ];

    return self::generateToken();
  }

The class Repository classes are only responsible to do DB queries.

The classes PasswordService, AppUserService and JwtService I converted to static just to avoid having to instantiate it. No other reason. It made the code simple to use, at least that's what I thought when I first created it, almost 2 years ago.

Based on some content I've seen online (medium posts, youtube, reddit and stackoverflow) everyone says to use DI, as it will resolve the problem I have in the AuthService, where it's tightly coupled with the other 3 classes, making it hard to test and maintain.

The problem is that all the content I found is giving basic examples. Ok, I understand the whole idea behind DI (It least I think I do). But if I move the dependecies instantiation to the controller and pass as parameter to AuthService, I'm not going to resolve the problem, I'll just move it to another class.

I saw a very few content about using Container DI, which is going to autoresolve DI on the constructor. But then, if I have a class with 5 methods where each method depends on 3 different other classes, I'll have to instantiate all of 15 classes but use only 3 of them. At least that's what I understood.

There is the option to resolve the DI on the method via params, but I could ended up with a method with many many params, and for me that doesn't seem to resolve the issue.

So basically this whole approach to implement it is still a bit vague for me, because it seems that I'm not actually resolving the issue, but rather moving it around. Of course I feel like I'm missing a huge part of the whole deal, I just don't know what it is and how to solve it.

I'm in the very beggining of this "refactoring" so any suggestions are welcome. For example, if there is a better Router package for this case, It's ok for me to switch over, as most of them have almos the same mechanics on how to setup the routes.

Any tips and advices are really appreciated!

\$\endgroup\$
2
  • \$\begingroup\$ Honestly, this may be better suited to stackoverflow.com instead. In any case, you identified the problem with dependencies. Now, what I'm not sure is how you envision the controller code to evolve. Generally, your controller either gets all dependencies injected or it gets the DI container (which you absolutely want!) injected. Many such containers also offer features like automatically creating dependencies even without you explicitly registering them as a service. \$\endgroup\$
    – uli
    Commented Nov 24, 2023 at 11:13
  • \$\begingroup\$ You did indeed misunderstood the purpose of Code Review. Here we review code that is already working correctly, not simplified code with lots of parts missing. We should preferably be able to run the code so we can observe its behavior. Have you ever tried to refactor code you can't run and only guess at what the parts are supposed to do? See: How do I ask a good question? Include all the code you want reviewed and, if needed, put a link to supporting code on something like GitHub. We also look at everything in your code, not only DI. \$\endgroup\$ Commented Nov 24, 2023 at 20:23

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Browse other questions tagged or ask your own question.