I have a OneToOne relationship between Page and SuperGridContent:
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity
* @ORM\Table(name="page")
* @ORM\HasLifecycleCallbacks
*/
class Page
{
/**
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
//...
/**
* @ORM\OneToOne(targetEntity="AppBundle\Entity\SuperGridContent", mappedBy="page", cascade={"persist", "remove"})
*/
protected $super_grid;
//...
}
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity
* @ORM\Table(name="super_grid_content")
* @ORM\HasLifecycleCallbacks
*/
class SuperGridContent
{
/**
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @ORM\OneToOne(targetEntity="AppBundle\Entity\Page", inversedBy="super_grid")
*/
private $page;
//...
}
Then in the page admin class I have:
<?php
namespace AppBundle\Admin;
use AppBundle\Entity\Page;
use Sonata\AdminBundle\Admin\AbstractAdmin;
use Sonata\AdminBundle\Form\FormMapper;
use Sonata\AdminBundle\Form\Type\ModelType;
class PageAdmin extends AbstractAdmin
{
protected function configureFormFields(FormMapper $formMapper)
{
$formMapper
->add('super_grid', ModelType::class, [
'label' => 'Super Grid',
'required' => false,
])
// ...
;
}
// ...
}
The problem is that when I create or edit a Page, the super_grid field is a select tag with all existing SuperGridContent as options. Even when they already have a Page relationship. If I select one of those, of course it fails, because the relationship is suposed to be unique.
Am I missing something or is there a way Sonata could handle it?
I'm using SonataAdminBundle 3.4
If I understand correctly you problem, I think you could use Symfony Entity Type instead of the Model Type as stated in Sonata documentation.
But I also think that your life would be much easier if you inverted the ownership of the OneToOne relationship. In your example
SuperGridContentis owning the relationship so when you want to update thesuper_gridof aPageyou might run into a constraint violation. If you changeinversedBytomappedByin theSuperGridContentclass andmappedBytoinversedByin thePageclass (+ if you regenerate your tables and make sure the cascading logic fits your needs) you should be OK.If I understand well, you want any new
Pageto have only the availablesuper_grids as choices and any existingPageto have its currentsuper_grid+ all the availablesuper_grids as choices.Then something like the following would do the job (careful that I am using Symfony 4.4, there might be slight syntax differences with your implementation):