validationformsdatesymfony1

How to validate a date without day with sfForm?


I'm creating a payment form with symfony 1.4 , and my form has a date widget defined like this, so that the user can select the expiration date of their credit card:

new sfWidgetFormDate(array(
  'format' => '%month%/%year%',
  'years'  => array_combine(range(date('Y'), date('Y') + 5), range(date('Y'), date('Y') + 5))

Notice the absence of %day% in the format like in most payment forms.

Now my problem is that sfValidatorDate requires the day field not to be empty. To work around this, I created a custom validator using a callback, which works well:

public function validateExpirationDate($validator, $value)
{
  $value['day'] = '15';
  $dateValidator = new sfValidatorDate(array(
    'date_format' => '#(?P<day>\d{2})(?P<month>\d{2})(?P<year>\d{2})#',
    'required'    => false,
    'min'         => strtotime('first day of this month')));
  $dateValidator->clean($value);
  return $value;
}

I feel there might be a simpler way to achieve this. What do you think? Have you already solved this problem in a cleaner way?


Solution

  • How do you store the date? If you just store month and year as integers or strings, then you can just make 2 choice widgets. But if you store it as datetime (timestamp), then you need a valid date anyway. This means that you need to automatically assign values to 'day' (usually first or last day of the month).

    class YourForm extends BaseYourForm
    {
      public function configure()
      {
        $this->widgetSchema['date'] = new sfWidgetFormDate(array(
          'format' => '%month%/%year%'
        ));
        $this->validatorSchema['date'] = new myValidatorDate(array(
          'day_default' => 1
        ));
      }
    } 
    
    class myValidatorDate extends sfValidatorDate
    {
      protected function configure($options = array(), $messages = array())
      {
        $this->addOption('day_default', 1);
        parent::configure($options, $messages);
      }
    
      protected function doClean($value)
      {
        if (!isset($value['day']))
        {
          $value['day'] = $this->getOption('day_default');
        }
        return parent::doClean($value);
      }
    }