2016-03-10 14 views
6

Có thể giải quyết một thực thể mục tiêu trên nhiều người quản lý thực thể không?Giải quyết thực thể mục tiêu với nhiều người quản lý thực thể

Tôi có một người lớp (trong một gói tái sử dụng):

/** 
* 
* @ORM\Entity 
* @ORM\Table(name="my_vendor_person") 
*/ 
class Person 
{ 
    /** 
    * Unique Id 
    * 
    * @var integer $id 
    * 
    * @ORM\Column(name="id", type="integer") 
    * @ORM\Id 
    * @ORM\GeneratedValue(strategy="AUTO") 
    */ 
    protected $id; 

    /** 
    * First Name 
    * 
    * @var string $name 
    * 
    * @ORM\Column(name="first_name", type="string", length=32) 
    */ 
    protected $firstName; 
    // etc... 

Và một người sử dụng lớp (trong ứng dụng chính của tôi):

/** 
* @ORM\Entity 
* 
* @ORM\Table(name="my_financial_user") 
* 
*/ 
class User extends BaseUser 
{ 

    /** 
    * @ORM\OneToOne(targetEntity="My\FinancialBundle\Model\PersonInterface") 
    * @var PersonInterface 
    */ 
    protected $person; 

Về cơ bản tôi muốn vài người sử dụng cho một người từ nhóm có thể sử dụng lại.

tôi đã thiết lập tùy chọn đơn vị quyết tâm mục tiêu trong cấu hình học thuyết của mà tôi nghĩ rằng nó cho phép tôi làm điều này:

doctrine: 
    orm: 
     auto_generate_proxy_classes: "%kernel.debug%" 
     default_entity_manager: default 
     resolve_target_entities: 
      My\FinanceBundle\Model\PersonInterface: My\VendorBundle\Entity\Person 
     entity_managers: 
      default: 
       naming_strategy: doctrine.orm.naming_strategy.underscore 
       connection: default 
       mappings: 
        MyFinanceBundle: ~ 
      second: 
       naming_strategy: doctrine.orm.naming_strategy.underscore 
       auto_mapping: false 
       connection: second 
       mappings: 
        MyVendorBundle: ~ 
        MyVendorUserBundle: ~ 

Ngoài ra, các lớp học sử dụng trong gói chính, mở rộng một cơ sở người dùng trong gói nhà cung cấp. Lớp người dùng tất nhiên được duy trì, trong db ứng dụng chính.

Với cấu hình này, nó cho tôi một lỗi.

[Doctrine\Common\Persistence\Mapping\MappingException]                      
The class 'My\VendorBundle\Entity\Person' was not found in the chain configured namespaces My\FinanceBundle\Entity, FOS\UserBundle\Model 

Có ai biết cách giải quyết vấn đề này không?

+1

Xem các câu hỏi liên quan sau: http://stackoverflow.com/questions/14403863/entities-associations-across-different-managers và http://stackoverflow.com/questions/9330018/issues-in-entities-from- các gói khác nhau-sử dụng-khác-thực thể-người quản lý – takeit

+1

Không. Quản lý thực thể không nói chuyện với nhau. Bạn sẽ cần phải tìm cách để bao gồm tất cả các thực thể cần thiết trong một người quản lý thực thể duy nhất. – Cerad

+0

không may. Tôi nghĩ rằng đây là trường hợp người dùng hợp pháp, hy vọng hỗ trợ sẽ có trong tương lai .. cảm ơn cả cho bình luận của bạn.bây giờ những gì tôi sẽ làm là tự động gán người đó cho người dùng trong bộ điều khiển nơi cần thiết ($ user = $ this-> getUser(); $ user-> person = $ person) – apfz

Trả lời

3

Như đã đề cập trong nhận xét, người quản lý thực thể không nói chuyện với nhau để bạn phải làm việc xung quanh nó. Một cách là sử dụng trình nghe học thuyết và chèn một cuộc gọi lại có thể được gọi bằng phương thức getPerson.

AppBundle \ thuyết \ InsertPersonListener

use Doctrine\Common\Persistence\Event\LifecycleEventArgs; 
use My\FinancialBundle\Entity\Person; 
use My\VendorBundle\Entity\User; 
use Symfony\Bridge\Doctrine\RegistryInterface; 

class InsertPersonListsner 
{ 
    /** 
    * @var RegistryInterface 
    */ 
    private $registry; 

