当一个实体不由Doctrine管理时的关联映射

时间:2013-07-31 18:11:27

标签: symfony associations

我在一对一关联中有2个实体。第一个Person存储在MySQL数据库中,由Doctrine处理。第二个AdUserRecord描述了ActiveDirectory用户记录。它是只读的。它不需要知道Person。此外,出于隐私原因,永远不应将AdUserRecord属性存储在MySQL数据库中。

使用AdUserRecord服务检索AdSearcher,该服务可以samaccountnameobjectGUID进行搜索。只要搜索成功,服务就会检查是否有相应的Person记录,如果没有,则创建一个。这很好。

当我使用Person对象开始时出现问题。大多数情况下,我不需要访问Person的{​​{1}},因此除非需要,否则我不想查询Active Directory。这意味着,我认为AdUserRecord需要访问Person::getAdrecord()服务。像这样:

AdSearcher

我一直在努力阅读Symfony文档,但我仍然感到难过。

问题

  • 如何将服务提供给实体?它应该通过构造函数注入,还是只需要在getter中注入?如果它只出现在吸气剂中,我是否必须注射它或有没有办法导入它?
  • 正在向实体添加服务以规范方式处理这些类型的情况?为public function getAdrecord(){ if($this->adrecord) return $this->adrecord; $searcher = ???; //get AdSearcher service somehow $record = $search->getRecordByUserGuid($this->ad_guid); if(!$record) throw new \Exception('this person no longer exists'); $this->adrecord = $record; return $this->adrecord; } s
  • 建立实体经理会更好吗?
  • 如果我必须构建实体管理器,我需要实现哪些接口?

AdUserRecord上课

Person

2 个答案:

答案 0 :(得分:1)

看起来Doctrine的postLoad event是最好的解决方案。

// src/Acme/DemoBundle/EventListener/ActiveDirectorySubscriber.php
namespace Acme\DemoBundle\EventListener;

use Acme\DemoBundle\Model\AdAwareInterface;
use Doctrine\Common\EventSubscriber;
use Doctrine\ORM\Event\LifecycleEventArgs;
// for doctrine 2.4: Doctrine\Common\Persistence\Event\LifecycleEventArgs;
use Symfony\Component\DependencyInjection\ContainerAware

class ActiveDirectorySubscriber extends ContainerAware implements EventSubscriber
{
    public function getSubscribedEvents()
    {
        return array(
            'postLoad',
        );
    }

    public function postLoad(LifecycleEventArgs $args)
    {
        $entity = $args->getEntity();

        if (!($entity instanceof AdAwareInterface)) {
            return:
        }

        $adSearcher = $this->getContainer()->get('acme_demo.ad_searcher');

        if ($adPerson = $adSearcher->find($entity->getAdGuid())) {
            $entity->setAdPerson($adPerson);
        }
    }
}

您还提到大多数时候您不需要使用活动目录。在优化之前,我强烈建议您实际测量有多少性能影响。但是,如果您确实注意到性能问题,请考虑使用代理对象将AdPerson搜索权限降低到您实际需要的位置。

public function postLoad(LifecycleEventArgs $args)
{
    $entity = $args->getEntity();

    if (!($entity instanceof AdAwareInterface)) {
        return:
    }

    $adSearcher = $this->getContainer()->get('acme_demo.ad_searcher');

    $entity->setAdPerson(new AdPersonProxy($adSearcher));
}

AdPersonProxy基本上会从您的AdPerson类扩展,通过调用来包装每个公共方法以加载实际的AdPerson对象,然后充当两者之间的外观。在开始编码之前,请考虑以下含义:

  • 它增加了代码库的复杂性(代码越多,维护的越多);
  • 调试会很麻烦 - 例如你可能会在你的内部得到一个例外 模板会让你长时间挠头(去过那里, 完成了);

最重要的是,理论上服务应该(大部分)不应该注入实体内部。

答案 1 :(得分:0)

关于你的第三个问题:

EntityManagers实施Doctrine/Common/Persistence/ObjectManager - 查看the interface on github

此外:

一个有点干净的实现类似于gedmo/doctrine-extensions提供的Document< - > Entity映射(称为 references )。

瞥一眼文档,看看它是如何运作的herehere

如果您想要的话,请开始深入研究ReferenceListener的代码:)