Sonata-admin cannot modify classes with inheritance

php, sonata-admin, symfony

Solution

First, there is a typo in your namespace in `QuestionAdmin`, it should probably be

`use Hippy\ScavengerHuntBundle\Entity\LettersInOrderQuestion;`

and not (Oder instead of Order"

`use Hippy\ScavengerHuntBundle\Entity\LettersInOderQuestion;`

Secondly, also in `QuestionAdmin`, you are mixing the Admin class and the entity class. See here, you have:

if ($subject instanceof LettersInOrderQuestionAdmin) {

it should be, according to your code:

if ($subject instanceof LettersInOrderQuestion) {

Finally, in SonataAdmin, it looks like if you put only one subclass, the class never gets active. You have to put at least two subClasses, if not, the subclass never gets active, see here :

public function hasActiveSubClass()
{
    if (count($this->subClasses) > 1 && $this->request) {
        return null !== $this->getRequest()->query->get('subclass');
    }

    return false;
} 

An issue has been opened here : https://github.com/sonata-project/SonataAdminBundle/issues/1945

Problem

I am using Symfony2 and I have a hierarchy of classes. The hierarchy is pretty simple, I have a Question (the parent) and many different sub-questions. Using Sonata, I want to be able to create different types of questions, that are sub-questions. To do so, I created a hierarchy of classes as follows : ``` Hippy\ScavengerHuntBundle\Entity\Question: type: entity table: null inheritanceType: JOINED discriminatorColumn: name: subClass type: string discriminatorMap: blurredMultipleChoiceQuestion: BlurredMultipleChoiceQuestion blurredTextQuestion: BlurredTextQuestion slidingPuzzleQuestion: SlidingPuzzleQuestion associationQuestion: AssociationQuestion trueOrFalseQuestion: TrueOrFalseQuestion lettersInOrderQuestion: LettersInOrderQuestion shortTextQuestion: ShortTextQuestion multipleChoiceQuestion: MultipleChoiceQuestion sentenceGapQuestion: SentenceGapQuestion fields: id: type: integer id: true generator: strategy: AUTO title: type: string length: 255 position: type: integer lifecycleCallbacks: { } ``` And I'll show you one example of a subclass ``` Hippy\ScavengerHuntBundle\Entity\LettersInOrderQuestion: type: entity table: null fields: description: type: text lifecycleCallbacks: { } <?php namespace Hippy\ScavengerHuntBundle\Entity; use Doctrine\ORM\Mapping as ORM; /** * LettersInOrderQuestion */ class LettersInOrderQuestion extends Question { /** * @var string */ private $description; /** * Set description * * @param string $description * @return LettersInOrderQuestion */ public function setDescription($description) { $this->description = $description; return $this; } /** * Get description * * @return string */ public function getDescription() { return $this->description; } } ``` At this point, everything seems to be set up properly (the database and the php classes). Now, I want to integrate this to SonataAdmin, so I added the following in the services ``` sonata.admin.question: class: Hippy\ScavengerHuntBundle\Admin\QuestionAdmin tags: - { name: sonata.admin, manager_type: orm, group: "Questions", label: "Question" } arguments: - ~ - Hippy\ScavengerHuntBundle\Entity\Question - ~ calls: - [ setTranslationDomain, [HippyScavengerHuntBundle]] - [ setSubClasses, [{lettersInOrderQuestion : "Hippy\ScavengerHuntBundle\Entity\LettersInOrderQuestion"}]] ``` And I created a class QuestionAdmin.php ``` <?php // src/Acme/DemoBundle/Admin/PostAdmin.php namespace Hippy\ScavengerHuntBundle\Admin; use Sonata\AdminBundle\Admin\Admin; use Sonata\AdminBundle\Datagrid\ListMapper; use Sonata\AdminBundle\Datagrid\DatagridMapper; use Sonata\AdminBundle\Form\FormMapper; use Hippy\ScavengerHuntBundle\Entity\LettersInOderQuestion; class QuestionAdmin extends Admin { // Fields to be shown on create/edit forms protected function configureFormFields(FormMapper $formMapper) { $subject = $this->getSubject(); var_dump($subject); //exit(); if ($subject instanceof LettersInOrderQuestionAdmin) { $formMapper->add('description', 'text'); } } // Fields to be shown on filter forms protected function configureDatagridFilters(DatagridMapper $datagridMapper) { $datagridMapper ->add('title') ; } // Fields to be shown on lists protected function configureListFields(ListMapper $listMapper) { $listMapper ->addIdentifier('title') ; } } ``` At this point, one thing that is cool is that Sonata admin seems to recognize that I'm dealing with subclasses, take a look : My problem is that when I try to create a lettersInOrderQuestion object, it is not recognized as a lettersInOrderQuestion but only as a Question. See here : We can see, first via the var_dump and second because the form description is not show, that the object passed is a Question and not a LettersInOrderQuestion, even though the url is ``` /admin/hippy/scavengerhunt/question/create?subclass=lettersInOrderQuestion ``` I'm running out of ideas.... Edit1: In Question AdminClass, in the configureFormFields method, I added ``` var_dump($this->getSubClasses()); ``` and the result was the following: ``` array (size=1) 'lettersInOrderQuestion' => string 'Hippy\ScavengerHuntBundle\Entity
ettersInOrderQuestion' (length=56) ``` Therefore, it looks like there is an error in the parsing of the entity class as the name gets mixed up...

Original source