Association mapping when one organization is not managed by Doctrine

I have 2 objects in a one-to-one association. The first, Person , is stored in the MySQL database and processed by Doctrine. The second, AdUserRecord , describes an ActiveDirectory user entry. It is read-only. You do not need to know about Person . In addition, AdUserRecord properties AdUserRecord never be stored in MySQL db for privacy reasons.

An AdUserRecord is retrieved using the AdSearcher service, which can search by samaccountname or objectGUID . Whenever a search is successful, the service checks to see if there is a matching Person record and creates it if it is not. It works great.

My problem arises when I start with a Person object. Basically, I do not need to contact Person AdUserRecord , so I would prefer not to query Active Directory if this is not required. This means that I think that Person::getAdrecord() should have access to the AdSearcher service. Something like that:

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

I read the Symfony docs pretty hard, but I'm still at a dead end.

Questions

  • How do I get a service in essence? Should it be entered through the constructor or only where necessary in the getter? If this only happens in getter, should I enter it or is there a way to import it?
  • adds an entity service to a canonical way of dealing with these types of situations? Would it be preferable to create an object manager for AdUserRecord s?
  • What interfaces do I need to implement if I need to create an entity manager?

Person class

 namespace ACRD\DefaultBundle\Entity; use Symfony\Component\Validator\Constraints as Assert; use Doctrine\ORM\Mapping as ORM; use Doctrine\Common\Collections\ArrayCollection; use ACRD\DefaultBundle\Entity\AdUserRecord; /** * @ORM\Entity * @Orm\Table(name="person") * */ class Person { /** * @ORM\Id * @ORM\Column(type="integer") * @ORM\GeneratedValue(strategy="AUTO") */ protected $id; /** * @ORM\Column(name="AD_guid", type="string", length=36, unique=true) */ protected $ad_guid; /** * @var AdUserRecord */ protected $adrecord; //usual getters and setters } 
+4
source share
2 answers

It seems that the Doctrine postLoad event is the best solution.

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

You also mentioned that most of the time you do not need to use active catalog material. Before optimizing, I strongly recommend that you really measure how performance impacts are. If, however, you notice a performance problem, consider using a proxy object to reduce the AdPerson search AdPerson to the point where you really need something from it.

 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 will basically expand from your AdPerson class, wrap each public method with a call to load the actual AdPerson object, and then act as a facade between them. Before you start coding, consider the following consequences:

  • it adds complexity to your code base (the more code, the more you need to support);
  • it will be painful to debug - for example, you can get an exception inside your template, which will leave you scratching your head for a long time (was there, did it);

The bottom line is that in theory, services should (basically) not be introduced inside objects.

+1
source

Regarding your third question:

EntityManagers implement Doctrine/Common/Persistence/ObjectManager - look at the interface on github .

Further:

a slightly clean implementation will be similar to the Document ↔ Entity mapping (called links) provided by gedmo / doctrine-extensions .

Take a look at the documentation to see how it works here and here .

If you want to start diving into ReferenceListener code :)

0
source

Source: https://habr.com/ru/post/1494551/


All Articles