2

I have a file /src/AppBundle/Entity/Questionnaire.php with 3 Entity classes, where I'm trying to implement Single table inheritance with Doctrine 2 on Symfony 2.7. Questionnaire is a parent abstract class, and there are 2 child classes FirstQuestions and SecondsQuestions that extends Questionnaire. I choosed this model because I need to write data in table in 2 steps. The code of this file is below:

namespace AppBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * Questionnaire
 *
 * @ORM\Entity
 * @ORM\Table(name="questionnaire")
 * @ORM\InheritanceType("SINGLE_TABLE")
 * @ORM\DiscriminatorColumn(name="discr", type="string")
 * @ORM\DiscriminatorMap({"firstquestions" = "FirstQuestions", "secondquestions" = "SecondQuestions"})
 */
abstract class Questionnaire {
    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

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

/**
 * FirstQuestions
 */
class FirstQuestions extends Questionnaire {
    /**
     * @var string
     *
     * @ORM\Column(name="firstName", type="string", length=64)
     */
    private $firstName;

    /**
     * @var string
     *
     * @ORM\Column(name="lastName", type="string", length=64)
     */
    private $lastName;

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

    /**
     * @var \DateTime
     *
     * @ORM\Column(name="birthday", type="date")
     */
    private $birthday;

    /**
     * @var integer
     *
     * @ORM\Column(name="shoeSize", type="integer")
     */
    private $shoeSize;

    /**
     * Set firstName
     *
     * @param string $firstName
     *
     * @return Questionnaire
     */
    public function setFirstName($firstName)
    {
        $this->firstName = $firstName;

        return $this;
    }

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

    /**
     * Set lastName
     *
     * @param string $lastName
     *
     * @return Questionnaire
     */
    public function setLastName($lastName)
    {
        $this->lastName = $lastName;

        return $this;
    }

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

    /**
     * Set email
     *
     * @param string $email
     *
     * @return Questionnaire
     */
    public function setEmail($email)
    {
        $this->email = $email;

        return $this;
    }

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

    /**
     * Set birthday
     *
     * @param \DateTime $birthday
     *
     * @return Questionnaire
     */
    public function setBirthday($birthday)
    {
        $this->birthday = $birthday;

        return $this;
    }

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

    /**
     * Set shoeSize
     *
     * @param integer $shoeSize
     *
     * @return Questionnaire
     */
    public function setShoeSize($shoeSize)
    {
        $this->shoeSize = $shoeSize;

        return $this;
    }

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

/**
 * SecondQuestions
 */
class SecondQuestions extends Questionnaire {
    /**
     * @var string
     *
     * @ORM\Column(name="favoriteIceCream", type="string", length=128)
     */
    private $favoriteIceCream;

    /**
     * @var string
     *
     * @ORM\Column(name="favoriteSuperHero", type="string", length=32)
     */
    private $favoriteSuperHero;

    /**
     * @var string
     *
     * @ORM\Column(name="favoriteMovieStar", type="string", length=64)
     */
    private $favoriteMovieStar;

    /**
     * @var \DateTime
     *
     * @ORM\Column(name="endOfTheWorld", type="date")
     */
    private $endOfTheWorld;

    /**
     * @var string
     *
     * @ORM\Column(name="superBowlWinner", type="string", length=32)
     */
    private $superBowlWinner;

    /**
     * Set favoriteIceCream
     *
     * @param string $favoriteIceCream
     *
     * @return Questionnaire
     */
    public function setFavoriteIceCream($favoriteIceCream)
    {
        $this->favoriteIceCream = $favoriteIceCream;

        return $this;
    }

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

    /**
     * Set favoriteSuperHero
     *
     * @param string $favoriteSuperHero
     *
     * @return Questionnaire
     */
    public function setFavoriteSuperHero($favoriteSuperHero)
    {
        $this->favoriteSuperHero = $favoriteSuperHero;

        return $this;
    }

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

    /**
     * Set favoriteMovieStar
     *
     * @param string $favoriteMovieStar
     *
     * @return Questionnaire
     */
    public function setFavoriteMovieStar($favoriteMovieStar)
    {
        $this->favoriteMovieStar = $favoriteMovieStar;

        return $this;
    }

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

    /**
     * Set endOfTheWorld
     *
     * @param \DateTime $endOfTheWorld
     *
     * @return Questionnaire
     */
    public function setEndOfTheWorld($endOfTheWorld)
    {
        $this->endOfTheWorld = $endOfTheWorld;

        return $this;
    }

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

    /**
     * Set superBowlWinner
     *
     * @param string $superBowlWinner
     *
     * @return Questionnaire
     */
    public function setSuperBowlWinner($superBowlWinner)
    {
        $this->superBowlWinner = $superBowlWinner;

        return $this;
    }

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

So the problem is when I'm trying to create object of child class(FirstQuestions or SecondsQuestions) in method of controller, Symfony displays me error "500 Internal Server Error". The code of controller with method is below:

namespace AppBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Request;
use AppBundle\Entity\Questionnaire;
use AppBundle\Entity\FirstQuestions;
use AppBundle\Entity\SecondQuestions;

class TestController extends Controller
{

    /**
     * @Route("/test", name="test")
     */
    public function indexAction(Request $request)
    {
        $item = new FirstQuestions(); // everything works well without this line
        return new Response(
            'ok'
        );
    }
}

Maybe I am doing something wrong or didn't set any important annotation. Can anyone help me?

Network_SPY
  • 263
  • 1
  • 2
  • 9

2 Answers2

2

This will be one of those annoying little oversight errors - an extra semi-colon or something somewhere that you're not looking for it. I'm creating this additional answer so that I can give you exactly the code I'm using. Hopefully, you'll be able to cut-and-paste, replace your own files with this new code, and it will magically start working.

First - to prove the point, here's my (modified) output:

Veromo\Bundle\CoreBundle\Entity\FirstQuestions Object
(
    [firstName:Veromo\Bundle\CoreBundle\Entity\FirstQuestions:private] => 
    [lastName:Veromo\Bundle\CoreBundle\Entity\FirstQuestions:private] => 
    [email:Veromo\Bundle\CoreBundle\Entity\FirstQuestions:private] => 
    [birthday:Veromo\Bundle\CoreBundle\Entity\FirstQuestions:private] => 
    [shoeSize:Veromo\Bundle\CoreBundle\Entity\FirstQuestions:private] => 
    [id:Veromo\Bundle\CoreBundle\Entity\Questionnaire:private] => 
)

Which shows that all I'm doing differently to you is using my own dev environment's namespaces.

AppBundle\Entity\Questionnaire.php

<?php

namespace AppBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * Questionnaire
 *
 * @ORM\Entity
 * @ORM\Table(name="questionnaire")
 * @ORM\InheritanceType("SINGLE_TABLE")
 * @ORM\DiscriminatorColumn(name="discr", type="string")
 * @ORM\DiscriminatorMap({"questionnaire"="Questionnaire", "firstquestions" = "FirstQuestions", "secondquestions" = "SecondQuestions"})
 */
abstract class Questionnaire {
    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

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

AppBundle\Entity\FirstQuestions.php

<?php

namespace AppBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * FirstQuestions
 * @ORM\Entity()
 */
class FirstQuestions extends Questionnaire {
    /**
     * @var string
     *
     * @ORM\Column(name="firstName", type="string", length=64)
     */
    private $firstName;

    /**
     * @var string
     *
     * @ORM\Column(name="lastName", type="string", length=64)
     */
    private $lastName;

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

    /**
     * @var \DateTime
     *
     * @ORM\Column(name="birthday", type="date")
     */
    private $birthday;

    /**
     * @var integer
     *
     * @ORM\Column(name="shoeSize", type="integer")
     */
    private $shoeSize;

    /**
     * Set firstName
     *
     * @param string $firstName
     *
     * @return Questionnaire
     */
    public function setFirstName($firstName)
    {
        $this->firstName = $firstName;

        return $this;
    }

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

    /**
     * Set lastName
     *
     * @param string $lastName
     *
     * @return Questionnaire
     */
    public function setLastName($lastName)
    {
        $this->lastName = $lastName;

        return $this;
    }

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

    /**
     * Set email
     *
     * @param string $email
     *
     * @return Questionnaire
     */
    public function setEmail($email)
    {
        $this->email = $email;

        return $this;
    }

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

    /**
     * Set birthday
     *
     * @param \DateTime $birthday
     *
     * @return Questionnaire
     */
    public function setBirthday($birthday)
    {
        $this->birthday = $birthday;

        return $this;
    }

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

    /**
     * Set shoeSize
     *
     * @param integer $shoeSize
     *
     * @return Questionnaire
     */
    public function setShoeSize($shoeSize)
    {
        $this->shoeSize = $shoeSize;

        return $this;
    }

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

AppBundle\Entity\SecondQuestions.php

<?php

namespace AppBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * SecondQuestions
 * @ORM\Entity()
 */
class SecondQuestions extends Questionnaire {
    /**
     * @var string
     *
     * @ORM\Column(name="favoriteIceCream", type="string", length=128)
     */
    private $favoriteIceCream;

    /**
     * @var string
     *
     * @ORM\Column(name="favoriteSuperHero", type="string", length=32)
     */
    private $favoriteSuperHero;

    /**
     * @var string
     *
     * @ORM\Column(name="favoriteMovieStar", type="string", length=64)
     */
    private $favoriteMovieStar;

    /**
     * @var \DateTime
     *
     * @ORM\Column(name="endOfTheWorld", type="date")
     */
    private $endOfTheWorld;

    /**
     * @var string
     *
     * @ORM\Column(name="superBowlWinner", type="string", length=32)
     */
    private $superBowlWinner;

