2
votes

[SETTINGS]

  • Symfony 3
  • CalendarEntity can be parent of ChocolateEntity
  • BoxEntity is parent WrapperEntity
  • WrapperEntity can be parent of ChocolateEntity and is always a child of BoxEntity
  • ChocolateEntity can only be child of either CalendarEntity or WrapperEntity

Diagram

[PROBLEM]

When I try to navigate to chocolate/show or chocolate/edit route from either CalendarEntity or BoxEntity , I get this message:

Unable to guess how to get a Doctrine instance from the request information

chocolate/index and chocolate/new routes are working fine.
And untill I came to add code in controller for CalendarEntity, every routes were working fine.

Checking dev.log file gave me this:

// Route: /calendar/{idCalendar}/chocolate/{idChocolate}/show
request.INFO: Matched route "calendar_chocolate_show". {"route":"calendar_chocolate_show","route_parameters":{"_controller":"AppBundle\\Controller\\ChocolateController::showAction","idCalendar":"1","idChocolate":"3","_route":"calendar_chocolate_show"},"request_uri":"http://sphere.gdn/app_dev.php/calendar/1/chocolate/3/show","method":"GET"} []

// Route: /box/{idBox}/wrapper/{idWrapper}/chocolate/{idChocolate}/show
request.INFO: Matched route "wrapper_chocolate_show". {"route":"wrapper_chocolate_show","route_parameters":{"_controller":"AppBundle\\Controller\\ChocolateController::showAction","idBox":"1","idWrapper":"1","idChocolate":"1","_route":"wrapper_chocolate_show"},"request_uri":"http://sphere.gdn/app_dev.php/box/1/wrapper/1/chocolate/1/show","method":"GET"} []

As I see it, Symfony have all needed paramters for each request, and no extra parameter.
I can't ind out how to fix this problem.

[FILES]

ENTITIES :

src/AppBundle/Entity/Calendar.php

class Calendar {
    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $idCalendar;
    /**
     * @var string
     *
     * @ORM\Column(name="name", type="string", length=255)
     */
    private $nameCalendar;
    /**
     * @var
     *
     * @ORM\OneToMany(targetEntity="AppBundle\Entity\Chocolate", mappedBy="calendar")
     */
    private $chocolate;
}

src/AppBundle/Entity/Box.php

class Box {
    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $idBox;
    /**
     * @var int
     *
     * @ORM\Column(name="parent", type="integer", nullable=true)
     */
    private $parent;
    /**
     * @var string
     *
     * @ORM\Column(name="name", type="string", length=255)
     */
    private $nameBox;
    /**
     * @var
     *
     * @ORM\OneToMany(targetEntity="AppBundle\Entity\Wrapper", mappedBy="box")
     */
    private $wrapper;
}

src/AppBundle/Entity/Wrapper.php

class Wrapper {
    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $idWrapper;
    /**
     * @var string
     *
     * @ORM\Column(name="name", type="string", length=255)
     */
    private $nameWrapper;
    /**
     * @var
     *
     * @ORM\ManyToOne(targetEntity="AppBundle\Entity\Box", inversedBy="wrapper")
     * @ORM\JoinColumn(onDelete="CASCADE", nullable=false)
     */
    private $box;
    /**
     * @var
     *
     * @ORM\OneToMany(targetEntity="AppBundle\Entity\Chocolate", mappedBy="wrapper")
     */
    private $chocolate;
}

src/AppBundle/Entity/Chocolate.php

class Chocolate {
    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $idChocolate;
    /**
     * @var string
     *
     * @ORM\Column(name="name", type="string", length=255)
     */
    private $nameChocolate;
    /**
     * @var
     *
     * @ORM\ManyToOne(targetEntity="AppBundle\Entity\Calendar", inversedBy="chocolate")
     * @ORM\JoinColumn(onDelete="CASCADE", nullable=true)
     */
    private $calendar;
    /**
     * @var
     *
     * @ORM\ManyToOne(targetEntity="AppBundle\Entity\Wrapper", inversedBy="chocolate")
     * @ORM\JoinColumn(onDelete="CASCADE", nullable=true)
     */
    private $wrapper;
}


ROUTINGS :

src/AppBundle/Resources/config/calendar.yml

# Calendar
calendar_show:
    path:     /calendar/{idCalendar}/show/
    defaults: { _controller: "AppBundle:Calendar:show" }
    methods:  GET

calendar_edit:
    path:     /calendar/{idCalendar}/edit/
    defaults: { _controller: "AppBundle:Calendar:edit" }
    methods:  [GET, POST]

