Остановить 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);
        }
    }
}