1

I am using php-di and Doctrine together. To use Doctrine there is a bootstrap.php file which constructs the $entityManager object. The $entityManager object is defined globally in that file so to use it in my classes I have to inject it.

For example assume the class below:

<?php
interface IAccountService{
    function login(string $username, string $password);
}
class AccountService implements IAccountService {

    private $entityManager;

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

    public function login(string $email, string $password){
        $q = $this->entityManager->createQueryBuilder()
            ->select('us.id, us.name, us.email, us.passwordHashed')
            ->from('User', 'us')
            ->where('us.email = ?1 AND us.passwordHashed = ?2')
            ->setMaxResults( '1' )
            ->setParameter(1,$email)
            ->setParameter(2, HASHHELPER::hashPasswordSHA512($password, $email))
            ->getQuery();

        // echo $q->getSql();

        $users = $q->getResult();

        // print_r($users);

        if(!empty($users) && count($users) > 0){
            $_SESSION["USER"] = $users[0];
            return true;
        }
        else{
            return false;
        }
    }
}
?>

But the type of $entityManager is not well defined and either when I call echo gettype($entityManager); it prints "object" as result. So I think I need to inject this parameter by its name instead of its type. I mean something like this:

$container->set('$entityManager', $entityManager);

But this does not work. What's the solution and the best way?

halfer
  • 19,824
  • 17
  • 99
  • 186
ConductedClever
  • 4,175
  • 2
  • 35
  • 69

2 Answers2

2

Can you show how are you injecting EntityManager now?

Also, it's a good practice to use type-hinting:

public function __construct(EntityManager $entityManager) {
    $this->entityManager = $entityManager;
}

UPDATE:

Ok, I usually use PHP-DI with a PHP configuration file (http://php-di.org/doc/php-definitions.html). It would look something like this:

return [
AccountService::class => DI\object(AccountService::class)->constructor("here goes EntityManager object")
];
Sauron1953
  • 37
  • 7
  • As I mentioned I don't have a typing like `EntityManager` you've added. And I am not injecting it now. It is the question. – ConductedClever Sep 02 '17 at 06:42
  • You mean something like this (?) : `$container->set('IAccountService', \DI\object('AccountService')->contructor($entityManager));` I think this is a bad solution. Because I should inject all the paramaeters of `AccountService` by hand and change this definition anytime I change `AccountService`. More problematic when I use this $entityManager in many classes like `AccountService`! Am I wrong? – ConductedClever Sep 02 '17 at 07:17
  • Both answers proposed by @Sauron1953 are correct, either type-hint the parameter or write a configuration file. You want to do `->contructor(\DI\get('EntityManager'))` that way you define the dependency `'EntityManager'` separately (with a [closure](http://php-di.org/doc/php-definitions.html#factories) for example). – Matthieu Napoli Sep 02 '17 at 07:25
  • @ConductedClever Yes, you have to do changes by hand, but you make them only at one place. If you could use type-hinting, the autowiring would do that magic for you. – Sauron1953 Sep 02 '17 at 07:33
  • @MatthieuNapoli I think without specifying the type `EntityManager` I your solution can't be used too. – ConductedClever Sep 02 '17 at 07:41
  • @Sauron1953 thanks to your solution, I have voted your solution up. But the question of injecting by variable name is open. – ConductedClever Sep 02 '17 at 07:42
  • 1
    I'm quite sure that you can't inject according to variable name. – Sauron1953 Sep 02 '17 at 08:08
  • @Sauron1953 so I think this is the answer. Have you seen any document about this? – ConductedClever Sep 02 '17 at 09:17
  • @ConductedClever Actually, check this: http://php-di.org/doc/inject-on-instance.html I don't have my business laptop at the moment , so I can't test it. – Sauron1953 Sep 02 '17 at 09:39
  • 1
    @ConductedClever you can't inject by parameter name (source: I'm the author of PHP-DI) – Matthieu Napoli Sep 02 '17 at 13:25
  • @MatthieuNapoli (the author of php-di), thanks for your clarification. – ConductedClever Sep 03 '17 at 04:24
0

The problem have solved after facing this link which shows the namespace and class name of $entityManager but the question of injecting according to variable name is still open. By now, the new source code of mine is like this:

AccountService.php

<?php
interface IAccountService{
    function login(string $username, string $password);
}
class AccountService implements IAccountService {

    private $entityManager;

    public function __construct(Doctrine\ORM\EntityManagerInterface $entityManager) {
        $this->entityManager = $entityManager;
    }

    public function login(string $email, string $password){
        $q = $this->entityManager->createQueryBuilder()
            ->select('us.id, us.name, us.email, us.passwordHashed')
            ->from('User', 'us')
            ->where('us.email = ?1 AND us.passwordHashed = ?2')
            ->setMaxResults( '1' )
            ->setParameter(1,$email)
            ->setParameter(2, HASHHELPER::hashPasswordSHA512($password, $email))
            ->getQuery();

        // echo $q->getSql();

        $users = $q->getResult();

        // print_r($users);

        if(!empty($users) && count($users) > 0){
            $_SESSION["USER"] = $users[0];
            return true;
        }
        else{
            return false;
        }
    }
}
?>

routes.php

<?php
  spl_autoload_register(function ($class_name) {
    switch ($class_name){
      case 'AccountController':
        require_once 'controllers/account_controller.php';
        break;
      case 'AccountService':
      case 'IAccountService':
        require_once 'services/account_service.php';
        break;
      case 'URLHELPER':
        require_once 'helpers/URLHELPER.php';
        break;
      case 'STRINGHELPER':
        require_once 'helpers/STRINGHELPER.php';
        break;
      case 'HASHHELPER':
        require_once "helpers/HASHHELPER.php";
        break;
      case 'User':
        require_once "models/entities/user.php";
        break;
    }
  });

  function call($controller, $action) {
    global $entityManager;
    $container = DI\ContainerBuilder::buildDevContainer();
    $container->set('IAccountService', \DI\object('AccountService'));
    $container->set('Doctrine\ORM\EntityManagerInterface', $entityManager);

    // require the file that matches the controller name
    require_once('controllers/' . $controller . '_controller.php');

    // create a new instance of the needed controller
    switch($controller) {
      case 'home':
        $controller = $container->get('HomeController');
        break;
      case 'account':
        $controller = $container->get('AccountController');
        break;
      default:
        $controller = 'home';
        $action = 'index';
    }

    // call the action
    $controller->{ $action }();
  }

  // just a list of the controllers we have and their actions
  // we consider those "allowed" values
  $controllers = array(
    'home' => ['index', 'error']
    ,'account' => ['login']
  );

  // check that the requested controller and action are both allowed
  // if someone tries to access something else he will be redirected to the error action of the pages controller
  if (array_key_exists($controller, $controllers)) {
    if (in_array($action, $controllers[$controller])) {
      call($controller, $action);
    } else {
      call('home', 'error');
    }
  } else {
    call('home', 'error');
  }
?>
halfer
  • 19,824
  • 17
  • 99
  • 186
ConductedClever
  • 4,175
  • 2
  • 35
  • 69