web-dev-qa-db-fra.com

Obtenir entityManager dans une entité

J'aimerais utiliser quelque chose comme:

$em = $this->getEntityManager();

À l'intérieur d'une entité.

Je comprends que je devrais le faire en tant que service mais, à des fins de test, je souhaite y accéder depuis une entité.

Est-il possible d'y parvenir?

J'ai essayé de:

$em = $this->getEntityManager();
$profile_avatar = $em->getRepository('bundle:Perfils')->findOneByUser($this-getId());

Mais ça ne marche pas.

Erreur fatale: Appel de la méthode non définie Proxies\webBundleEntityUserProxy :: getEntityManager () dans /opt/lampp/htdocs/web/src/Pct/bundle/Entity/User.php en ligne 449

Pourquoi j'essaie de le faire de cette façon?

J'ai 3 types d'utilisateurs: les utilisateurs de Facebook, Twitter et MyOwnWebsite. Chacun d'entre eux a un avatar différent qui relie le profil de Facebook, Twitter ou autre, si son utilisateur est myownwebsite, je récupère l'avatar depuis une URL dans une base de données. Pour l'instant, je ne veux pas créer de service, car j'essaie simplement de le faire fonctionner, de le tester et non de créer un déploiement final. C'est pourquoi j'essaie d'appeler le responsable d'entité à partir d'une entité. Je ne veux pas, à présent, modifier les fichiers de configuration, juste cette entité.

16
Reinherd

Comme l'a souligné (à nouveau) un commentateur, un responsable d'entité à l'intérieur d'une entité est une odeur de code. Pour la situation spécifique de l'OP où il souhaitait acquérir l'entité responsable, avec une moindre gêne, une simple injection de setter serait la plus fiable (contrairement à mon exemple initial d'injection via constructeur).

Pour ceux qui cherchent ici une solution supérieure au même problème, il y a 2 façons de le faire:

  1. Implémentation de l'interface ObjectManagerAware comme suggéré par https://stackoverflow.com/a/24766285/1349295

    use Doctrine\Common\Persistence\ObjectManagerAware;
    use Doctrine\Common\Persistence\ObjectManager;
    use Doctrine\Common\Persistence\Mapping\ClassMetadata;
    use Doctrine\ORM\Mapping as ORM;
    
    /**
     * @ORM\Entity
     */
    class Entity implements ObjectManagerAware
    {
        public function injectObjectManager(
            ObjectManager $objectManager,
            ClassMetadata $classMetadata
        ) {
            $this->em = $objectManager;
        }
    }
    
  2. Ou, en utilisant les rappels de cycle de vie @postLoad/@postPersist et en acquérant le gestionnaire d'entité à l'aide de l'argument LifecycleEventArgs comme suggéré par https://stackoverflow.com/a/23793897/1349295

    use Doctrine\Common\Persistence\Event\LifecycleEventArgs;
    use Doctrine\ORM\Mapping as ORM;
    
    /**
     * @ORM\Entity
     * @ORM\HasLifecycleCallbacks()
     */
    class Entity
    {
        /**
         * @ORM\PostLoad
         * @ORM\PostPersist
         */
        public function fetchEntityManager(LifecycleEventArgs $args)
        {
            $this->setEntityManager($args->getEntityManager());
        }
    }
    

Réponse originale

Utiliser une EntityManager à l'intérieur d'une Entity est TRÈS MAUVAISE PRATIQUE. Cela va à l'encontre de l'objectif de découplage de la requête et de la persistance des opérations de l'entité elle-même.

Mais si vous avez vraiment, vraiment, vraiment besoin d’un responsable d’entité dans une entité et que vous ne pouvez pas le faire autrement, vous l’injectez dans l’entité.

class Entity
{
    private $em;

    public function __contruct($em)
    {
        $this->em = $em;
    }
}

Puis invoquez comme new Entity($em).

21
Czar Pino

Le meilleur moyen est d’utiliser le cycle de vie: @ORM\HasLifecycleCallbacks

Et vous pouvez utiliser l'événement approprié pour obtenir le résultat souhaité:

@postLoad
@postPersist
...
5
onalbi

Appeler le gestionnaire d'entités à l'intérieur d'une entité est une mauvaise pratique! Vous devriez garder vos entités aussi simples que possible.

Dans quel but avez-vous besoin d'appeler le gestionnaire d'entités à partir d'une entité?

3
Ahmed Siouani

Au lieu d'utiliser Entity Manager dans votre entité, je pense que vous devriez créer un référentiel personnalisé pour votre entité. 

Dans votre fichier ORM d'entité, ajoutez une entrée comme suit (ou dans vos annotations de classe d'entité si vous n'utilisez pas YML): 

App\Bundle\Profils: 
# Replace the above as appropiate
    type: entity
    table: (your table)
    ....
    repositoryClass: App\Bundle\CustomRepos\ProfilsRepository
    # Replace the above as appropiate. 
    # I always put my custom repos in a common folder, 
    # such as CustomRepos

Maintenant, créez une nouvelle classe PHP qui a l'espace de nom ci-dessus: 

//Your ProfilsRepository.php
<?php
namespace App\Bundle\CustomRepos;

use Doctrine\ORM\EntityRepository;

class ProfilsRepository extends EntityRepository
{
    /**
     * Will return the user url avatar given the user ID
     * @param integer $userID The user id.
       @return string The avatar url
     */
    public function getUserProfile($userId)
    {
       $em = $this->getEntityManager();
       $qb = $em->createQueryBuilder();
       $qb->select... (your logic to retrieve the profil object);

       $query = $qb->getQuery();
       $result = $query->getResult();

       return $result;
    }
}

Enfin, dans votre contrôleur:

// Your controller
<?php
   namespace <class namespace>;
   ...
   use App\Bundle\CustomRepos\ProfilsRepository;
   use Symfony\Bundle\FrameworkBundle\Controller\Controller;
   ...
   class YourClassNameController extends Controller
   {
      public function yourAction()
      {
         $userId = <get the user ID>;
         // Pass the name of your entity manager to the 
         // getManager function if you have more than one and
         // didn't define any default
         $em = $this->getDoctrine()->getManager();
         $repo = $em->getRepository('Profils');
         $avatar = $repo->getUserProfile($userId);
         ...

      }
   }
2
Nicolas

Vous devez définir le fichier services.yml avec: 

services:
    your_service_name:
        class: AppBundle\Controller\ServiceController
        arguments: [ @doctrine.orm.entity_manager ]

Vous devez également définir le contrôleur avec le constructeur suivant:

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

et utilisez $this->em dans le contrôleur (par exemple $connection = $this->em->getConnection();)

0
Fabien Thetis