Injection Symfony 2 EntityManager en service

96

J'ai créé mon propre service et j'ai besoin d'injecter doctrine EntityManager, mais je ne vois pas que cela __construct()est appelé sur mon service et l'injection ne fonctionne pas.

Voici le code et les configurations:

<?php

namespace Test\CommonBundle\Services;
use Doctrine\ORM\EntityManager;

class UserService {

    /**
     *
     * @var EntityManager 
     */
    protected $em;

    public function __constructor(EntityManager $entityManager)
    {
        var_dump($entityManager);
        exit(); // I've never saw it happen, looks like constructor never called
        $this->em = $entityManager;
    }

    public function getUser($userId){
       var_dump($this->em ); // outputs null  
    }

}

Voici services.ymldans mon bundle

services:
  test.common.userservice:
    class:  Test\CommonBundle\Services\UserService
    arguments: 
        entityManager: "@doctrine.orm.entity_manager"

J'ai importé ce .yml config.ymldans mon application comme ça

imports:
    # a few lines skipped, not relevant here, i think
    - { resource: "@TestCommonBundle/Resources/config/services.yml" }

Et quand j'appelle le service dans le contrôleur

    $userservice = $this->get('test.common.userservice');
    $userservice->getUser(123);

$this->emJ'obtiens un objet (non nul), mais dans UserService est nul, et comme je l'ai déjà mentionné, le constructeur sur UserService n'a jamais été appelé

Encore une chose, Controller et UserService sont dans différents bundles (j'en ai vraiment besoin pour garder le projet organisé), mais quand même: tout le reste fonctionne bien, je peux même appeler

$this->get('doctrine.orm.entity_manager')

dans le même contrôleur que j'utilise pour obtenir UserService et obtenir un objet EntityManager valide (non nul).

On dirait qu'il me manque un morceau de configuration ou un lien entre UserService et Doctrine config.

Andrey Zavarin
la source
Avez-vous essayé l'injection de setter? Ça marche?
gremo
Si par 'injection de setter' vous voulez dire ajouter une méthode setter pour EntityManager sur mon service et appeler le contrôleur avec $ this-> get ('doctrine.orm.entity_manager') comme paramètre, alors oui, j'ai essayé et cela fonctionne. Mais j'aime vraiment utiliser une injection appropriée via la configuration
Andrey Zavarin
2
Je veux dire ceci: symfony.com/doc/current/book/… de toute façon __constructorest l'erreur.
gremo
Euh, je n'ai pas essayé l'injection de setter. __construct a résolu le problème, mais de toute façon, merci pour votre aide!
Andrey Zavarin

Réponses:

112

La méthode du constructeur de votre classe doit être appelée __construct() , pas __constructor():

public function __construct(EntityManager $entityManager)
{
    $this->em = $entityManager;
}
richsage
la source
2
Salut, dans cet exemple, comment pourrais-je changer la connexion par défaut à une autre?
ptmr.io
Oui, mais ce serait encore mieux si vous utilisiez une interface. public function __construct(EntityManagerInterface $entityManager)
Hugues D
65

Pour référence moderne, dans Symfony 2.4+, vous ne pouvez plus nommer les arguments de la méthode d'injection de constructeur. Selon la documentation que vous transmettriez:

services:
    test.common.userservice:
        class:  Test\CommonBundle\Services\UserService
        arguments: [ "@doctrine.orm.entity_manager" ]

Et puis ils seraient disponibles dans l'ordre dans lequel ils ont été listés via les arguments (s'il y en a plus d'un).

public function __construct(EntityManager $entityManager) {
    $this->em = $entityManager;
}
Chadwick Meyer
la source
8
Vous pouvez faire un: conteneur d'application / console: déboguer et découvrir quels services vous exécutez également.
Hard Fitness
18

Remarque à partir de Symfony 3.3 EntityManager est déprécié. Utilisez plutôt EntityManagerInterface.

namespace AppBundle\Service;

use Doctrine\ORM\EntityManagerInterface;

class Someclass {
    protected $em;

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

    public function somefunction() {
        $em = $this->em;
        ...
    }
}
Robert Saylor
la source
1
Juste au cas où quelqu'un trébucherait et serait confus: le EntityManager n'a certainement pas été déprécié. L'utilisation de l'interface facilite le câblage automatique et est recommandée mais n'est en aucun cas nécessaire. Et l'interface existe depuis longtemps. Rien de vraiment nouveau ici.
Cerad
Voilà la réponse. Cependant, veuillez faire référence à: stackoverflow.com/questions/22154558/…
tfont
Mettez à jour ma propre solution. La bonne façon maintenant devrait être d'utiliser des entités et des référentiels. Entity Manager est déjà naturellement injecté dans un référentiel. Vous pouvez voir un exemple ici: youtu.be/AHVtOJDTx0M
Robert Saylor
7

Depuis 2017 et Symfony 3.3, vous pouvez enregistrer Repository en tant que service , avec tous ses avantages.

Consultez mon article Comment utiliser le référentiel avec Doctrine as Service dans Symfony pour une description plus générale.


Pour votre cas spécifique, le code original avec réglage ressemblerait à ceci:

1. Utilisation dans vos services ou contrôleur

<?php

namespace Test\CommonBundle\Services;

use Doctrine\ORM\EntityManagerInterface;

class UserService
{
    private $userRepository;

    // use custom repository over direct use of EntityManager
    // see step 2
    public function __constructor(UserRepository $userRepository)
    {
        $this->userRepository = $userRepository;
    }

    public function getUser($userId)
    {
        return $this->userRepository->find($userId);
    }
}

2. Créez un nouveau référentiel personnalisé

<?php

namespace Test\CommonBundle\Repository;

use Doctrine\ORM\EntityManagerInterface;

class UserRepository
{
    private $repository;

    public function __construct(EntityManagerInterface $entityManager)
    {
        $this->repository = $entityManager->getRepository(UserEntity::class);
    }

    public function find($userId)
    {
        return  $this->repository->find($userId);
    }
}

3. Enregistrer les services

# app/config/services.yml
services:
    _defaults:
        autowire: true

    Test\CommonBundle\:
       resource: ../../Test/CommonBundle
Tomáš Votruba
la source