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.
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
.
// 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 $postRepo
is the correct Repository for the Post
entity and $platform
an existing Platform
object.
Either way: I end up getting the following error:
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.
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)
{
[...]
"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",
[...]
},
[...]
}
Another way, maybe a bit OO/cleaner without using IDs:
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