Остановить SonataAdmin/Symfony2 от создания пустых объектов с помощью встроенных администраторов sonata_type_admin
Прежде всего, я не уверен, что это проблема сонаты или Symfony2, это первый раз, когда я работаю с формами Sf2 для редактирования отношений.
Здесь проблема:
У меня есть два класса, назовите их старыми фаворитами: Car
и Wheel
. У автомобиля есть необязательные отношения "один-к-одному" с колесом (это, к примеру, просто пойдите с ним...). Я создал SonataAdmin с классом CarAdmin
, который использует WheelAdmin
с помощью sonata_type_admin
и пытается создать автомобиль без ввода каких-либо данных для Wheel.
Однако, на submit (где-то в $form- > bind()/$form- > submit(), насколько я могу проследить) Symfony и/или Sonata создает экземпляр Колеса и пытается его сохранить (со всеми его значения null
). Поскольку у Колеса есть некоторые ненулевые ограничения, это исключает исключение DBALException, в котором вы не можете вставить колесо с нулевыми значениями.
Это непослушный характер, и я хотел бы остановить его. Если я не буду вводить какие-либо данные для Wheel, мне не нужен колесо phantom, угрожающее моему коду и базе данных. Я ожидаю, что если я не буду вводить данные, нечего вставлять/сохранять, чтобы он остался один. Но это не то, что происходит... любые идеи, как приручить это во что-то разумное?
Здесь длинная версия с блоками кода и всего:
Сначала определены ORM:
# MyNS\MyBundle\Resources\Config\Doctrine\Car.orm.yml
MyNS\MyBundle\Entity\Car:
type: entity
repositoryClass: MyNS\MyBundle\Entity\Repositories\CarRepository
table: test_cars
id:
id:
type: integer
generator: { strategy: AUTO }
fields:
color:
type: string
length: 50
owner:
type: string
length: 50
nullable: true
oneToOne:
leftFrontWheel:
targetEntity: Wheel
cascade: [ persist ]
joinColumn:
name: leftFrontWheelId
referencedColumnName: id
# MyNS\MyBundle\Resources\Config\Doctrine\Wheel.orm.yml
MyNS\MyBundle\Entity\Wheel:
type: entity
repositoryClass: MyNS\MyBundle\Entity\Repositories\WheelRepository
table: test_wheels
id:
id:
type: integer
generator: { strategy: AUTO }
fields:
diameter:
type: integer
length: 5
Затем классы SonataAdmin:
namespace MyNS\MyBundle\Admin
use ...
class CarAdmin extends Admin
{
protected function configureFormFields(FormMapper $formMapper)
{
$formMapper
->add('color', null, array('required' => true))
->add('owner', null, array('required' => false))
->add('leftFrontWheel', 'sonata_type_admin', array('delete' => false))
;
}
protected function configureListFields(ListMapper $listMapper) { ... }
}
и
namespace MyNS\MyBundle\Admin;
use ...
class WheelAdmin extends Admin
{
protected function configureFormFields(FormMapper $formMapper)
{
$formMapper
->add('diameter', null, array('required' => false))
;
}
protected function configureListFields(ListMapper $listMapper) { ... }
}
и, наконец, записи admin.yml:
services:
sonata.admin.car:
class: MyNS\MyBundle\Admin\CarAdmin
tags:
- { name: sonata.admin, manager_type: orm, label: "Car" }
arguments:
- ~
- MyNS\MyBundle\Entity\Car
- 'SonataAdminBundle:CRUD'
calls:
- [ setTranslationDomain, [MyNS\MyBundle]]
sonata.admin.wheel:
class: MyNS\MyBundle\Admin\WheelAdmin
tags:
- { name: sonata.admin, manager_type: orm, label: "Wheel" }
arguments:
- ~
- MyNS\MyBundle\Entity\Wheel
- 'SonataAdminBundle:CRUD'
calls:
- [ setTranslationDomain, [MyNS\MyBundle]]
Ожидаемое/требуемое поведение:
-
Отобразить форму с тремя полями:
- car.color(обязательно)
- car.owner(необязательно)
- car.wheel.diameter(опционально)
-
Если car.wheel.diameter остается пустым, тогда не нужно создавать колесо и test_cars.leftFrontWheelId
должен оставаться null
в базе данных
-
Если введено car.wheel.diameter, тогда необходимо создать колесо и связать его с автомобилем (это, похоже, отлично работает с существующей конфигурацией)
Вопрос: Как заставить эту систему вести себя как указано выше?
Ответы
Ответ 1
Это может быть вызвано отсутствием 'required' => false
, no?
protected function configureFormFields(FormMapper $formMapper) {
$formMapper
->add('color', null, array('required' => true))
->add('owner', null, array('required' => false))
->add('leftFrontWheel', 'sonata_type_admin', array('required' => false, 'delete' => false))
;
}
Ответ 2
Измените поле формы Wheel
для чего-то вроде:
$formMapper
// ...
->add('leftFrontWheel', 'sonata_type_admin', array(
'delete' => false,
'by_reference => true,
'required' => false,
))
// ...
См. by_reference
документация
Если этого недостаточно, используйте в своем родительском классе администратора перехват prePersist и определите, какое поле вы храните. то есть:
// Fire on submit, before the object persisting
public function prePersist($object)
if ($wheel = $object->getLeftFrontWheel()) {
if (!$wheel->getYourNonNullableField()) {
$object->setLefTFrontWheel(null);
}
}
}