Combining input and choice widget in symfony

This article has moved to this location.


A few month ago, i was redevelop an application, using an existing database. One of the problems I encountered, there is a field whose content is a mixture of integer and string. For example: “1 Day”, “3 Month”, “5 Year”. where the string input should one of the three above (Day or Month or Year).


To overcome this problem, I created a custom widget, which is a combination of input and choice widget. Below is the custom widget i created :

<?php
class myWidgetFormInputTextAndChoice extends sfWidgetForm
{
  protected function configure($options = array(), $attributes = array())
  {
	$this->addOption('text', array());
	$this->addOption('choice', array());
	$this->addOption('format', '%text% %choice%');
	parent::configure($options, $attributes);
  }

  public function render($name, $value = null, $attributes = array(), $errors = array())
  {
       if (null !== $value)
       {
           if (false === is_array($value))
           {
                $tmp = explode(' ', $value);
                $value = array();
                $value['text'] = $tmp[0];
                $value['choice'] = $tmp[1];
           }
       }
       $text = $this->getTextWidget($attributes)->render($name.'[text]', $value['text']);
       return strtr($this->getOption('format'), array(
          '%text%' => $text,
          '%choice%' => $this->getChoiceWidget($attributes)->render($name.'[choice]', $value['choice']),
        ));
  }

  protected function getTextWidget($attributes = array())
  {
    return new sfWidgetFormInputText($this->getOptionsFor('text'), $this->getAttributesFor('text', $attributes));
  }

  protected function getChoiceWidget($attributes = array())
  {
    return new sfWidgetFormChoice($this->getOptionsFor('choice'), $this->getAttributesFor('choice', $attributes));
  }

  protected function getOptionsFor($type)
  {
    $options = $this->getOption($type);
    if (!is_array($options))
    {
      throw new InvalidArgumentException(sprintf('You must pass an array for the %s option.', $type));
    }
    return $options;
  }

  protected function getAttributesFor($type, $attributes)
  {
    $defaults = isset($this->attributes[$type]) ? $this->attributes[$type] : array();
    return isset($attributes[$type]) ? array_merge($defaults, $attributes[$type]) : $defaults;
  }

}

And here is the validator

<?php
class myValidatorInputTextAndChoice extends sfValidatorBase
{
   public function configure($options = array(), $messages = array())
   {
 	parent::configure($options, $messages);
	$this->addRequiredOption('text');
	$this->addRequiredOption('choice');
	$this->addOption('text_field', 'text');
	$this->addOption('choice_field', 'choice');
   }

  public function doClean($value)
  {
       $textField = $this->getOption('text_field');
       $choiceField = $this->getOption('choice_field');
       $value[$textField] = $this->getOption('text')->clean(isset($value[$textField]) ? $value[$textField] : null);
       $value[$choiceField]   =  $this->getOption('choice')->clean(isset($value[$choiceField]) ? $value[$choiceField] : null);

       if ($value[$textField] && $value[$choiceField])
       {
    	    return $value[$textField].' '.$value[$choiceField];
       }
       return $value;
    }
}

To use the widget, in the form configure() :

$choices = array('Day'=>'Day', 'Month'=>'Month', 'Year'=>'Year');
$this->widgetSchema['your_widget'] = new myWidgetFormInputTextAndChoice(array('choice'=>array('choices'=>$choices)));
$this->validatorSchema['your_widget'] = new myValidatorInputTextAndChoice(array('text'=>new sfValidatorInteger(), 'choice'=>new sfValidatorChoice(array('choices'=>array_keys($choices)))));

$this->setDefault('your_widget', '1 Year');
Advertisements

One response to “Combining input and choice widget in symfony

  1. Prasad December 13, 2011 at 11:40 am

    Thanks so much. Very soon I will write a phone-number widget to display country code, area code & number.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: