2012-11-12 2 views
26

Symfony2プロジェクトでは、ブログ投稿といわゆるプラットフォームの関係を作成する必要がありました。 プラットフォームは、サイトの表示に使用するドメインに基づいて特定のフィルタを定義します。 例:url first-example.comでサイトに参加すると、サイトはこの特定のプラットフォームに接続されているブログ投稿のみを提供します。多対多関係でEntityRepository :: findBy()を使用すると、DoctrineでE_NOTICEになります

これを行うには、私はPostとPlatformという2つのエンティティを作成しました。その後、多対多関係でそれらをマッピングしました。 私はこの多対多の関係を介して、ドクシンのEntityRepositoryの組み込み関数findBy()からデータを取得しようとしています。 $postRepoPostエンティティと$platform既存Platformオブジェクトの正しいリポジトリである

// every one of these methods will throw the same error 
$posts = $postRepo->findBy(array('platforms' => array($platform))); 
$posts = $postRepo->findByPlatforms($platform); 
$posts = $postRepo->findByPlatforms(array($platform)); 


いずれかの方法:私は、次のエラーを取得し終わる:

ErrorException: Notice: Undefined index: joinColumns in [...]/vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/BasicEntityPersister.php line 1495 

[...]/vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/BasicEntityPersister.php:1495 
[...]/vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/BasicEntityPersister.php:1452 
[...]/vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/BasicEntityPersister.php:1525 
[...]/vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/BasicEntityPersister.php:1018 
[...]/vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/BasicEntityPersister.php:842 
[...]/vendor/doctrine/orm/lib/Doctrine/ORM/EntityRepository.php:157 
[...]/src/Foobar/BlogBundle/Tests/ORM/PostTest.php:102 

は、多対多の関係では、このように関連entitesを取得することも可能です、または私は自分でこれらの関数を書くことを強制していますか? 奇妙なことです:Doctrineは "それはできません"のようなエラーは投げませんが、内部はE_NOTICEです。私はそれが可能でなければならないと考えているのですが、私はここでいくつかの点を欠いています。

興味深い部分に分けて、2つのエンティティはこのように見えます。

<?php 

namespace Foobar\CommunityBundle\Entity; 

use Doctrine\Common\Collections\ArrayCollection; 
use Doctrine\ORM\Mapping as ORM; 

// [...] other namespace stuff 

/** 
* @ORM\Entity(repositoryClass="Foobar\CommunityBundle\Entity\Repository\PlatformRepository") 
* @ORM\Table(name="platforms") 
*/ 
class Platform 
{ 
    /** 
    * @ORM\Id 
    * @ORM\Column(type="integer") 
    * @ORM\GeneratedValue(strategy="AUTO") 
    */ 
    protected $id; 

    // [...] other field stuff 
} 
<?php 

namespace Foobar\BlogBundle\Entity; 

use Doctrine\Common\Collections\ArrayCollection; 
use Doctrine\ORM\Mapping as ORM; 

// [...] other namespace stuff 

/** 
* @ORM\Entity(repositoryClass="Foobar\BlogBundle\Entity\Repository\PostRepository") 
* @ORM\Table(name="posts") 
*/ 
class Post implements Likeable, Commentable, Taggable, PlatformAware 
{ 
    /** 
    * @ORM\Id 
    * @ORM\Column(type="integer") 
    * @ORM\GeneratedValue(strategy="AUTO") 
    */ 
    protected $id; 

    /** 
    * @ORM\ManyToMany(targetEntity="Foobar\CommunityBundle\Entity\Platform", cascade={"persist"}) 
    * @ORM\JoinTable(name="map_post_platform", 
    *  joinColumns={@ORM\JoinColumn(name="post_id", referencedColumnName="id")}, 
    *  inverseJoinColumns={@ORM\JoinColumn(name="platform_id", referencedColumnName="id")} 
    *  ) 
    */ 
    protected $platforms; 

    // [...] other fields 

    /** 
    * Constructor 
    */ 
    public function __construct() 
    { 
     // [...] 
     $this->platforms = new ArrayCollection(); 
    } 
} 

そしてもちろんのcomposer.jsonファイル(および関連する行にストリップダウン)