# Chocolate
calendar_chocolate:
    resource: "@AppBundle/Resources/config/chocolate.yml"
    prefix:   /

src/AppBundle/Resources/config/box.yml

#Box
box_show:
    path:     /box/{idBox}/show/
    defaults: { _controller: "AppBundle:Box:show" }
    methods:  GET

box_edit:
    path:     /box/{idBox}/edit/
    defaults: { _controller: "AppBundle:Box:edit" }
    methods:  [GET, POST]

# Wrapper
box_wrapper:
    resource: "@AppBundle/Resources/config/wrapper.yml"
    prefix:   /

src/AppBundle/Resources/config/wrapper.yml

# Wrapper
wrapper_show:
    path:     /box/{idBox}/wrapper/{idWrapper}/show/
    defaults: { _controller: "AppBundle:Wrapper:show" }
    methods:  GET

wrapper_edit:
    path:     /box/{idBox}/wrapper/{idWrapper}/edit/
    defaults: { _controller: "AppBundle:Wrapper:edit" }
    methods:  [GET, POST]

# Chocolate
wrapper_chocolate:
    resource: "@AppBundle/Resources/config/chocolate.yml"
    prefix:   /

src/AppBundle/Resources/config/chocolate.yml

# Calendar Chocolate
calendar_chocolate_show:
    path:     /calendar/{idCalendar}/chocolate/{idChocolate}/show
    defaults: { _controller: "AppBundle:Chocolate:show" }
    methods:  GET

calendar_chocolate_edit:
    path:     /calendar/{idCalendar}/chocolate/{idChocolate}/edit
    defaults: { _controller: "AppBundle:Chocolate:edit" }
    methods:  [GET, POST]

# Box Chocolate
wrapper_chocolate_show:
    path:     /box/{idBox}/wrapper/{idWrapper}/chocolate/{idChocolate}/show
    defaults: { _controller: "AppBundle:Chocolate:show" }
    methods:  GET

wrapper_chocolate_edit:
    path:     /box/{idBox}/wrapper/{idWrapper}/chocolate/{idChocolate}/edit
    defaults: { _controller: "AppBundle:Chocolate:edit" }
    methods:  [GET, POST]


CONTROLLERS :

src/AppBundle/Controller/CalendarController.php

class CalendarController extends Controller {
    /**
     * Finds and displays a Calendar entity.
     *
     * @param Calendar $calendar
     *
     * @return \Symfony\Component\HttpFoundation\Response
     */
    public function showAction(Calendar $calendar) {
        $deleteForm=$this->createDeleteForm($calendar);

        return $this->render('AppBundle:calendar:show.html.twig', array(
            'calendar'=>$calendar,
            'delete_form'=>$deleteForm->createView(),
        ));
    }

    /**
     * Displays a form to edit an existing Calendar entity.
     *
     * @param Request $request
     * @param Calendar $calendar
     *
     * @return \Symfony\Component\HttpFoundation\RedirectResponse|\Symfony\Component\HttpFoundation\Response
     */
    public function editAction(Request $request, Calendar $calendar) {
        $deleteForm=$this->createDeleteForm($calendar);
        $editForm=$this->createForm('AppBundle\Form\CalendarType', $calendar);
        $editForm->handleRequest($request);

        if($editForm->isSubmitted() && $editForm->isValid()) {
            $em=$this->getDoctrine()
                     ->getManager();
            $em->persist($calendar);
            $em->flush();

            return $this->redirectToRoute('calendar_edit', array('idCalendar'=>$calendar->getIdCalendar()));
        }

        return $this->render('AppBundle:calendar:edit.html.twig', array(
            'calendar'=>$calendar,
            'edit_form'=>$editForm->createView(),
            'delete_form'=>$deleteForm->createView(),
        ));
    }
}

src/AppBundle/Controller/BoxController.php

class BoxController extends Controller {
    /**
     * Finds and displays a Box entity.
     *
     * @param Box $box
     *
     * @return \Symfony\Component\HttpFoundation\Response
     */
    public function showAction(Box $box) {
        $deleteForm=$this->createDeleteForm($box);

        return $this->render('AppBundle:box:show.html.twig', array(
            'box'=>$box,
            'delete_form'=>$deleteForm->createView(),
        ));
    }

    /**
     * Displays a form to edit an existing Box entity.
     *
     * @param Request $request
     * @param Box $box
     *
     * @return \Symfony\Component\HttpFoundation\RedirectResponse|\Symfony\Component\HttpFoundation\Response
     */
    public function editAction(Request $request, Box $box) {
        $deleteForm=$this->createDeleteForm($box);
        $editForm=$this->createForm('AppBundle\Form\BoxType', $box);
        $editForm->handleRequest($request);

        if($editForm->isSubmitted() && $editForm->isValid()) {
            $em=$this->getDoctrine()
                     ->getManager();
            $em->persist($box);
            $em->flush();

            return $this->redirectToRoute('box_edit', array('idBox'=>$box->getIdBox()));
        }

        return $this->render('AppBundle:box:edit.html.twig', array(
            'box'=>$box,
            'edit_form'=>$editForm->createView(),
            'delete_form'=>$deleteForm->createView(),
        ));
    }
}

src/AppBundle/Controller/WrapperController.php

class WrapperController extends Controller {
    /**
     * Finds and displays a Wrapper entity.
     *
     * @param Box $box
     * @param Wrapper $wrapper
     *
     * @return \Symfony\Component\HttpFoundation\Response
     */
    public function showAction(Box $box, Wrapper $wrapper) {
        $deleteForm=$this->createDeleteForm($box, $wrapper);

        return $this->render('AppBundle:wrapper:show.html.twig', array(
            'box'=>$box,
            'wrapper'=>$wrapper,
            'delete_form'=>$deleteForm->createView(),
        ));
    }

    /**
     * Displays a form to edit an existing Wrapper entity.
     *
     * @param Request $request
     * @param Box $box
     * @param Wrapper $wrapper
     *
     * @return \Symfony\Component\HttpFoundation\RedirectResponse|\Symfony\Component\HttpFoundation\Response
     */
    public function editAction(Request $request, Box $box, Wrapper $wrapper) {
        $deleteForm=$this->createDeleteForm($box, $wrapper);
        $editForm=$this->createForm('AppBundle\Form\WrapperType', $wrapper);
        $editForm->handleRequest($request);

        if($editForm->isSubmitted() && $editForm->isValid()) {
            $em=$this->getDoctrine()
                     ->getManager();
            $em->persist($wrapper);
            $em->flush();
            return $this->redirectToRoute('wrapper_edit', array(
                'idBox'=>$box->getIdBox(),
                'idWrapper'=>$wrapper->getIdWrapper()
            ));
        }

        return $this->render('AppBundle:wrapper:edit.html.twig', array(
            'box'=>$box,
            'wrapper'=>$wrapper,
            'edit_form'=>$editForm->createView(),
            'delete_form'=>$deleteForm->createView(),
        ));
    }
}

src/AppBundle/Controller/ChocolateController.php

class ChocolateController extends Controller {
    /**
     * Finds and displays a Chocolate entity.
     *
     * @param Calendar $calendar
     * @param Box $box
     * @param Wrapper $wrapper
     * @param Chocolate $chocolate
     *
     * @return \Symfony\Component\HttpFoundation\Response
     */
    public function showAction(Calendar $calendar=null, Box $box=null, Wrapper $wrapper=null, Chocolate $chocolate) {
        $deleteForm=$this->createDeleteForm($calendar, $box, $wrapper, $chocolate);

        return $this->render('AppBundle:chocolate:show.html.twig', array(
            'calendar'=>$calendar,
            'box'=>$box,
            'wrapper'=>$wrapper,
            'chocolate'=>$chocolate,
            'delete_form'=>$deleteForm->createView(),
        ));
    }

    /**
     * Displays a form to edit an existing Chocolate entity.
     *
     * @param Request $request
     * @param Calendar $calendar
     * @param Box $box
     * @param Wrapper $wrapper
     * @param Chocolate $chocolate
     *
     * @return \Symfony\Component\HttpFoundation\RedirectResponse|\Symfony\Component\HttpFoundation\Response
     */
    public function editAction(Request $request, Calendar $calendar=null, Box $box=null, Wrapper $wrapper=null, Chocolate $chocolate) {
        $deleteForm=$this->createDeleteForm($calendar, $box, $wrapper, $chocolate);
        $editForm=$this->createForm('AppBundle\Form\ChocolateType', $chocolate);
        $editForm->handleRequest($request);

        if($editForm->isSubmitted() && $editForm->isValid()) {
            $em=$this->getDoctrine()
                     ->getManager();
            $em->persist($chocolate);
            $em->flush();
            if($box) {
                return $this->redirectToRoute('wrapper_box_chocolate_edit', array(
                    'idBox'=>$box->getIdBox(),
                    'idWrapper'=>$wrapper->getIdWrapper(),
                    'idChocolate'=>$chocolate->getIdChocolate()
                ));
            } else {
                return $this->redirectToRoute('calendar_chocolate_edit', array(
                    'idCalendar'=>$calendar->getIdCalendar(),
                    'idWrapper'=>$wrapper->getIdWrapper(),
                    'idChocolate'=>$chocolate->getIdChocolate()
                ));
            }
        }

        return $this->render('AppBundle:chocolate:edit.html.twig', array(
            'calendar'=>$calendar,
            'box'=>$box,
            'wrapper'=>$wrapper,
            'chocolate'=>$chocolate,
            'edit_form'=>$editForm->createView(),
            'delete_form'=>$deleteForm->createView(),
        ));
    }
}
2
Checked this answer already, but his case and mine seems differents, and his explanations are sloppy... Couldn't get real hints on the problem.Preciel
have you used @ParamConverter ?Vamsi Krishna B
Yeah, like "suggested" in the linked topic. But just like I told Alvin, it did nothing. And symfony doc have no exemple on how to use it when multiple entities are using a common entity.Preciel

