0

I've made a form in Symfony that is not bound to an entity. One of the form elements is a set of checkboxes, fieldtypes. Which fieldtype checkboxes show should depend on the value of the searchby field. I want to add a class to each checkbox to use as a show/hide hook for the javascript I will add later. But so far as I can see, the choices form element only allows for an overall class to be applied.

Here's the relevant bit of my form:

$form = $this->createFormBuilder()
    ->add('searchby', 'choice', array(
            'label' => 'browse.label.searchby',
            'choices'=>array(
                'name'              => 'browse.searchby.name',
                'location'          => 'browse.searchby.location',
                'classification'    => 'browse.searchby.classification'
                    ),
            'required' => true,
            'multiple' => false,
            'expanded' => true,
                    ))
    ->add('fieldtypes', 'choice', array(
            'label' => 'browse.label.fieldtypes',
            'choices' => array(
                'extensionAttribute12'      =>  'person.label.position.fr',
                'title'                     =>  'person.label.position.eng',
                'l'                         =>  'person.label.city',
                'st'                        =>  'person.label.province',
                'co'                        =>  'person.label.country',
                'givenname'                 =>  'person.label.firstname',
                'sn'                        =>  'person.label.lastname',
                'name'                      =>  'person.label.fullname',
                ),
            'required' => true,
            'multiple' => true,
            'expanded' => true
                    ));

If I want to add the class 'searchbyname' to the radiobuttons created from $options['choices']['givenname'], $options['choices']['sn'], $options['choices']['name'], how would I go about it?

dnagirl
  • 20,196
  • 13
  • 80
  • 123
  • Sadly you cannot set individual attributes on the options from the form builder. Can you adjust your javascript to key on option values? It will be the easiest way. Otherwise, you will need to customize your form theme and that will be painful. – Cerad Aug 15 '13 at 14:17
  • @Cerad: Drat! I can do the javascript based on values but it's not as clean since added options will mean edits in 2 places instead of one. I saw this answer (http://stackoverflow.com/questions/12244376/select-with-optgroup-in-symfony-2-0). The optgroups are not used for checkboxes, but they should be available to the form theme, no? I will look at the theme and see how grisly the change would be. – dnagirl Aug 15 '13 at 14:24

1 Answers1

1

After seeing that choices could be declared like this:

'choices' => array(
        'classification'    => array(
            'extensionAttribute12'      =>  'person.label.position.fr',
            'title'                     =>  'person.label.position.eng',
            ),
        'location'  => array(
            'l'                         =>  'person.label.city',
            'st'                        =>  'person.label.province',
            'co'                        =>  'person.label.country',
        ),
        'name'  =>  array(
            'givenname'                 =>  'person.label.firstname',
            'sn'                        =>  'person.label.lastname',
            'name'                      =>  'person.label.fullname',
        )
    ),

where the key to each sub array would be used as an <optgroup> label in a <select>; and after attempting to modify the Twig template (which was every bit a painful as @Cerad said it would be), I tried extending the ChoiceType class by creating a form type extension.

My solution is inefficient since I'm modifying the child views after they are created and because I had to include all the code from ChoiceType::finishView. I can't see how a child view is created. There is a line in ChoiceType::buildForm that reads $remainingViews = $options['choice_list']->getRemainingViews();, but since $options['choices'] was input as an array, I don't know what class getRemainingViews() is being called from.

At any rate, here it is:

<?php
namespace Expertise\DefaultBundle\Form\Extension;

use Symfony\Component\Form\AbstractTypeExtension;
use Symfony\Component\Form\FormView;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\PropertyAccess\PropertyAccess;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;


class ChoiceTypeExtension extends AbstractTypeExtension
{
    /**
     * @return string The name of the type being extended
     */
    public function getExtendedType()
    {
        return 'choice';
    }

    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setOptional(array('optgroup_as_class'));
        $resolver->setDefaults(array('optgroup_as_class'=>false));
    }


    public function finishView(FormView $view, FormInterface $form, array $options)
    {

        if ($options['expanded']) {
            // Radio buttons should have the same name as the parent
            $childName = $view->vars['full_name'];

            // Checkboxes should append "[]" to allow multiple selection
            if ($options['multiple']) {
                $childName .= '[]';
            }

            foreach ($view as $childView) {
                $childView->vars['full_name'] = $childName;
                if($options['optgroup_as_class']){
                    foreach($options['choices'] as $optclass => $choices){
                        if(!is_array($choices)) continue;
                        foreach($choices as $value => $label){
                            if($childView->vars['value'] == $value && $childView->vars['label'] == $label) {
                                $childView->vars['attr']['class'] =  $optclass;
                                break 2;
                            }
                        }
                    }
                }
            }
        }
    }
}

Add it as a service, use the "optgroup" choices format and set optgroup_as_class to true.

I'd love to see a more efficient method.

Community
  • 1
  • 1
dnagirl
  • 20,196
  • 13
  • 80
  • 123