First of all, I'm not sure if this is a Sonata issue or a Symfony2 one, this is the first time I'm working with Sf2 forms to edit a relationship.
Here's the problem:
I have two classes, let's call them the old favourites: Car
and Wheel
. Car has an optional one-to-one relationship with Wheel (it's for the example, just go with it...). I have set up SonataAdmin with a CarAdmin
class which embeds a WheelAdmin
using sonata_type_admin
and try to create a Car without entering any data for Wheel.
However, on submit (somewhere in $form->bind()/$form->submit() as far as I can trace) Symfony and/or Sonata is instantiating a Wheel and trying to persist it (with all its values as null
). Since the Wheel has some non-null constraints this throws a DBALException complaining that you cannot INSERT a Wheel with null vlaues.
This is naughty and I'd like to stop it happening. If I don't enter any details for Wheel I don't want a phantom Wheel menacing my code and database. What I expect is that if I enter no data there is nothing to insert/persist so it's left alone. But this is not what's happening... any ideas how to tame this into something sensible?
Here's the long version, with code blocks and everything:
The ORM definitions first:
# 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
Then the SonataAdmin classes:
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) { ... }
}
and
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) { ... }
}
and finally the admin.yml entries:
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]]
Expected/required behaviour:
Display a form with three fields:
- car.color (required)
- car.owner (optional)
- car.wheel.diameter (optional)
if car.wheel.diameter is left blank then no Wheel should be created and
test_cars.leftFrontWheelId
should remainnull
in the databaseif car.wheel.diameter is entered then a Wheel should be created and linked to the Car (this seems to work fine with the existing config)
The question: How do I get this system to behave as above?
$car->setLeftFrontWheel(null)
clears the relationship and stops it trying to persist an empty Wheel.) – caponica