35

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

そのために、PostとPlatformの2つのエンティティを作成しました。その後、多対多の関係でそれらをマッピングしました。findBy()Doctrinesの組み込み関数からこの多対多の関係を介してデータを取得しようとしていますEntityRepository

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

エンティティと既存のオブジェクト$postRepoの正しいリポジトリはどこにありますか。 いずれにせよ:次のエラーが発生します。Post$platformPlatform

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

この方法で多対多の関係にある関連するエンティティを取得することも可能ですか、それともこれらの関数を自分で作成する必要がありますか?奇妙なことは、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",
        [...]

    },
    [...]
}
4

3 に答える 3

41

別の方法として、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

于 2014-09-22T13:11:35.550 に答える
31

それは非常に可能ですが、StockDoctrineリポジトリはこのようには機能しません。

コンテキストに応じて、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;
  }
}

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

$posts = $platform->getPosts();

あなたは「興味深い部分に取り掛かった」ので、この方法があるかどうかは明らかではありませんが、通常は

app/console doctrine:generate:entities
于 2012-11-22T16:40:58.630 に答える
3

この質問は、BIDIRECTIONAL(現在はUNIDIRECTRIONAL)が必要なManyToMany関係の問題のようです。MappedByを使用して双方向性を作成します。

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

実用的 :

エンティティの1つはOWNINGSIDEで、もう1つはINVERSESIDEです。この例では、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;
    }
}

インバースサイドセットアップ:

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();
于 2014-08-17T14:51:28.203 に答える