    /**
     * Set favoriteIceCream
     *
     * @param string $favoriteIceCream
     *
     * @return Questionnaire
     */
    public function setFavoriteIceCream($favoriteIceCream)
    {
        $this->favoriteIceCream = $favoriteIceCream;

        return $this;
    }

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

    /**
     * Set favoriteSuperHero
     *
     * @param string $favoriteSuperHero
     *
     * @return Questionnaire
     */
    public function setFavoriteSuperHero($favoriteSuperHero)
    {
        $this->favoriteSuperHero = $favoriteSuperHero;

        return $this;
    }

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

    /**
     * Set favoriteMovieStar
     *
     * @param string $favoriteMovieStar
     *
     * @return Questionnaire
     */
    public function setFavoriteMovieStar($favoriteMovieStar)
    {
        $this->favoriteMovieStar = $favoriteMovieStar;

        return $this;
    }

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

    /**
     * Set endOfTheWorld
     *
     * @param \DateTime $endOfTheWorld
     *
     * @return Questionnaire
     */
    public function setEndOfTheWorld($endOfTheWorld)
    {
        $this->endOfTheWorld = $endOfTheWorld;

        return $this;
    }

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

    /**
     * Set superBowlWinner
     *
     * @param string $superBowlWinner
     *
     * @return Questionnaire
     */
    public function setSuperBowlWinner($superBowlWinner)
    {
        $this->superBowlWinner = $superBowlWinner;

        return $this;
    }

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

AppBundle\Controller\TestController.php

<?php

namespace AppBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Request;
use AppBundle\Entity\Questionnaire;
use AppBundle\Entity\FirstQuestions;
use AppBundle\Entity\SecondQuestions;

class TestController extends Controller
{
    /**
     * @Route("/test",name="test")
     */
    public function indexAction( Request $request )
    {
        $item = new FirstQuestions();
        return new Response(
            '<pre>'.print_r( $item, true ).'</pre>'
        );
    }
}

And just to be sure ...

app\config\routing.yml

test:
    resource:   "@AppBundle/Controller/TestController.php"
    type:       annotation

It's GOT to be some stupid, annoying little error that nobody is looking for.

Hope this helps ...

Ragdata
  • 1,156
  • 7
  • 16
  • Thank you so much for the help, man. Silly me, the problem was that I didn't clean /app/cache directory and new changes with annotations didn't come into effect because of it. Now everything works and I am able to create child objects. – Network_SPY Sep 28 '15 at 14:45
  • Awesome! Glad to hear it. – Ragdata Sep 28 '15 at 21:08
1

ALL Entity classes which are part of the mapped entity hierarchy need to be specified in the @DiscriminatorMap. So, yes, your annotation is incorrect.

Doctrine Single Table Inheritance

EDIT

You have another annotations error - neither of your subclasses has an @Entity annotation:

/**
 * FirstQuestions
 * @ORM\Entity()
 */
class FirstQuestions extends Questionnaire {

/**
 * SecondQuestions
 * @ORM\Entity()
 */
class SecondQuestions extends Questionnaire {

After fixing this I was able to use Doctrine's Schema Update tool to build the tables AND successfully created a FirstQuestions object.

Ragdata
  • 1,156
  • 7
  • 16
  • I've changed annotation of @DiscriminatorMap and described class Questionnaire there too: @ORM\DiscriminatorMap({"questionnaire"="Questionnaire", "firstquestions" = "FirstQuestions", "secondquestions" = "SecondQuestions"}) But still have that problem – Network_SPY Sep 25 '15 at 21:54
  • @Regdata yeah, I've already tried to change the annotations like in your example, also tried to change scope of properties from private to protected. But nothing helped, still have this error. – Network_SPY Sep 27 '15 at 17:13
  • @Regdata It's great that your solution successfully worked, so I still don't lose hope that I will be able to solve this problem too. Could you show me please all your code including controller with method where you create FirstQuestions object? – Network_SPY Sep 27 '15 at 17:22
  • Controller was no different to yours. Have you run the schema update tool - actually built your entity tables? – Ragdata Sep 27 '15 at 20:23
  • http://symfony.com/doc/current/book/doctrine.html#creating-the-database-tables-schema – Ragdata Sep 27 '15 at 20:24
  • @Regdata yeah, of course, I had run it before I wrote my question here. It created 1 table Questionnaire with all fields that described in 3 classes. – Network_SPY Sep 28 '15 at 07:48
  • Sorry mate - I HAD to ask. I've just retested ... created each entity in exactly the same way as you ... switched to an annotated route for my controller ... imported exactly the same namespaces (well - my entities are under a different namespace - but that's not the issue here) ... cut-and-pasted your indexAction function ... and ALL IS WELL. Aside from those problems I caught in my answer to you, there's nothing wrong here - I get a happy "ok" response with your code – Ragdata Sep 28 '15 at 08:30
  • The ONLY thing different between us is that I'm using a file called 'ScratchController.php' and you're using 'TestController.php'. I can even var_dump the FirstQuestions Entity for you ... – Ragdata Sep 28 '15 at 08:33