1

I've added an entity field type to a form I'm using but when I try to set preferred_choices I get the following error message

Warning: spl_object_hash() expects parameter 1 to be object, string given in /srv/www/amber/public_html/Symfony/vendor/symfony/symfony/src/Symfony/Bridge/Doctrine/Form/Type/DoctrineType.php line 98

You can see the code below

    $builder->add('candStatus', 'entity', array(
        'label' => 'Candidate Status', 
        'class' => 'AmberAtsBundle:SelCandStatus',
        'query_builder' => function(EntityRepository $er) {
            return $er->createQueryBuilder('sc')
            ->orderBy('sc.rank', 'ASC');
            },
         'property' => 'candStatus',
         'preferred_choices' => array('1'),
        ));

I'm fairly new to Symfony, so any help would be appreciated

Ben Stinton
  • 411
  • 2
  • 8
  • 17
  • 1
    Pretty sure that its a problem related to Entity .. post code of the entity if possible.. – Vamsi Krishna B Jun 24 '13 at 14:21
  • I've looked around a bit more, and found the answer within the following 2 question: http://stackoverflow.com/questions/15776867/set-default-value-of-choice-field-symfony-formtype http://stackoverflow.com/questions/5425819/doctrine-2-undefined-entity-method-findoneby I've removed the preferred_choices from the formType, and instead added some code to the controller to pre populate the object before it is used to create the form. I'll post more detail when I can answer in a few hours time – Ben Stinton Jun 24 '13 at 16:26
  • You can use the getReference method for entity manager to construct an array that will work for 'preferred_choices' on an entity form field. See [this question](http://stackoverflow.com/questions/8073236/symfony2-setting-a-default-choice-field-selection/17413107#17413107) – j_goldman Dec 11 '13 at 10:20

4 Answers4

11

This is what works with Symfony 2.7:

$builder->add('license', 'entity', [
    'class' => 'CmfcmfMediaModule:License\LicenseEntity',
    'preferred_choices' => function (LicenseEntity $license) {
        return !$license->isOutdated();
    },
    // ...
])

preferred_choices needs an anonymous function which is called for each entity and must return true or false depending on whether it's preferred or not.

Christian
  • 1,663
  • 19
  • 33
2

I believe you need to pass into your form an EntityRepository (or similar) and actually provide a collection of entities to preferred_choices. From memory, in previous versions of Symfony it would permit an array of entity IDs, but not now.

Probably preferred_choices should also be a callback, like query_builder.

The code that actually determines if something from preferred_choices matches a particular choices is below. It's just a simple PHP array_search().

Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceList #

protected function isPreferred($choice, array $preferredChoices)
{
    return false !== array_search($choice, $preferredChoices, true);
}
Ryan
  • 4,594
  • 1
  • 32
  • 35
1

From your example, where you want to get the first result as the prefered choice, you have to return the entity with the first rank and not its index.

To do so, you can retrive it in the controller then pass it as a parameter in $options:

public function buildForm(FormBuilderInterface $builder, array $options)
{
    //prevent error if $options['prefered_choices'] is not set
    $prefered_choices = isset($options['prefered_choices']) ? $options['prefered_choices'] : array();
    $builder->add('candStatus', 'entity', array(
        'label' => 'Candidate Status', 
        'class' => 'AmberAtsBundle:SelCandStatus',
        'query_builder' => function(EntityRepository $er) {
            return $er->createQueryBuilder('sc')
                ->orderBy('sc.rank', 'ASC')
            ;
        },
        'property' => 'candStatus',
        'preferred_choices' => $prefered_choices,
    ));
    //...
}

You can also use getReference, as j_goldman noted in their comment, but since your ranks can change (I think), I don't think it fit well for your use case:

$builder->add('candStatus', 'entity', array(
    'label' => 'Candidate Status', 
    'class' => 'AmberAtsBundle:SelCandStatus',
    'query_builder' => function(EntityRepository $er) {
        return $er->createQueryBuilder('sc')
            ->orderBy('sc.rank', 'ASC')
        ;
    },
    'property' => 'candStatus',
    'prefered_choices' => $this->em->getReference('AmberAtsBundle:SelCandStatus', 1),
));

Finally, you can use a callback returning the chosen entity, for example with the same DQL you used with a limit of 1: (It's what I would do)

$builder->add('candStatus', 'entity', array(
    'label' => 'Candidate Status', 
    'class' => 'AmberAtsBundle:SelCandStatus',
    'query_builder' => function(EntityRepository $er) {
        return $er->createQueryBuilder('sc')
            ->orderBy('sc.rank', 'ASC')
        ;
    },
    'property' => 'candStatus',
    'preferred_choices' => function(EntityRepository $er) {
        return $er->createQueryBuilder('sc')
            ->orderBy('sc.rank', 'ASC')
            ->setMaxResults(1)
        ;
    },
));
Community
  • 1
  • 1
Veve
  • 6,643
  • 5
  • 39
  • 58
  • your last example will not work. you are given the entity object, not the Repository in the preferred_choices closure. At least this was the only object i was geting. – Rufinus Nov 27 '15 at 00:12
0

In Symfony3 the following works for me:

'preferred_choices' => function($entity) {
                $preferred = [1, 2];
                $choices = [];

                if(in_array($entity->getId(), $preferred)) {
                    $choices[] = $entity;
                }

                return $choices;
            },