Идентификатор объекта родителя не сохраняется в отношениях 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
, вы должны соответствующим образом адаптировать этот код.