среда, 9 декабря 2009 г.

Виджет для jquery.datepicker

Делаем виджет для ввода даты с помощью jQuery.datepicker



1. Делаем новый виджет. Создаем файл lib/widget/sfWidgetFormInputDate.class.php

addOption('date_format', 'd.m.Y');
  }
  
  public function render($name, $value = null, $attributes = array(), $errors = array())
  {
    $datepicker=sprintf(<<<EOF

EOF
    ,
    $this->generateId($name)
    );
      
    
    $value=strlen($value) ? date($this->getOption('date_format',strtotime($value))) : '';
    
    return $datepicker.parent::render($name, $value, $attributes, $errors);
  }
}

2. Создаем новый валидатор lib/validator/sfValidatorI18n.class.php

addOption('input_date_format', 'Y-m-d');
   $this->addOption('output_date_format', 'Y-m-d');

   parent::configure($options, $messages);
  }

  /**
   * Override sfValidatorDate doClean. Quite strange : I had to copy/paste the original
   * code after my 'convertDateToFormat' method : a simple parent::doClean($value) would
   * not work !
   * @see trunk/lib/vendor/symfony/lib/validator/sfValidatorDate#doClean($value)
   */
 protected function doClean($value)
  {

   $value = $this->convertDateToFormat($value);

// I had to copy/paste the rest of doClean, otherwise it wouldn't work ! I don't know why...
   if (is_array($value))
    {
      $clean = $this->convertDateArrayToTimestamp($value);
    }
    else if ($regex = $this->getOption('date_format'))
    {
      if (!preg_match($regex, $value, $match))
      {
        throw new sfValidatorError($this, 'bad_format', array('value' => $value, 'date_format' => $this->getOption('date_format_error') ? $this->getOption('date_format_error') : $this->getOption('date_format')));
      }

      $clean = $this->convertDateArrayToTimestamp($match);
    }
    else if (!ctype_digit($value))
    {
      $clean = strtotime($value);
      if (false === $clean)
      {
        throw new sfValidatorError($this, 'invalid', array('value' => $value));
      }
    }
    else
    {
      $clean = (integer) $value;
    }

    if ($this->hasOption('max') && $clean > $this->getOption('max'))
    {
      throw new sfValidatorError($this, 'max', array('value' => $value, 'max' => date($this->getOption('date_format_range_error'), $this->getOption('max'))));
    }

    if ($this->hasOption('min') && $clean < $this->getOption('min'))
    {
      throw new sfValidatorError($this, 'min', array('value' => $value, 'min' => date($this->getOption('date_format_range_error'), $this->getOption('min'))));
    }

    return $clean === $this->getEmptyValue() ? $clean : date($this->getOption('with_time') ? $this->getOption('datetime_output') : $this->getOption('date_output'), $clean);
  }

  /**
   * converts the given date
   * $value must match the option 'input_date_format'. It will be convert to 'output_date_format'
   * For example : $value = 19/08/2009, input_date_format = DD/MM/YYYY, output_date_format = YYYY-MM-DD
   * Output will be 2009-08-19
   * @param $value
   * @return unknown_type
   * @author  Simon Hostelet
   */
  protected function convertDateToFormat($value)
  {

   // we check if input/output_date_format are well written,
   // we get the date separator, and the order of year, month and day in the mask
    $input_details = $this->getDateAlrightSeparatorAndOrder($this->getOption('input_date_format'));
    foreach($input_details as $key => $val)
    {
     $key = 'input_' . $key;
     $$key = $val;
    }
    $output_details = $this->getDateAlrightSeparatorAndOrder($this->getOption('output_date_format'));

    $input_date = explode($input_date_separator, $value);

    // is this date valid ?
    if(count($input_date)!=3 or !checkdate(intval($input_date[$input_month_order]), intval($input_date[$input_day_order]), intval($input_date[$input_year_order])))
    {
     throw new sfValidatorError($this, 'invalid', array('value' => $value));
    }

    // let's build the output date
    $output_date = $this->getOption('output_date_format');
    $output_date = preg_replace('/Y|y/', $input_date[$input_year_order], $output_date);
    $output_date = preg_replace('/m/', $input_date[$input_month_order], $output_date);
    $output_date = preg_replace('/d/', $input_date[$input_day_order], $output_date);

    return $output_date;
  }

  /**
   * get a date format (like d/m/Y), check the format, and returns date separator (-/_, .)
   * and date order
   * @param $format
   * @return array
   * @author  Simon Hostelet
   */
  protected function getDateAlrightSeparatorAndOrder($format)
  {
    // does the date_format looks right ?
    if(!preg_match('/(d|m|y|Y)([-\/_,\. ]{1})(d|m|y|Y)([-\/_,\. ]{1})(d|m|y|Y)/', $format, $matches))
    {
      throw new sfValidatorError($this, 'invalid', array('value' => $value));
    }

   // what is the date separator ?
    preg_match('/[dmyY]{1}([\/\-,\._ ]{1})[dmyY]{1}/', $format, $matches);
    $return_array['date_separator'] = $matches[1];

    // what is the order of day, month and year in the format mask ?
    $date_order = explode($return_array['date_separator'], $format);
    foreach($date_order as $key => $val)
    {
      switch($val)
      {
        case 'd':
          $return_array['day_order'] = $key;
          break;
        case 'm':
          $return_array['month_order'] = $key;
          break;
        default:
          $return_array['year_order'] = $key;
      }
    }

    return $return_array;
  }
}


3. Используем в классе формы

$this->widgetSchema['birthday']=new sfWidgetFormInputDate();
$this->validatorSchema['birthday']=new sfValidatorDateI18n(array(
  'date_output'=>'Y-m-d',
  'input_date_format'=>'d.m.Y',
  'output_date_format'=>'Y-m-d',
  'required'=>false,
  'with_time'=>false,
),
array(
  'bad_format'=>'Используйте дату в формате ДД.ММ.ГГГГ',
));

Может быть, я когда-нибудь соберусь оформить это в плагин :)

Комментариев нет:

Отправить комментарий