在实体中获取entityManager

时间:2013-02-04 10:25:26

标签: symfony doctrine

我想用,比如:

$em = $this->getEntityManager();

在实体内部。

我知道我应该将其作为服务,但出于某些测试目的,我想从实体访问它。

有可能实现吗?

我试过:

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

但是没有用。

  

致命错误:调用未定义的方法   Proxies \ webBundleEntityUserProxy :: getEntityManager()in    /opt/lampp/htdocs/web/src/Pct/bundle/Entity/User.php 在线    449

为什么我要这样做?

我有3种用户:Facebook,Twitter和MyOwnWebsite用户。他们每个都有不同的头像链接Facebook的个人资料,推特或其他,如果它的myownwebsite用户,我从数据库中的URL检索头像。目前,我不想创建服务,因为我只是想让它工作,测试它,而不是创建一个最终部署。所以这就是我试图从实体中调用实体管理器的原因。到目前为止,我不想修改配置文件,只需修改此实体。

5 个答案:

答案 0 :(得分:22)

正如评论者(再次)指出的那样,实体内部的实体经理是代码气味。对于OP的特定情况,他希望以最少的麻烦获得实体经理,简单的setter注入将是最可靠的(与我通过构造函数注入的原始示例相反)。

对于那些在此寻找同一问题的优秀解决方案的人来说,有两种方法可以达到这个目的:

  1. 按照https://stackoverflow.com/a/24766285/1349295

    的建议实施ObjectManagerAware界面
    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. 或者,使用@postLoad / @postPersist生命周期回调并使用https://stackoverflow.com/a/23793897/1349295建议的LifecycleEventArgs参数获取实体管理器

    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());
        }
    }
    
  3. 原始答案

    EntityManager内使用Entity是非常糟糕的做法。这样做会破坏将查询和持久操作与实体本身分离的目的。

    但是,如果你真的,真的,真的需要一个实体中的实体经理而不能做其他事情,那么就把它注入实体。

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

    然后调用new Entity($em)

答案 1 :(得分:5)

最好的方法是使用生命周期:@ORM\HasLifecycleCallbacks

您可以根据需要使用相应的事件:

@postLoad
@postPersist
...

答案 2 :(得分:3)

从实体内部调用实体管理器是一种不好的做法!你应该让你的实体尽可能简单。

您出于什么目的需要从实体调用实体管理器?

答案 3 :(得分:2)

我认为您应该做的是,而不是在您的实体中使用实体管理器,而是为您的实体创建自定义存储库。

在您的实体ORM文件中,按如下方式添加条目(如果不使用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

现在,创建一个具有以上命名空间的新PHP类:

//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;
    }
}

最后,在您的控制器中:

// 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);
         ...

      }
   }

答案 4 :(得分:0)

您需要将services.yml设置为:

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

您还需要使用以下构造函数设置Controller:

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

并在控制器中使用$this->em (例如$connection = $this->em->getConnection();