2 Answers

1
votes

As every entities are related, you don't need to pass extra parameter to your showAction() or editAction().

Taking back your code, showAction() would become this:

public function showAction(Chocolate $chocolate) {
    $deleteForm=$this->createDeleteForm($video);

    return $this->render('AppBundle:chocolate:show.html.twig', array(
        'chocolate'=>$chocolate,
        'delete_form'=>$deleteForm->createView(),
    ));
}

And your editAction() would become this:

public function editAction(Request $request, Chocolate $chocolate) {
    $deleteForm=$this->createDeleteForm($chocolate);
    $editForm=$this->createForm('AppBundle\Form\ChocolateType', $chocolate);
    $editForm->handleRequest($request);

    if($editForm->isSubmitted() && $editForm->isValid()) {
        $em=$this->getDoctrine()
                 ->getManager();
        $em->persist($chocolate);
        $em->flush();
        if($chocolate->getWrapper() !== null) {
            return $this->redirectToRoute('wrapper_chocolate_edit', 

        array(
            'idBox'=>$chocolate->getWrapper()->getBox()->getIdBox(),
            'idWrapper'=>$chocolate->getWrapper()->getIdWrapper(),
            'idChocolate'=>$chocolate->getIdChocolate()
        ));
    } else {
        return $this->redirectToRoute('calendar_chocolate_edit',
            array(
                'idCalendar'=>$chocolate->getCalendar()->getIdCalendar(),
                'idChocolate'=>$chocolate->getIdChocolate()
                ));
            }
        }

        return $this->render('AppBundle:Dashboard/chocolate:edit.html.twig', array(
            'chocolate'=>$chocolate,
            'edit_form'=>$editForm->createView(),
            'delete_form'=>$deleteForm->createView(),
        ));
    }

Every informations are in the ChocolateEntity, you just need to get the parent each time, and then the parameter needed.

As you did things, only showAction() and newAction() will need to have parameters, that is because, in both case, you don't return a specific ChocolateEntity

public function indexAction(Calendar $calendar=null, Wrapper $wrapper=null)
public function newAction(Request $request, Calendar $calendar=null, Wrapper $wrapper=null)

And like the editAction() you can get the parents without passing them.

Also note that your twig will change a bit. As exemple, when you display an entity (showAction()), the link "Back to the list" will change based on the route, it will then give something like this:

{% if chocolate.wrapper is not null %}
    <a href="{{ path('wrapper_chocolate_list', { 'idBox': chocolate.wrapper.box.idBox, 'idWrapper': chocolate.wrapper.idWrapper }) }}">Back to the list</a>
{% else %}
    <a href="{{ path('calendar_chocolate_list', { 'idCalendar': chocolate.calendar.idCalendar }) }}">Back to the list</a>
{% endif %}

Doing so, will hint Symfony to get the parents data even if you only pass the ChocolateEntity as argument. It will be the same for other twig files.

Hope it will help you.

This topic was yummy, going to get some chocolates myself.

0
votes

So Preciel, in the ChocolateController try:

/**
 * Finds and displays a Chocolate entity.
 *
 * @param Calendar $calendar
 * @param Box $box
 * @param Wrapper $wrapper
 * @param Chocolate $chocolate
 *
 * @return \Symfony\Component\HttpFoundation\Response
 *
 *  @ParamConverter("calendar", class="AppBundle:Calendar")
 *  @ParamConverter("chocolate", class="AppBundle:Chocolate")
 */
public function showAction(Calendar $calendar=null, Box $box=null, Wrapper $wrapper=null, Chocolate $chocolate) {
...

I think @Vamsi is correct.