php 在多对多关系中使用 EntityRepository::findBy() 将导致 Doctrine 中的 E_NOTICE
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/13343533/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Using EntityRepository::findBy() with Many-To-Many relations will lead to a E_NOTICE in Doctrine
提问by devsheeep
For a Symfony2 project I had to create a relationship between a blog post and so called platforms. A platform defines a specific filter based on the domain you use to view the site. For example: If you join the site by url first-example.com, the site will only provide blog posts, which are connected to this specific platform.
对于 Symfony2 项目,我必须在博客文章和所谓的平台之间建立关系。平台根据您用于查看站点的域定义特定过滤器。例如:如果您通过 url first-example.com 加入该站点,则该站点将仅提供连接到该特定平台的博客文章。
To do so, I created two entities Post and Platform. Afterwards I mapped them together with a Many-To-Many relationship.
I'm trying to retrieve data via this Many-To-Many relationship from the builtin function findBy()in Doctrines' EntityRepository.
为此,我创建了两个实体 Post 和 Platform。之后我用多对多关系将它们映射在一起。我试图通过这种多对多关系从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));
Where $postRepois the correct Repository for the Postentity and $platforman existing Platformobject.
Either way: I end up getting the following error:
实体和现有对象$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
Is it even possible to retrieve related entites in a Many-To-Many relationship this way, or am i forced to write these functions by myself?
The weird thing is: Doctrine will not throw any error like: "It's not possible.", but an internal E_NOTICE. Thats why I tent to think it should be possible, but I'm missing some points here.
甚至可以通过这种方式在多对多关系中检索相关实体,还是我被迫自己编写这些函数?奇怪的是:Doctrine 不会抛出任何错误,例如:“这是不可能的。”,而是一个内部的E_NOTICE. 这就是为什么我认为这应该是可能的,但我在这里遗漏了一些要点。
Stripped down to the interesting parts, the two Entities look like this.
剥离到有趣的部分,两个实体看起来像这样。
<?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();
}
}
And of course the composer.json file (as well stripped down to the relevant lines)
当然还有 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",
[...]
},
[...]
}
采纳答案by Lighthart
It is very possible, but the Stock Doctrine Repository does not work this way.
这是很有可能的,但是 Stock Doctrine Repository 不是这样工作的。
You have two options, depending on your context:
您有两种选择,具体取决于您的上下文:
Write a custom method in the Repository.
在存储库中编写自定义方法。
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;
}
}
Or use the default getter methods in the platform object.
或者使用平台对象中的默认 getter 方法。
$posts = $platform->getPosts();
You "stripped down to the interesting parts" so it is not obvious if you have this method but it is normally made on
你“精简到有趣的部分”,所以如果你有这个方法并不明显,但它通常是在
app/console doctrine:generate:entities
回答by jhvaras
Another way, maybe a bit OO/cleaner without using IDs:
另一种方式,也许有点面向对象/更清洁,而不使用 ID:
public function getPosts(Platform $platform)
{
$qb = $this->createQueryBuilder("p")
->where(':platform MEMBER OF p.platforms')
->setParameters(array('platform' => $platform))
;
return $qb->getQuery()->getResult();
}
A better method name would be findPostsByPlatform
更好的方法名称是 findPostsByPlatform
回答by Vincent
This question seems a problem with a ManyToMany relationship which you want BIDIRECTIONAL (and is now UNIDIRECTRIONAL). Use MappedBy to create bidirectionality :
这个问题似乎是一个多对多关系的问题,你想要双向(现在是单向)。使用 MappedBy 创建双向性:
Practical :
实际的 :
One of your entities is OWNING SIDE, the other INVERSE SIDE. In your example entity named Post is owning side, and entity named Platform is inverse side.
你的一个实体是自己的一面,另一个反面。在您的示例中,名为 Post 的实体是拥有方,而名为 Platform 的实体是反向方。
OWNING SIDE setup :
拥有方设置:
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;
}
}
INVERSE SIDE Setup :
反面设置:
Class Platform {
...
/**
* @ManyToMany(targetEntity="Post", mappedBy="platforms")
**/
protected $posts;
...
public function Platform() {
$this->posts= new ArrayCollection();
}
...
public function getPosts()
{
return $this->posts;
}
}
EXAMPLE retrieving an array of entities, starting from one of the sides :
示例检索实体数组,从一侧开始:
$post->getPlatforms();
$platform->getPosts();

