Usar EntityRepository :: findBy () con relaciones Many-To-Many dará lugar a un E_NOTICE en Doctrine

Para un proyecto Symfony2 tuve que crear una relación entre una publicación de blog y las llamadas plataformas. Una plataforma define un filtro específico basado en el dominio que usa para ver el sitio. Por ejemplo: si se une al sitio por url first-example.com, el sitio solo proporcionará publicaciones de blog, que están conectadas a esta plataforma específica.

Para hacerlo, creé dos entidades Post y Plataforma. Luego los mapeé junto con una relación Muchos a Muchos. Estoy tratando de recuperar datos a través de esta relación Muchos a Muchos a partir de la función integrada findBy() en el EntityRepository Doctrines.

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

Donde $postRepo es el Repositorio correcto para la entidad Post y $platform un objeto Platform existente.
De cualquier manera: termino recibiendo el siguiente 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 

¿Es posible recuperar entidades relacionadas en una relación Muchos a Muchos de esta manera, o me veo obligado a escribir estas funciones yo solo? Lo extraño es que Doctrine no lanzará ningún error como: “No es posible”, sino un E_NOTICE interno. Es por eso que creo que debería ser posible, pero me faltan algunos puntos aquí.

Reducidos a las partes interesantes, las dos Entidades se ven así.

 <?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 } 
 platforms = new ArrayCollection(); } } 

Y, por supuesto, el archivo composer.json (también desglosado en las líneas correspondientes)

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

Es muy posible, pero Stock Doctrine Repository no funciona de esta manera.

Tienes dos opciones, dependiendo de tu contexto:

Escriba un método personalizado en el Repositorio.

 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; } } 

O use los métodos getter predeterminados en el objeto de la plataforma.

 $posts = $platform->getPosts(); 

Usted “se despojó de las partes interesantes” por lo que no es obvio si tiene este método, pero normalmente se hace en

 app/console doctrine:generate:entities 

Otra forma, tal vez un poco OO / cleaner sin usar ID:

 public function getPosts(Platform $platform) { $qb = $this->createQueryBuilder("p") ->where(':platform MEMBER OF p.platforms') ->setParameters(array('platform' => $platform)) ; return $qb->getQuery()->getResult(); } 

Un mejor nombre de método sería findPostsByPlatform

Esta pregunta parece un problema con una relación ManyToMany que desea BIDIRECCIONAL (y ahora es UNIDIRECTRIONAL). Usa MappedBy para crear bidireccionalidad:

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

Práctico:

Una de tus entidades es AL LADO, el otro lado INVERSO. En su entidad de ejemplo llamada Poste es propietaria, y la entidad llamada Plataforma es inversa.

Configuración de OWNING SIDE:

 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; } } 

CONFIGURACIÓN DEL LADO INVERSO:

 Class Platform { ... /** * @ManyToMany(targetEntity="Post", mappedBy="platforms") **/ protected $posts; ... public function Platform() { $this->posts= new ArrayCollection(); } ... public function getPosts() { return $this->posts; } } 

EJEMPLO recuperar una matriz de entidades, empezando por uno de los lados:

 $post->getPlatforms(); $platform->getPosts();