1: <?php
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: namespace Vodacek\Forms\Controls;
30:
31: use Nette\Forms\IControl,
32: Nette\Forms\Controls\BaseControl;
33:
34: 35: 36: 37: 38:
39: class DateInput extends BaseControl {
40:
41: const TYPE_DATETIME = 'datetime',
42: TYPE_DATETIME_LOCAL = 'datetime-local',
43: TYPE_DATE = 'date',
44: TYPE_MONTH = 'month',
45: TYPE_TIME = 'time',
46: TYPE_WEEK = 'week';
47:
48:
49: protected $type;
50:
51:
52: protected $range = array('min' => null, 'max' => null);
53:
54:
55: protected $submitedValue = null;
56:
57: private static $formats = array(
58: self::TYPE_DATETIME => 'Y-m-d\TH:i:se',
59: self::TYPE_DATETIME_LOCAL => 'Y-m-d\TH:i:s',
60: self::TYPE_DATE => 'Y-m-d',
61: self::TYPE_MONTH => 'Y-m',
62: self::TYPE_TIME => 'H:i:s',
63: self::TYPE_WEEK => 'o-\WW'
64: );
65:
66: public static function register() {
67: $class = __CLASS__;
68: \Nette\Forms\Container::extensionMethod('addDate', function (\Nette\Forms\Container $form, $name, $label = null, $type = 'datetime-local') use ($class) {
69: $component = new $class($label, $type);
70: $form->addComponent($component, $name);
71: return $component;
72: });
73: \Nette\Forms\Rules::$defaultMessages[__CLASS__.'::validateDateInputRange'] = \Nette\Forms\Rules::$defaultMessages[\Nette\Forms\Form::RANGE];
74: \Nette\Forms\Rules::$defaultMessages[__CLASS__.'::validateDateInputValid'] = 'Please enter a valid date.';
75: }
76:
77: 78: 79: 80: 81:
82: public function __construct($label = null, $type = self::TYPE_DATETIME_LOCAL) {
83: if (!isset(self::$formats[$type])) {
84: throw new \InvalidArgumentException("invalid type '$type' given.");
85: }
86: parent::__construct($label);
87: $this->control->type = $this->type = $type;
88: $this->control->data('dateinput-type', $type);
89: }
90:
91: public function setValue($value = null) {
92: if ($value === null || $value instanceof \DateTime) {
93: $this->value = $value;
94: $this->submitedValue = null;
95: } elseif (is_string($value)) {
96: if ($value === '') {
97: $this->value = null;
98: $this->submitedValue = null;
99: } else {
100: $this->value = $this->parseValue($value);
101: if ($this->value !== false) {
102: $this->submitedValue = null;
103: } else {
104: $this->value = null;
105: $this->submitedValue = $value;
106: }
107: }
108: } else {
109: $this->submitedValue = $value;
110: throw new \InvalidArgumentException("Invalid type for \$value.");
111: }
112: return $this;
113: }
114:
115: public function getControl() {
116: $control = parent::getControl();
117: $format = self::$formats[$this->type];
118: if ($this->value !== null) {
119: $control->value = $this->value->format($format);
120: }
121: if ($this->submitedValue !== null && is_string($this->submitedValue)) {
122: $control->value = $this->submitedValue;
123: }
124: if ($this->range['min'] !== null) {
125: $control->min = $this->range['min']->format($format);
126: }
127: if ($this->range['max'] !== null) {
128: $control->max = $this->range['max']->format($format);
129: }
130: return $control;
131: }
132:
133: public function addRule($operation, $message = null, $arg = null) {
134: if ($operation === \Nette\Forms\Form::RANGE) {
135: $this->range['min'] = $this->normalizeDate($arg[0]);
136: $this->range['max'] = $this->normalizeDate($arg[1]);
137: $operation = __CLASS__.'::validateDateInputRange';
138: $arg[0] = $this->formatDate($arg[0]);
139: $arg[1] = $this->formatDate($arg[1]);
140: } elseif ($operation === \Nette\Forms\Form::VALID) {
141: $operation = __CLASS__.'::validateDateInputValid';
142: }
143: return parent::addRule($operation, $message, $arg);
144: }
145:
146: public static function validateFilled(IControl $control) {
147: if (!$control instanceof self) {
148: throw new \InvalidArgumentException("Cant't validate control '".\get_class($control)."'.");
149: }
150: return ($control->value !== null || $control->submitedValue !== null);
151: }
152:
153: 154: 155: 156: 157:
158: public static function validateDateInputValid(IControl $control) {
159: return self::validateValid($control);
160: }
161:
162: public static function validateValid(IControl $control) {
163: if (!$control instanceof self) {
164: throw new \InvalidArgumentException("Cant't validate control '".\get_class($control)."'.");
165: }
166: return $control->submitedValue === null;
167: }
168:
169: 170: 171: 172: 173:
174: public static function validateDateInputRange(self $control) {
175: if ($control->range['min'] !== null) {
176: if ($control->range['min'] > $control->value) {
177: return false;
178: }
179: }
180: if ($control->range['max'] !== null) {
181: if ($control->range['max'] < $control->value) {
182: return false;
183: }
184: }
185: return true;
186: }
187:
188: 189: 190: 191:
192: private function parseValue($value) {
193: $date = null;
194: if ($this->type === self::TYPE_WEEK) {
195: try {
196: $date = new \DateTime($value."1");
197: } catch (\Exception $e) {
198: $date = false;
199: }
200: } else {
201: $date = \DateTime::createFromFormat('!'.self::$formats[$this->type], $value);
202: }
203: return $date;
204: }
205:
206: 207: 208: 209:
210: private function formatDate(\DateTime $value = null) {
211: if ($value) {
212: $value = $value->format(self::$formats[$this->type]);
213: }
214: return $value;
215: }
216:
217: 218: 219: 220:
221: private function normalizeDate(\DateTime $value = null) {
222: if ($value) {
223: $value = $this->formatDate($value);
224: $value = $this->parseValue($value);
225: }
226: return $value;
227: }
228: }
229: