1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143: 144: 145: 146: 147: 148: 149: 150: 151: 152: 153: 154: 155: 156: 157: 158: 159: 160: 161: 162: 163: 164: 165: 166: 167: 168: 169: 170: 171: 172: 173: 174: 175: 176: 177: 178: 179: 180: 181: 182: 183: 184: 185: 186: 187: 188: 189: 190: 191: 192: 193: 194: 195: 196: 197: 198: 199: 200: 201: 202: 203: 204: 205: 206: 207: 208: 209: 210: 211: 212: 213: 214:
<?php
namespace MvcCore\Ext\Forms\Validators;
class Date
extends \MvcCore\Ext\Forms\Validator
implements \MvcCore\Ext\Forms\Fields\IMinMaxStepDates {
use \MvcCore\Ext\Forms\Field\Props\Format;
use \MvcCore\Ext\Forms\Field\Props\MinMaxStepDates;
const ERROR_DATE_INVALID = 0;
const ERROR_DATE_TO_LOW = 1;
const ERROR_DATE_TO_HIGH = 2;
const ERROR_DATE_STEP = 3;
protected static $errorMessages = [
self::ERROR_DATE_INVALID => "Field '{0}' requires a valid date format: '{1}'.",
self::ERROR_DATE_TO_LOW => "Field '{0}' requires date higher or equal to '{1}'.",
self::ERROR_DATE_TO_HIGH => "Field '{0}' requires date lower or equal to '{1}'.",
self::ERROR_DATE_STEP => "Field '{0}' requires date in predefined days interval '{1}' from start point '{2}'.",
];
protected static $fieldSpecificProperties = [
'min' => NULL,
'max' => NULL,
'step' => NULL,
'format' => NULL,
];
protected $format = NULL;
protected static $errorMessagesFormatReplacements = [
'd' => 'DD',
'j' => 'D',
'D' => 'Mon-Sun',
'l' => 'Monday-Sunday',
'm' => 'MM',
'n' => 'M',
'M' => 'Jan-Dec',
'F' => 'January-December',
'Y' => 'YYYY',
'y' => 'YY',
'a' => 'am/pm',
'A' => 'AM/PM',
'g' => '1-12',
'h' => '01-12',
'G' => '01-12',
'H' => '00-23',
'i' => '00-59',
's' => '00-59',
'u' => '0-999999',
];
public function SetField (\MvcCore\Ext\Forms\IField $field) {
parent::SetField($field);
if ($this->format === NULL) {
$this->throwNewInvalidArgumentException(
'No `format` property defined in current validator or in field.'
);
}
return $this;
}
public function Validate ($rawSubmittedValue) {
$rawSubmittedValue = trim((string) $rawSubmittedValue);
$safeValue = preg_replace('#[^a-zA-Z0-9\:\.\-\,/ ]#', '', $rawSubmittedValue);
$safeValueLength = mb_strlen($safeValue);
if ($safeValueLength === 0) return NULL;
$date = @date_create_from_format($this->format, $safeValue);
if ($date === FALSE || $safeValueLength !== mb_strlen($rawSubmittedValue)) {
$this->field->AddValidationError(
static::GetErrorMessage(static::ERROR_DATE_INVALID),
[strtr($this->format, static::$errorMessagesFormatReplacements)]
);
$date = NULL;
} else {
$date = $this->checkMinMax($date);
$date = $this->checkStep($date);
}
return $date;
}
protected function checkMinMax (\DateTimeInterface $date) {
if ($this->min !== NULL && $date < $this->min) {
$this->field->AddValidationError(
static::GetErrorMessage(static::ERROR_DATE_TO_LOW),
[$this->min->format($this->format)]
);
}
if ($this->max !== NULL && $date > $this->max) {
$this->field->AddValidationError(
static::GetErrorMessage(static::ERROR_DATE_TO_HIGH),
[$this->max->format($this->format)]
);
}
return $date;
}
protected function checkStep (\DateTimeInterface $date) {
if ($this->step !== NULL) {
$fieldValue = $this->field->GetValue();
if ($fieldValue instanceof \DateTimeInterface) {
$fieldType = $this->field->GetType();
$stepMatched = FALSE;
static $dateIntervalSpecs = [
'month' => 'M',
'week' => 'W',
'time' => 'S',
'date' => 'D',
'datetime' => 'D',
'datetime-local' => 'D',
];
$interval = new \DateInterval('P' . $this->step . $dateIntervalSpecs[$fieldType]);
$formatedDate = $date->format($this->format);
$datePeriod = new \DatePeriod($fieldValue, $interval, PHP_INT_MAX);
$previousValue = $fieldValue;
$dateToCheckFrom = $fieldValue;
foreach ($datePeriod as $datePoint) {
if ($datePoint > $date) {
$dateToCheckFrom = $previousValue;
break;
} else {
$previousValue = $datePoint;
}
}
$datePeriod = new \DatePeriod($dateToCheckFrom, $interval, PHP_INT_MAX);
$counter = 0;
foreach ($datePeriod as $datePoint) {
if ($counter > 3) break;
$formatedDatePoint = $datePoint->format($this->format);
if ($formatedDate === $formatedDatePoint) {
$stepMatched = TRUE;
break;
} else {
$counter++;
}
}
if (!$stepMatched) {
$this->field->AddValidationError(
static::GetErrorMessage(static::ERROR_DATE_STEP),
[$this->step, $fieldValue->format($this->format)]
);
$date = $fieldValue;
}
}
}
return $date;
}
}