Stuart Brown Stuart Brown - 1 month ago 10
PHP Question

Unable to guess how to get a Doctrine instance

I have been through the process of updating my project from Symfony 2.8 to Symfony 3 and am now reworking one of my controllers but am having some trouble.

I have a Child entity and controller. The controller has a base route

/**
* Child controller.
*
* @Route("/profile/{parentName}/{childName}")
*/


with an action

/**
* Finds and displays a Child entity.
*
* @Route("/{id}", name="child_show")
* @Method("GET")
* @Template()
*/
public function showAction(Child $child)
{
$deleteForm = $this->createDeleteForm($child);

return array(
'child' => $child,
'delete_form' => $deleteForm->createView(),
);
}


However I don't want the page URL to be domain.com/parentname/childname/id I want it to be domain.com/parentname/childname

In 2.8 my controller was

/**
* Child controller.
*
* @Route("/profile/{parentName}/{childName}")
*/


/**
* Finds and displays a Child entity.
*
* @Route("/", name="child_show")
* @Method("GET")
* @Template()
*/
public function showAction($childName)
{

$em = $this->getDoctrine()->getManager();
$entity = $em->getRepository('AppBundle:Child')->findOneByName($childName);
if (!$entity) {
throw $this->createNotFoundException('Unable to find Child entity.');
}

$deleteForm = $this->createDeleteForm($childName);

return array(
'entity' => $entity,
'delete_form' => $deleteForm->createView(),
);
}


and it worked as I wanted.

However if in my updated controller I modify the route annotation on showAction to

/**
* @Route("/", name="child_show")
* @Method("GET")
* @Template()
*/


I get an error Unable to guess how to get a Doctrine instance from the request information. I guess because the Id is needed to get the correct instance of Child? However childName ($name) in the Child entity is also unique.

I'm a bit stuck with this. Can anyone advise what I am doing wrong? I want to be able to have a route for the child profile page that doesn't contain the ID but uses the child's name to return the info required.

Update in response to some comments / questions - below is my Child entity

namespace AppBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use AppBundle\Entity\User;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;

/**
* Child
*
* @ORM\Table()
* @ORM\Entity(repositoryClass="AppBundle\Entity\ChildRepository")
* @UniqueEntity("name")
*/

class Child
{

/**
* @var integer
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;

/**
* @var string
*
* @ORM\Column(name="name", type="string", length=255, unique=true)
*/
private $name;

/*
* Todo - figure out how to use a date type for dateofbirth below and as well in users.yml fixtures file
*/

/**
* @var \DateTime
*
* @ORM\Column(name="date_of_birth", type="datetime")
*/
private $dateOfBirth;

//todo find ot why the parent variable here and Id variable in AppBundle:User are not mapped correctly
/**
* @ORM\ManyToOne(targetEntity="AppBundle\Entity\User", inversedBy="id")
* @ORM\JoinColumn(onDelete="CASCADE")
*/

private $parent;

/**
* @return User
*/
public function getParent()
{
return $this->parent;
}

/**
* @param User $parent
*/
public function setParent(User $parent)
{
$this->parent = $parent;
}


/**
* Get id
*
* @return integer
*/
public function getId()
{
return $this->id;
}

/**
* Set name
*
* @param string $name
*
* @return Child
*/
public function setName($name)
{
$this->name = $name;

return $this;
}

/**
* Get name
*
* @return string
*/
public function getName()
{
return $this->name;
}


/**
* Set dateOfBirth
*
* @param \DateTime $dateOfBirth
*
* @return Child
*/
public function setDateOfBirth($dateOfBirth)
{
$this->dateOfBirth = $dateOfBirth;

return $this;
}

/**
* Get dateOfBirth
*
* @return \DateTime
*/
public function getDateOfBirth()
{
return $this->dateOfBirth;
}
}


and modified the showAction to

/**
* Child controller.
*
* @Route("/profile/{parentName}/{name}")
*/

/**
* Finds and displays a Child entity.
*
* @Route("/", name="child_show")
* @Method("GET")
* @Template()
*/
public function showAction(Child $name)
{
$deleteForm = $this->createDeleteForm($name);

return array(
'child' => $name,
'delete_form' => $deleteForm->createView(),
);
}


but I now get an error AppBundle\Entity\Child object not found.

ERROR - Uncaught PHP Exception

Symfony\Component\HttpKernel\Exception\NotFoundHttpException: "AppBundle\Entity\Child object not found." at /Library/WebServer/Documents/story-project/app/cache/dev/classes.php line 7183

Answer

The entity is not found, because Doctrine can't find a Child with name {name} and parentName parentName... Which seems legit, since parentName does not exist in the Child entity.

Two solutions :

1 - Never tried, but might work : create getParentName() in Child and make it return $this->parent->getName()

2 - Add a ParamConverter annotation on the top of your Controller Action:

/**
 * Finds and displays a Child entity.
 *
 * @Route("/", name="child_show")
 * @Method("GET")
 * @Template()
 * @ParamConverter("child", class="AppBundle:Child", options={"name" = "name"})
 */
 public function showAction(Child $child)

This way, the Converter will only consider the argument "name" when attempting to retrieve your Child entity... (is that really what you want by the way?) Don't forget to use ParamConverter in your Controller.

Comments