Идентификатор объекта родителя не сохраняется в отношениях OneToMany в SonataAdmin

Я использую SonataAdmin (и Symfony2) для управления моими объектами. У меня есть отношения oneToMany между одним шагом и многими задачами. Поскольку один шаг может содержать много Заданий, когда я создаю Шаг, я хочу иметь возможность создавать много Заданий, и я хочу, чтобы эти задачи были связаны с этим Шагом. Для этого я создал все соответствующие классы admin (один для Task и один для Step).

Здесь то, что я делаю, вызывает мою проблему. Когда я пытаюсь создать Шаг, я могу создать задачи и даже переупорядочить их, что отлично и все сделано автоматически SonataAdminBundle. Когда я нажимаю на сохранение, все сохраняется в базе данных, за исключением того, что в базе данных идентификатор шага не задан в строке Задачи. Поэтому задачи не связаны с этапом...

Здесь мой класс администратора:

<?php
// src/Acme/DemoBundle/Admin/PostAdmin.php

namespace IMA\ProcessManagementBundle\Admin;

use Sonata\AdminBundle\Admin\Admin;
use Sonata\AdminBundle\Datagrid\ListMapper;
use Sonata\AdminBundle\Datagrid\DatagridMapper;
use Sonata\AdminBundle\Form\FormMapper;

class StepAdmin extends Admin
{
    // Fields to be shown on create/edit forms
    protected function configureFormFields(FormMapper $formMapper)
    {
        $formMapper
            ->add('name', 'text', array('label' => 'Nom de l\'étape'))

            ->add('tasks', 'sonata_type_collection', array(), array(
                'edit' => 'inline',
                'inline' => 'table',
                'sortable'  => 'positionNumber'
            ))
            ->add('positionNumber', 'integer', array('label' => 'Position'))
        ;
    }

    // Fields to be shown on filter forms
    protected function configureDatagridFilters(DatagridMapper $datagridMapper)
    {
        $datagridMapper
            ->add('name')

        ;
    }

    // Fields to be shown on lists
    protected function configureListFields(ListMapper $listMapper)
    {
        $listMapper
            ->addIdentifier('name')
            ->add('slug')
        ;
    }
}

Здесь также мой класс администрирования Task:

<?php
// src/Acme/DemoBundle/Admin/PostAdmin.php

namespace IMA\ProcessManagementBundle\Admin;

use Sonata\AdminBundle\Admin\Admin;
use Sonata\AdminBundle\Datagrid\ListMapper;
use Sonata\AdminBundle\Datagrid\DatagridMapper;
use Sonata\AdminBundle\Form\FormMapper;

class TaskAdmin extends Admin
{
    // Fields to be shown on create/edit forms
    protected function configureFormFields(FormMapper $formMapper)
    {
        $formMapper
            ->add('name', 'text', array('label' => 'Tâche'))
            ->add('positionNumber', 'integer', array('label' => 'Position'))

        ;
    }

    // Fields to be shown on filter forms
    protected function configureDatagridFilters(DatagridMapper $datagridMapper)
    {
        $datagridMapper
            ->add('name')

        ;
    }

    // Fields to be shown on lists
    protected function configureListFields(ListMapper $listMapper)
    {
        $listMapper
            ->addIdentifier('name')
            ->add('slug')
        ;
    }
}

Кроме того, вот описание моих сущностей

IMA\ProcessManagementBundle\Entity\Step:
    type: entity
    table: null
    fields:
        id:
            type: integer
            id: true
            generator:
                strategy: AUTO
        name:
            type: string
            length: 255
        positionNumber:
            type: integer


    oneToMany:
        tasks:
            targetEntity: Task
            mappedBy: step
            cascade: ["persist", "merge"]

    lifecycleCallbacks: {  }


IMA\ProcessManagementBundle\Entity\Task:
    type: entity
    table: null
    fields:
        id:
            type: integer
            id: true
            generator:
                strategy: AUTO
        name:
            type: string
            length: 255
        positionNumber:
            type: integer


    manyToOne:
        step:
            targetEntity: Step
            inversedBy: tasks


    lifecycleCallbacks: {  }

Мне интересно, почему id шага не задан в строке Task...

Ответы

Ответ 1

Вам нужно вручную прикрепить шаг к задачам, для этого вам нужно использовать методы prePersist и preUpdate в классе шагов администратора...

Причиной этого является то, что разработчики SonataAdminBundle говорят, что это доктрина, чтобы справиться с этим, и разработчики Doctrine говорят, что это ответственность за связки... Поэтому пока нам нужно сделать это для себя.

Это будет ваш новый класс stepAdmin:

<?php
namespace IMA\ProcessManagementBundle\Admin;

use Sonata\AdminBundle\Admin\Admin;
use Sonata\AdminBundle\Datagrid\ListMapper;
use Sonata\AdminBundle\Datagrid\DatagridMapper;
use Sonata\AdminBundle\Form\FormMapper;

class StepAdmin extends Admin
{
    // Fields to be shown on create/edit forms
    protected function configureFormFields(FormMapper $formMapper)
    {
        $formMapper
            ->add('name', 'text', array('label' => 'Nom de l\'étape'))

            ->add('tasks', 'sonata_type_collection', array(), array(
                'edit' => 'inline',
                'inline' => 'table',
                'sortable'  => 'positionNumber'
            ))
            ->add('positionNumber', 'integer', array('label' => 'Position'))
        ;
    }

    // Fields to be shown on filter forms
    protected function configureDatagridFilters(DatagridMapper $datagridMapper)
    {
        $datagridMapper
            ->add('name')

        ;
    }

    // Fields to be shown on lists
    protected function configureListFields(ListMapper $listMapper)
    {
        $listMapper
            ->addIdentifier('name')
            ->add('slug')
        ;
    }


    public function prePersist($object)
    {
        foreach ($object->getTasks() as $task) {
            $task->setStep($object);
        }
    }

    public function preUpdate($object)
    {
        foreach ($object->getTasks() as $task) {
            $task->setStep($object);
        }
    }


}

Ответ 2

В вашей организации Step вы должны добавить метод addTask:

class Step
{
    //...

    public function addTask($tasks)
    {
        $tasks->setStep($this);
        $this->tasks[] = $tasks;

        return $this;
    }

    //...
}

Поскольку вы не предоставляете свой Step.php, вы должны соответствующим образом адаптировать этот код.