Using EntityRepository::findBy() with Many-To-Many relations will lead to a E_NOTICE in Doctrine

database-relations, doctrine, many-to-many, php, symfony

Solution

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`

Problem

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

Original source