Search code examples
symfonyleft-joinentity-relationship

how displaying two ManyToMany entities Symfony2


I'm under SF2.0.15 with Doctrine2 and I have two entities.

-Expedition - Step

To explain, one expedition can have several steps and one step can belong to several expeditions. In addition, one expedition belongs to his founder (named "owner" and stored in the User entity). So, I have chosen to make a ManyToMany joining between Expedition and Steps tables. In your opinion, is it a good choice or a wrong choice ?

I want to create a method which select all the steps which belong to one expedition (I have the expedition's Id which is contained in $id_exp). So, I have read lots of topics in the Internet but it always fail and I want to know why...

The entity Expedition.php

/**
 * @ORM\ManyToOne(targetEntity="Easymuth\UserBundle\Entity\User")
 * @ORM\JoinColumn(nullable=false)
 */
private $owner;
/**
 * @ORM\ManyToMany(targetEntity="Easymuth\ExpeditionBundle\Entity\Step", cascade={"persist"})
 */
private $steps;

/**
 * Add steps
 *
 * @param Easymuth\ExpeditionBundle\Entity\Step $steps
 */
public function addStep(\Easymuth\ExpeditionBundle\Entity\Step $step)
{
    $this->steps[] = $step;
}

public function __construct()
{
    $this->steps = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
 * Get steps
 *
 * @return Doctrine\Common\Collections\Collection 
 */
public function getSteps()
{
    return $this->steps;
}

ExpeditionRepository.php :

namespace Easymuth\ExpeditionBundle\Entity;

use Doctrine\ORM\EntityRepository;

class ExpeditionRepository extends EntityRepository
{
public function getStepsFromExpedition($id_exp) {
  $qb = $this->createQueryBuilder('e')
             ->leftJoin('e.steps', 's')
             ->addSelect('s')
             ->where('e.id = :id')
             ->setParameter('id', $id_exp);

  return $qb->getQuery()->getResult();
}
}

And finally in my controller, I have :

namespace Easymuth\ExpeditionBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Easymuth\ExpeditionBundle\Entity\Expedition;

class MainController extends Controller
{
public function stepsAction($id_exp) {

    $expedition = $this->getDoctrine()
                    ->getEntityManager()
                    ->getRepository('EasymuthExpeditionBundle:Expedition')
                    ->getStepsFromExpedition($id_exp);

    print_r($expedition->getSteps()); // it displays a very long contents........

    //return $this->render('EasymuthExpeditionBundle:Main:steps.html.twig'));
   }
}

The displayed error on the print_r (or var_dump) is :

Fatal error: Call to a member function getSteps() on a non-object in /Applications/MAMP/htdocs/easymuth/src/Easymuth/ExpeditionBundle/Controller/MainController.php

Thank you very much for your help !


Solution

  • It is a good choice, you have to use ManyToMany associations for this design, good point ! But be careful, if you want to add information in your association (like order for example, can be useful for step in expedition), you have to create a new entity. Check here for more info.

    Then, the problem is in your controller. (You don't need additional function in your repository)
    If you want to get all the steps from one expedition, just do in your controller :

    //find your expedition
    $expedition = $this->getDoctrine()
                        ->getEntityManager()
                        ->getRepository('EasymuthExpeditionBundle:Expedition')
                        ->find($id_exp);
    
    //then get the steps from this expedition
    $steps = $expedition->getSteps();
    

    You have to be sure that the expedition with $id_exp does exist or it will throw an error when you want to use your $expedition variable (because it is set at null) You can check existence this way :

    if(!$expedition) {
        //do some stuff like throwing exception
    }