phpsymfony1symfony-formssymfony-1.4

How to display radio buttons of a sfWidgetFormChoice individually?


I'd like to render a symfony form this way:

form with radio buttons

My problem concerns the radio buttons widget: I don't know how to render each choice individually, in order to display other fields between those radio buttons.

Is there a way to achieve this with symfony forms?

Thanks!


Solution

  • Symfony makes this a little difficult to do. You'd like a renderChoice( $value) method that's callable from the view, but that would require changing or extending sfFormField.

    Changing it isn't future proof, and extending it would also require you to change some symfony variable so the fields accessible in your view are instances of this new class. I don't know if that option exists.

    Instead, I opted to extend sfWidgetFormSelectRadio into the following very simple class which extends formatChoices. It will check if you're asking for only one option. If you are, it renders that tag and returns it, otherwise it renders normally via parent::.

    This lets you call from your view: $form['field']->render(array('only_choice'=> $value))
    where $value is the index of the radio option you want to render:

    <?php
    
    /**
     * sfWidgetFormSelectRadioSingleable lets you render just one option at a time.
     *
     * @package    symfony
     * @subpackage widget
     * @author     Fabien Potencier <fabien.potencier@symfony-project.com>
     * @version    SVN: $Id: sfWidgetFormSelectRadio.class.php 27738 2010-02-08 15:07:33Z Kris.Wallsmith $
     */
    class sfWidgetFormSelectRadioSingleable extends sfWidgetFormSelectRadio
    {
      public function formatChoices($name, $value, $choices, $attributes)
      {
        $onlyChoice = (!empty($attributes['only_choice'])) ? $attributes['only_choice'] : false; unset($attributes['only_choice']);
    
        if($onlyChoice)
        {
          if(!isset($choices[$onlyChoice]))
              throw new Exception("Option '$onlyChoice' doesn't exist.");
    
          $key    = $onlyChoice;
          $option = $choices[$key];
          $baseAttributes = array(
            'name'  => substr($name, 0, -2),
            'type'  => 'radio',
            'value' => self::escapeOnce($key),
            'id'    => $id = $this->generateId($name, self::escapeOnce($key)),
          );
    
          if (strval($key) == strval($value === false ? 0 : $value))
          {
            $baseAttributes['checked'] = 'checked';
          }
    
          return $this->renderTag('input', array_merge($baseAttributes, $attributes));
        }
        else
        {
          return parent::formatChoices($name, $value, $choices, $attributes);
        }
      }
    }
    

    Awkward code, but easy enough to use in practice and it won't break in the future.