2017-12-21 32 views
3

私はタグを持つエンティティを2つ持っています。動的なDoctrine関係の逆サイドメソッド

class TaggableListener implements EventSubscriber 
{ 
    /** 
    * @return array 
    */ 
    public function getSubscribedEvents() 
    { 
     return [ 
      Events::loadClassMetadata 
     ]; 
    } 

    /** 
    * @param \Doctrine\ORM\Event\LoadClassMetadataEventArgs $eventArgs 
    */ 
    public function loadClassMetadata(LoadClassMetadataEventArgs $eventArgs) 
    { 
     // the $metadata is the whole mapping info for this class 
     $metadata = $eventArgs->getClassMetadata(); 

     $class = $metadata->getReflectionClass(); 
     if (!$class->implementsInterface(TaggableEntityInterface::class)) { 
      return; 
     } 

     $namingStrategy = $eventArgs 
      ->getEntityManager() 
      ->getConfiguration() 
      ->getNamingStrategy() 
     ; 

     $metadata->mapManyToMany([ 
      'targetEntity' => Tag::class, 
      'fieldName'  => 'tags', 
      'cascade'  => ['persist'], 
      'joinTable'  => [ 
       'name'  => $namingStrategy->classToTableName($metadata->getName()) . '__Tags', 
       'joinColumns' => [ 
        [ 
         'name'     => $namingStrategy->joinKeyColumnName($metadata->getName()), 
         'referencedColumnName' => $namingStrategy->referenceColumnName(), 
         'onDelete' => 'CASCADE', 
         'onUpdate' => 'CASCADE', 
        ], 
       ], 
       'inverseJoinColumns' => [ 
        [ 
         'name'     => 'tag_id', 
         'referencedColumnName' => $namingStrategy->referenceColumnName(), 
         'onDelete' => 'CASCADE', 
         'onUpdate' => 'CASCADE', 
        ], 
       ] 
      ] 
     ]); 
    } 
} 

interface TaggableEntityInterface 
{ 
    public function addTag(Tag $tags); 
    public function removeTag(Tag $tags); 
    public function getTags(); 
} 

trait Tags 
{ 
    protected $tags; 

    public function addTag(Tag $tags) { /*..*/ }; 
    public function removeTag(Tag $tags) { /*..*/ }; 
    public function getTags() { /*..*/ }; 
} 

私は$category->getTags()または$product->getTags()を使用して、すべてのタグを取得することができます:私はこのblog postに基づいた動的な関係を作成しました。これは素晴らしいです。それは古いブログ投稿ですが、明らかに古くはありません。

しかし、メソッドがないので、タグに関連するすべての商品を簡単に取得する方法はありません。

は理想的には、私はTaggableEntityInterface[]を返しTag::getRelatedEntities()たいので、コレクションは両方ProductCategoryエンティティが含まれています。私のテンプレートで

、私はこのような何かを考えています:

<h1>Related entities:</h1> 
<ul> 
{% for relatedEntity in tag.getRelatedEntities %} 
    <li>{{ relatedEntity }}</li> //..implementing `__toString()` 
{% endfor %} 
</ul> 

Tag::getRelatedEntities()および/またはTag::getProducts()メソッドを取得するための最良の方法は何ですか?

私のタグエンティティで手動でgetProductsメソッドを作成することはできますが、そのような種類のものは動的関係の考え方を壊します。この例では、ProductとCategoryエンティティしか持っていませんが、現実にはTaggableであるエンティティがたくさんあります。

答えて

2

Doctrineでは、複数の異なるエンティティを指す単一の関係を作成することはできません。つまり、TagrelatedEntitiesがある場合は、同じクラスまたは少なくともマップされたスーパークラスのオブジェクトの配列でなければなりません。

Doctrineが管理しているすべてのクラスを繰り返し処理し、指定されたインターフェイスを実装しているかどうかをチェックし、それらのエンティティをタグで検索し、それらをすべて1つの配列にマージするサービスを記述することです。

例コード:

$entities = []; 
foreach ($entityManager->getMetadataFactory()->getAllMetadata() as $classMetadata) { 
    if (in_array(TaggableEntityInterface::class, class_implements($classMetadata->getName()))) { 
     $repository = $entityManager->getRepository($classMetadata->getName()); 
     $entities = array_merge($entities, $repository->findBy(['tag' => $tag])); 
    } 
} 

簡単にあなたのテンプレートからこの機能にアクセスしたい場合は、小枝の機能にこれを包むことができます。

コードは実際にテストされていないため、使用状況によっては修正や改善が必要な場合があります。

+0

'where句'のエラーメッセージに '不明な列' Product__Tags.tag_idがあります。何か案が? –

+0

移行(または、スキーマ:更新)を実行しましたか? Doctrineはどの列を使用するかを知っているので、データベースには存在しません。 –

関連する問題