0

I have an one to one relation in my sonata admin bundle.

Person <-> Player. 

If i go to my Person admin i can choose the player from the choice list.

If i go to another Person object the player (which is now already assigned) is shown again ... if i choose it, there occurs an error ...

The error is

Failed to update object: AppBundle\Entity\Person

SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '18' for key 'UNIQ_9A5FDF45F6B75B26'

Can i change the behaviour that already assigned values do not appear in other objects?

I cant find a option for doing this in sonata admin

Community
  • 1
  • 1
Jim Panse
  • 2,220
  • 12
  • 34

1 Answers1

0

You can generate a custom choice list for every Person.

Add method to PlayerRepository:

class PlayerRepository extends EntityRepository
{
    public function getNotAssociatedPlayers($person)
    {
        $qb = $this->createQueryBuilder('p')
                   ->leftJoin('p.person', 'prsn')
                   ->where('prsn.id is null');
        if($person !== null)
        {
            $qb->orWhere('prsn.id = :person')
               ->setParameter('person', $person);
        }

        return $qb->getQuery()
                  ->getResult();
    }
}

And use it in PersonAdmin:

protected function configureFormFields(FormMapper $formMapper)
{
    $person = ($this->getSubject()->getPlayer() !== null)
              ? $this->getSubject()->getId()
              : null;
    $em = $this->getConfigurationPool()->getContainer()->get('doctrine.orm.entity_manager');
    $choices = $em->getRepository('YourBundle:Player')->getNotAssociatedPlayers($person);

    $formMapper
        ->add('player', null, array(
            'choices' => $choices,
        ));

Please, let me know if something went wrong with that.

EDIT:

Documented solution is a query_builder option for the field:

$formMapper
    ->add('player', null, array(
        'query_builder' => function(EntityRepository $er) 
        {
            $qb = $er->createQueryBuilder('p')
                     ->leftJoin('p.person', 'prsn')
                     ->where('prsn.id is null');
            if($this->getSubject()->getPlayer() !== null)
            {
                $qb->orWhere('prsn.id = :person')
                   ->setParameter('person', $this->getSubject()->getId());
            }
            return $qb;
        }
    ));
Snegirekk
  • 724
  • 7
  • 12
  • Thats already a good approach, thanks for that! But there is one problem ... if i assign the player in the person form and the site reloads, my input box is empty due to the now assigned entity ... so now my approach is, to write an own query in the query_builder property of the formmapper and select all which are not assigned OR the one which is assigned to my current person ... if this is possible in the entity with your approach, it should be much cleaner i think. Let me know if there is a solution for that. – Jim Panse Nov 15 '17 at 07:39
  • @JimPanse , i've updated my answer. But i'm not sure i've understood you correctly (thanks to my poor english). Do you mean this code doesn't work as expected for you? Or do you need more elegant solution? – Snegirekk Nov 15 '17 at 19:28
  • @JimPanse , oh, i think i've understood u now. Look at my first approach again, please. When we define $person variable, we check that current Person is associated with Player. And in the PlayerRepository we add orWhere clause if necessary. About this? – Snegirekk Nov 15 '17 at 20:03