Search code examples
phpinheritancetwigentitysymfony-3.4

How to display heritage entities data in twig view?


I'm using Symfony 3.4 with built-in forms in a Bootstrap modal and I've created an inheritance with an abstract parent entity (USER) and two daughter entities (EMPLOYER and SEASONAL where the ID fields are commented out to use that of USER) that's extends USER with the 3 entities of PROTECTED fields.

On my site, from my twig modalForm view, I manage to register in base my different types of users Employer or Seasonal via my SecurityController.

Once the record is done, I redirect to a userAccount twig view whose URL is receiving the data sent by the user's creation: MySeason / {role} / {id} / my-account and the UserAccountController which should recover the data sent previously and display them, that's when I come across the error:

An exception occurred while executing 'SELECT t1.id AS id_2, t1.email AS email_3, t1.password AS password_4, t1.registration AS registration_5, t1.company AS company_6, t1.contact AS contact_7, t1.role AS role_8 FROM employer t1 WHERE t0.id = ?' with params ["1"]: SQLSTATE[42S22]: Column not found: 1054 Field 't0.id' unknown in where clause

I think in the error, symfony confuses t1.id of the daughter entity and the t0.id of the parent entity.

If anyone has a solution to offer me! ;-)

My parent Entity

...
/**
* User
*
* @ORM\Table(name="user")
* @ORM\Entity(repositoryClass="P6\GeneralBundle\Repository\UserRepository")
*/
abstract class User
{
/**
* @var int
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;

/**
* @var string
*
* @ORM\Column(name="email", type="string", length=255)
*/
protected $email;

/**
* @var string
*
* @ORM\Column(name="password", type="string", length=255)
*/
protected $password;
...

My daughter entity

...
/**
* Employer
*
* @ORM\Table(name="employer")
* @ORM\Entity(repositoryClass="P6\GeneralBundle\Repository\EmployerRepository")
*/
class Employer extends User
{
const ROLE_USER = 'EMPLOYER';

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

/**
* @var string
*
* @ORM\Column(name="company", type="string", length=255)
*/
protected $company;

/**
* @var string
*
* @ORM\Column(name="contact", type="string", length=255)
*/
protected $contact;
...

My SecurityController

<?php

namespace P6\GeneralBundle\Controller;

use P6\GeneralBundle\Entity\Seasonal;
use P6\GeneralBundle\Form\SeasonalType;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use P6\GeneralBundle\Entity\Employer;
use P6\GeneralBundle\Form\EmployerType;

class SecurityController extends Controller
{

public function userRegistrationAction (Request $request)
 {
 // Employer Form

$employer = new Employer();

 if ($formEmployer = $this->createForm(EmployerType::class, $employer, array('action' => $this->generateUrl('registerUser')
 ))) {

$formEmployer->handleRequest($request);

if ($formEmployer->isSubmitted() && $formEmployer->isValid()) {
/** @var Employer $employer */
$employer = $formEmployer->getData();
$em = $this->getDoctrine()->getManager();
$em->persist($employer);
$em->flush();

$this->addFlash('registration', 'Votre profil a bien été enregistré !');

return $this->redirectToRoute('user_account', [
'role' => $employer->getRole(),
'id' => $employer->getId(),
]);
}
}

// Seasonal Form

$seasonal = new Seasonal();

 if ($formSeasonal = $this->createForm(SeasonalType::class, $seasonal, array('action' => $this->generateUrl('registerUser')
 ))) {

$formSeasonal->handleRequest($request);

if ($formSeasonal->isSubmitted() && $formSeasonal->isValid()) {
/** @var Seasonal $seasonal */
$seasonal = $formSeasonal->getData();
$em = $this->getDoctrine()->getManager();
$em->persist($seasonal);
$em->flush();

$this->addFlash('registration', 'Votre profil a bien été enregistré !');

return $this->redirectToRoute('user_account', [
'role' => $seasonal->getRole(),
'id' => $seasonal->getId(),
]);
}
}

 // Renvoi de vue si les formulaires ne sont pas valides

return $this->render('@General/Default/modalForm.html.twig', [
'formEmployer' => $formEmployer->createView(),
'formSeasonal' => $formSeasonal->createView(),
]);
}
}

My UserAccountController

<?php

namespace P6\GeneralBundle\Controller;

use P6\GeneralBundle\Entity\Employer;
use P6\GeneralBundle\Entity\Seasonal;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;

class UserAccountController extends Controller
{
public function userAccountAction(Employer $employer, Seasonal $seasonal)
 {
$repository = $this->getDoctrine()->getRepository('GeneralBundle:Employer');
$employer = $repository->findBy(['employer' => $employer->getId()]);

//        if ($repository = $this->getDoctrine()->getRepository('GeneralBundle:Seasonal')) {
//            $seasonal = $repository->findBy(['seasonal' => $seasonal->getId()]);
//        }

return $this->render('@General/Default/userAccount.html.twig', [
'employer' => $employer,
//'seasonal' => $seasonal,
]);

}
}

I already tried 3 ways to extends a class(Mapped superclass, single table and class table) but that does not solve my problem. I expect to be able to recover the data saved in the database and display it in a twig view.


Solution

  • I found a solution through this link (Symfony2-Doctrine2 inheritance persist not working properly), I can finally recover the data sent during registration from the User to the next view, the User's account!

    In fact, I had to add this piece of code in the parameters of my mother class:

    * @ORM \ InheritanceType ("JOINED")
    * @ORM \ DiscriminatorColumn (name = "discr", type = "string")
    * @ORM \ DiscriminatorMap ({"employer" = "Employer", "seasonal" = "Seasonal"})
    

    But also modify the getters Id of my daughter entities by replacing:

    public function getId (){return $ this-> id;}
    

    by:

    public function getId (){return parent :: getId ();}
    

    And finally, I replaced in my UserAccountController:

    $ repository = $ this-> getDoctrine () -> getRepository ('GeneralBundle: Employer');
    $ employer = $ repository-> findBy (['employer' => $ employer-> getId ()]);
    

    by:

    $ repository = $ this-> getDoctrine () -> getRepository ('GeneralBundle: Employer');
    $ employer = $ repository-> findOneBy (['id' => $ employer-> getId ()]);
    

    Hoping that this solution does not block me for the rest;)