    /** 
    * Insert the registry into the listener rather than the entity manager 
    * to avoid a cyclical dependency issue 
    * 
    * @param RegistryInterface $registry 
    */ 
    public function __construct(RegistryInterface $registry) 
    { 
     $this->registry = $registry; 
    } 

    /** 
    * On postLoad insert person callback 
    * 
    * @var LifecycleEventArgs $args 
    */ 
    public function postLoad(LifecycleEventArgs $args) 
    { 
     $user = $args->getObject(); 

     // If not a user entity ignore 
     if (!$user instanceof User) { 
      return; 
     } 

     $reflectionClass = new \ReflectionClass(User::class); 

     $property = $reflectionClass->getProperty('personId'); 
     $property->setAccessible(true); 

     // if personId is not set ignore 
     if (null === $personId = $property->getValue($user)) { 
      return; 
     } 

     // get the repository for your person class 
     // - changed to your version from the comments 
     $repository = $this->registry 
      ->getManagerForClass(Person::class) 
      ->getRepository('MyVendorBundle:Person'); 

     // set the value as a callback rather than the entity 
     // so it's not called unless necessary 
     $property = $reflectionClass->getProperty('personCallback'); 
     $property->setAccessible(true); 
     $property->setValue($user, function() use ($repository, $personId) { 
      return $repository->find($personId); 
     }); 
    } 
} 

My \ VendorBundle \ Entity \ User

use My\FinancialBundle\Entity\Person; 

class User 
{ 
    //.. 

    /** 
    * @var Person 
    */ 
    private $person; 

    /** 
    * @var integer 
    */ 
    private personId; 

    /** 
    * @var callable 
    */ 
    private $personCallback; 

    /** 
    * Set person 
    * 
    * @param Person|null $person 
    * @return $this 
    */ 
    public function setPerson(Person $person = null) 
    { 
     $this->person = $person; 

     // if the person is null reset the personId and 
     // callback so that it's not called again 
     if (null === $person) { 
      $this->personId = null; 
      $this->personCallback = null; 
     } else { 
      // set the personId to be stored on the db for the next postLoad event 
      $this->personId = $person->getId(); 
     } 

     return null; 
    } 

    /** 
    * Get person 
    * 
    * @return Person|null 
    */ 
    public function getPerson() 
    { 
     // if the person has not been set and the callback is callable, 
     // call the function and set the result (of $repository->find($personId)) 
     // to the person property and then return it. The callback is 
     // reset to stop unnecessary repository calls in case of a null response 
     if (null === $this->person && is_callable($this->personCallback)) { 
      $this->person = call_user_func($this->personCallback); 
      $this->personCallback = null; 
     } 

     return $this->person; 
    } 
} 

AppBundle \ Resources \ services.yml

app.listener.insert_person: 
    class: AppBundle\Doctrine\InsertPersonListener 
    arguments: 
     - '@doctrine' 
    tags: 
     - { name: doctrine.event_listener, event: postLoad } 

CẬP NHẬT

Sau khi tìm kiếm một ví dụ về điều này trong thực tế đời sống tôi thấy this. Từ đó tôi thấy rằng bạn có thể thay đổi

$reflectionClass = new \ReflectionClass(User::class) 

để

$reflectionClass = $args->getObjectManager() 
    ->getClassMetadata(User::class) 
    ->reflClass 

đó, tôi giả sử, có nghĩa là một ít new \ReflectionClass(...) gọi mỗi tải.

+0

điều này thực sự tốt! không chỉ là câu trả lời thực tế mà còn học được rất nhiều. cảm ơn vì đã đăng bài này. hy vọng điều này sẽ giúp những người khác đối mặt với cùng một vấn đề. – apfz

+0

Tôi giả định trong postLoad, $ property-> getValue ($ user), nên là $ property-> getValue ($ entity), vì $ user không được định nghĩa. cũng $ args-> getEntity(), có thể là $ args-> getObject() vì getEntity bị phản đối. – apfz

+0

Tệ của tôi. Đối với một số lý do tôi quyết định viết nó trực tiếp vào hộp văn bản hơn là sử dụng một IDE mà có thể đã thực hiện tất cả những điều này thực sự rõ ràng. Tôi cũng đã đổi tên '$ entity' thành' $ user' để nó rõ ràng hơn và thêm tệp cấu hình 'services.yml' mà tôi đã quên. – qooplmao

Các vấn đề liên quan