{ 
    [...] 
    "require": { 
     "php": ">=5.3.3", 
     "symfony/symfony": "2.1.*", 
     "doctrine/orm": ">=2.2.3,<2.4-dev", 
     "doctrine/doctrine-bundle": "1.0.*", 
     "doctrine/doctrine-fixtures-bundle": "dev-master", 
     [...] 

    }, 
    [...] 
} 

答えて

19

それは非常に可能ですが、証券教義リポジトリはこのように動作しません。 。

はあなたのコンテキストに応じて、2つのオプションがあります。

は、リポジトリ内のカスタムメソッドを記述します。

class PostRepository extends EntityRepository 
{ 
    public function getPosts($id) 
    { 
    $qb = $this->createQueryBuilder('p'); 
    $qb->join('p.platform', 'f') 
     ->where($qb->expr()->eq('f.id', $id)); 
    return $qb; 
    } 
} 

または、プラットフォームオブジェクトのデフォルトゲッターメソッドを使用します。

$posts = $platform->getPosts(); 

あなたが

app/console doctrine:generate:entities 
+0

だろうあなたの答えをいただき、ありがとうございます。ほんの少し追加。最初の方法は、カスタムリポジトリに独自の関数を記述することです。私は自分自身を不明瞭にしているかもしれませんが、Doctrineの組み込みの 'find *()'関数を通して関連するエンティティを取得しようとしました。私は一方向の関連性があるので、2番目の方法は機能しません。したがって、 'Platform'には' $ posts'というプロパティはありません。そのため、getterとsetterはありません。それにもかかわらず、あなたの答えは私には大いに役立ちます。なぜなら、フィルタリングされた多対多の関連付けを取得するための組み込みの方法を使用することはできません。 – devsheeep

1

に、このメソッドを持っていますが、それが正常に行われた場合、この質問はあなたの多対多の関係に問題があることを思わ明らかにされていませんので、あなたは「興味深い部分にストリップダウン」 BIDIRECTIONALが欲しいです(今はUNIDIRECTRIONALです)。双方向性を作成するためにMappedByを使用します。

http://doctrine-orm.readthedocs.org/en/latest/reference/association-mapping.html#many-to-many-bidirectional

実践:あなたのエンティティの

片側を所有している、他の逆SIDE。 Postという名前のエンティティでは、所有側が所有側で、Platformというエンティティが逆側です。

所有側の設定:

Class Post { 
    ...  
    /** 
    * @ManyToMany(targetEntity="Platform") 
    * @JoinTable(name="map_post_platform", 
    *  joinColumns={@JoinColumn(name="post_id", referencedColumnName="id")}, 
    *  inverseJoinColumns={@JoinColumn(name="platform_id", referencedColumnName="id", unique=true)}) 
    **/ 
    protected $platforms; 
    ... 
    public function Post() { 
     $this->platforms= new ArrayCollection(); 
    } 
    ... 
    public function assignToPlatform($platform) { 
     $this->platforms[] = $platform; 
    } 
    ... 
    public function getPlatforms() { 
     return $this->platforms; 
    } 
} 

逆SIDEセットアップ:

Class Platform { 
    ... 
    /** 
    * @ManyToMany(targetEntity="Post", mappedBy="platforms") 
    **/ 
    protected $posts; 
    ... 
    public function Platform() { 
     $this->posts= new ArrayCollection(); 
    } 
    ... 
    public function getPosts() 
    { 
     return $this->posts; 
    } 
} 

例は両側の1から始めて、実体の配列を取得:

$post->getPlatforms(); 
$platform->getPosts(); 
+0

これはこの目的のための正しい解決策です。 –

28

別の方法を、おそらくIDを使用しないOO /クリーナーのビット:

public function getPosts(Platform $platform) 
{ 
    $qb = $this->createQueryBuilder("p") 
     ->where(':platform MEMBER OF p.platforms') 
     ->setParameters(array('platform' => $platform)) 
    ; 
    return $qb->getQuery()->getResult(); 
} 

より良いメソッド名はfindPostsByPlatform

+1

恐ろしく、Doctrineの文書でそれを見たことがありません。パフォーマンスはどうですか? – Nevertheless

+2

パフォーマンスを気にする人は、QueryBuilderを使用しないでください。ORMも使用しないでください。 – jhvaras

+1

あなたの名前はわかりやすいですが、Doctrineの「find」で始まる魔法のような機能のため、カスタム名に「find」を使わない方がよいです。 getPostsByPlatform()。 – Lighthart

関連する問題