使用EntityRepository::findBy()与多对多关系将导致教义E_NOTICE

对于Symfony2项目,我必须在博客文章和所谓的平台之间建立关系。平台根据您用于查看站点的域定义特定的筛选器。例如:如果您通过 url first-example.com 加入网站,则该网站将仅提供连接到此特定平台的博客文章。

为此,我创建了两个实体 Post 和 Platform。之后,我用多对多关系将它们映射在一起。我正在尝试通过这种多对多关系从 Doctrines 的内置函数中检索数据。findBy()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));

其中 是实体和现有对象的正确存储库。
无论哪种方式:我最终收到以下错误:$postRepoPost$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

是否有可能以这种方式在多对多关系中检索相关内容,或者我被迫自己编写这些函数?奇怪的是:教义不会抛出任何错误,比如:“这是不可能的”,而是一个内部的。这就是为什么我认为这应该是可能的,但我在这里遗漏了一些要点。E_NOTICE

剥离到有趣的部分,这两个实体看起来像这样。

<?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",
        [...]

    },
    [...]
}

答案 1

另一种方式,在不使用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


答案 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

推荐