Code snippets for symfony 1.x

Navigation

Refine Tags

Snippets tagged "validator date"

Validator and widget for fuzzy dates

If I understand correctly, ISO-8601 allows for dates represented as YYYY, YYYY-MM, and YYYY-MM-DD, among others. I did not see the possibility of supporting these date formats with the built-in widgets and validators, so I wrote some.

class ynWidgetFormDateFuzzy extends sfWidgetFormDate
{
  public function render($name, $value = null, $attributes = array(), $errors = array())
  {
    // convert value to an array
    $default = array('year' => null, 'month' => null, 'day' => null);
    if (is_array($value))
    {
      $value = array_merge($default, $value);
    }
    else if ( preg_match( '/^(\d+)$/', $value, $matches ) )
    {
      $value = array(
        'year'  => $matches[1],
        'month' => '',
        'day'   => '',
      );
    }
    else if ( preg_match( '/^(\d+)-(\d+)$/', $value, $matches ) )
    {
      $value = array(
        'year'  => $matches[1],
        'month' => $matches[2],
        'day'   => '',
      );
    }
    else
    {
      $value = (string) $value == (string) (integer) $value ? (integer) $value : strtotime($value);
      if (false === $value)
      {
        $value = $default;
      }
      else
      {
        $value = array('year' => date('Y', $value), 'month' => date('n', $value), 'day' => date('j', $value));
      }
    }
 
    $date = array();
    $emptyValues = $this->getOption('empty_values');
 
    $date['%day%'] = $this->renderDayWidget(
      $name.'[day]',
      $value['day'] ? (int) $value['day'] : '',
      array(
        'choices' => array('' => $emptyValues['day']) + $this->getOption('days'),
        'id_format' => $this->getOption('id_format')
      ),
      array_merge($this->attributes, $attributes)
    );
 
    $date['%month%'] = $this->renderMonthWidget(
      $name.'[month]',
      $value['month'] ? (int) $value['month'] : '',
      array(
        'choices' => array('' => $emptyValues['month']) + $this->getOption('months'),
        'id_format' => $this->getOption('id_format')
      ),
      array_merge($this->attributes, $attributes)
    );
 
    $date['%year%'] = $this->renderYearWidget($name.'[year]', $value['year'], array('choices' => $this->getOption('can_be_empty') ? array('' => $emptyValues['year']) + $this->getOption('years') : $this->getOption('years'), 'id_format' => $this->getOption('id_format')), array_merge($this->attributes, $attributes));
 
    return strtr($this->getOption('format'), $date);
  }
}
 
 
class ynValidatorDateFuzzy extends sfValidatorBase
{
  protected function configure($options = array(), $messages = array())
  {
    $this->addMessage('max', 'The date must be before %max%.');
    $this->addMessage('min', 'The date must be after %min%.');
 
    $this->addOption('min', null);
    $this->addOption('max', null);
  }
 
  protected function doClean($value)
  {
    if ( ! is_array( $value ) ) {
      throw new sfValidatorError($this, 'bad_format');
    }
 
    // convert array to date string
    if (is_array($value))
    {
      $value = $this->convertDateArrayToString($value);
    }
 
    if ($max = $this->getOption('max')) {
      $date_max = new DateTime( $max );
 
      if ( $this->lowestPossible( $value )->format('Ymd') > $date_max->format('Ymd') ) {
        throw new sfValidatorError($this, 'max', array('value' => $value, 'max' => 'out of range'));
      }
    }
 
    if ($min = $this->getOption('min')) {
      $date_min = new DateTime( $min );
 
      if ( $this->highestPossible( $value )->format('Ymd') < $date_min->format('Ymd') ) {
        throw new sfValidatorError($this, 'max', array('value' => $value, 'min' => 'out of range'));
      }
    }
 
    return $value;
  }
 
  protected function convertDateArrayToString($value)
  {
    // all elements must be empty or a number
    foreach (array('year', 'month', 'day', 'hour', 'minute', 'second') as $key)
    {
      if (isset($value[$key]) && !preg_match('#^\d+$#', $value[$key]) && !empty($value[$key]))
      {
        throw new sfValidatorError($this, 'invalid', array('value' => $value));
      }
    }
 
    // check empty value correspondence
 
    if (
      ! $value['year'] && ! $value['month'] && ! $value['day']
    ) {
      return $this->getEmptyValue();
    }
    else if (
      ! $value['year']
      && ($value['month'] || $value['day'])
    ) {
      throw new sfValidatorError($this, 'invalid', array('value' => $value));
    }
    else if (
      $value['year'] && ! $value['month'] && $value['day']
    ) {
      throw new sfValidatorError($this, 'invalid', array('value' => $value));
    }
 
    if ( $value['month'] && ! in_array( (int) $value['month'], range(1,12) ) ) {
      throw new sfValidatorError($this, 'invalid', array('value' => $value));
    }
 
    if ( $value['day'] && ! in_array( (int) $value['day'], range(1,31) ) ) {
      throw new sfValidatorError($this, 'invalid', array('value' => $value));
    }
 
    $clean = '';
 
    if ( $value['year'] ) {
      $clean .= sprintf( '%04d', intval( $value['year'] ) );
    }
 
    if ( $value['month'] ) {
      $clean .= sprintf( '-%02d', intval( $value['month'] ) );
    }
 
    if ( $value['day'] ) {
      $clean .= sprintf( '-%02d', intval( $value['day'] ) );
    }
 
    return $clean;
  }
 
  protected function highestPossible( $date )
  {
    if ( preg_match( '/^\d+$/', $date, $matches ) ) {
      return new DateTime( $date . '-12-31' );
    }
    else if ( preg_match( '/^\d+-(\d+)$/', $date, $matches ) ) {
      switch ( $matches[1] ) {
        case '2':
          return new DateTime( $date . '-28' );
        case '1':
        case '3':
        case '5':
        case '7':
        case '8':
        case '10':
        case '12':
          return new DateTime( $date . '-31' );
        default:
          return new DateTime( $date . '-30' );
      }
    }
    else {
      return new DateTime( $date );
    }
  }
 
  protected function lowestPossible( $date )
  {
    if ( preg_match( '/^\d+$/', $date, $matches ) ) {
      return new DateTime( $date . '-01-01' );
    }
    else if ( preg_match( '/^\d+-(\d+)$/', $date, $matches ) ) {
      return new DateTime( $date . '-01' );
    }
    else {
      return new DateTime( $date );
    }
  }
}
 
by yitznewton on 2011-02-16, tagged date  validator  widget