dnagirl
dnagirl

Reputation: 20456

add class to subset of symfony checkboxes

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?

Upvotes: 0

Views: 1719

Answers (1)

dnagirl
dnagirl

Reputation: 20456

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.

Upvotes: 1

Related Questions