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: 30: 31: 32: 33: 34: 35: 36: 37:
38: abstract class FormControl extends Component implements IFormControl
39: {
40:
41: public static $idMask = 'frm%s-%s';
42:
43:
44: public $caption;
45:
46:
47: protected $value;
48:
49:
50: protected $control;
51:
52:
53: protected $label;
54:
55:
56: private $errors = array();
57:
58:
59: private $disabled = FALSE;
60:
61:
62: private $htmlId;
63:
64:
65: private $htmlName;
66:
67:
68: private $rules;
69:
70:
71: private $translator = TRUE;
72:
73:
74: private $options = array();
75:
76:
77: 78: 79:
80: public function __construct($caption = NULL)
81: {
82: $this->monitor('Form');
83: parent::__construct();
84: $this->control = Html::el('input');
85: $this->label = Html::el('label');
86: $this->caption = $caption;
87: $this->rules = new Rules($this);
88: }
89:
90:
91: 92: 93: 94: 95:
96: protected function attached($form)
97: {
98: if (!$this->disabled && $form instanceof Form && $form->isAnchored() && $form->isSubmitted()) {
99: $this->htmlName = NULL;
100: $this->loadHttpData();
101: }
102: }
103:
104:
105: 106: 107: 108: 109:
110: public function getForm($need = TRUE)
111: {
112: return $this->lookup('Form', $need);
113: }
114:
115:
116: 117: 118: 119:
120: public function getHtmlName()
121: {
122: if ($this->htmlName === NULL) {
123: $name = str_replace(self::NAME_SEPARATOR, '][', $this->lookupPath('Form'), $count);
124: if ($count) {
125: $name = substr_replace($name, '', strpos($name, ']'), 1) . ']';
126: }
127: if (is_numeric($name) || in_array($name, array('attributes','children','elements','focus','length','reset','style','submit','onsubmit'))) {
128: $name .= '_';
129: }
130: $this->htmlName = $name;
131: }
132: return $this->htmlName;
133: }
134:
135:
136: 137: 138: 139: 140:
141: public function setHtmlId($id)
142: {
143: $this->htmlId = $id;
144: return $this;
145: }
146:
147:
148: 149: 150: 151:
152: public function getHtmlId()
153: {
154: if ($this->htmlId === FALSE) {
155: return NULL;
156:
157: } elseif ($this->htmlId === NULL) {
158: $this->htmlId = sprintf(self::$idMask, $this->getForm()->getName(), $this->lookupPath('Form'));
159: }
160: return $this->htmlId;
161: }
162:
163:
164: 165: 166: 167: 168: 169:
170: public function setAttribute($name, $value = TRUE)
171: {
172: $this->control->$name = $value;
173: return $this;
174: }
175:
176:
177: 178: 179: 180: 181: 182: 183: 184: 185:
186: public function setOption($key, $value)
187: {
188: if ($value === NULL) {
189: unset($this->options[$key]);
190:
191: } else {
192: $this->options[$key] = $value;
193: }
194: return $this;
195: }
196:
197:
198: 199: 200: 201: 202: 203:
204: final public function getOption($key, $default = NULL)
205: {
206: return isset($this->options[$key]) ? $this->options[$key] : $default;
207: }
208:
209:
210: 211: 212: 213:
214: final public function getOptions()
215: {
216: return $this->options;
217: }
218:
219:
220:
221:
222:
223: 224: 225: 226:
227: public function setTranslator(ITranslator $translator = NULL)
228: {
229: $this->translator = $translator;
230: return $this;
231: }
232:
233:
234: 235: 236: 237:
238: final public function getTranslator()
239: {
240: if ($this->translator === TRUE) {
241: return $this->getForm(FALSE) ? $this->getForm()->getTranslator() : NULL;
242: }
243: return $this->translator;
244: }
245:
246:
247: 248: 249: 250: 251: 252:
253: public function translate($s, $count = NULL)
254: {
255: $translator = $this->getTranslator();
256: return $translator === NULL || $s == NULL ? $s : $translator->translate($s, $count);
257: }
258:
259:
260:
261:
262:
263: 264: 265: 266:
267: public function setValue($value)
268: {
269: $this->value = $value;
270: return $this;
271: }
272:
273:
274: 275: 276: 277:
278: public function getValue()
279: {
280: return $this->value;
281: }
282:
283:
284: 285: 286: 287:
288: public function isFilled()
289: {
290: return (string) $this->getValue() !== '';
291: }
292:
293:
294: 295: 296: 297:
298: public function setDefaultValue($value)
299: {
300: $form = $this->getForm(FALSE);
301: if (!$form || !$form->isAnchored() || !$form->isSubmitted()) {
302: $this->setValue($value);
303: }
304: return $this;
305: }
306:
307:
308: 309: 310: 311:
312: public function loadHttpData()
313: {
314: $path = explode('[', strtr(str_replace(array('[]', ']'), '', $this->getHtmlName()), '.', '_'));
315: $this->setValue(Arrays::get($this->getForm()->getHttpData(), $path, NULL));
316: }
317:
318:
319: 320: 321: 322: 323:
324: public function setDisabled($value = TRUE)
325: {
326: $this->disabled = (bool) $value;
327: return $this;
328: }
329:
330:
331: 332: 333: 334:
335: public function isDisabled()
336: {
337: return $this->disabled;
338: }
339:
340:
341:
342:
343:
344: 345: 346: 347:
348: public function getControl()
349: {
350: $this->setOption('rendered', TRUE);
351:
352: $control = clone $this->control;
353: $control->name = $this->getHtmlName();
354: $control->disabled = $this->disabled;
355: $control->id = $this->getHtmlId();
356: $control->required = $this->isRequired();
357:
358: $rules = self::exportRules($this->rules);
359: $rules = substr(PHP_VERSION_ID >= 50400 ? json_encode($rules, JSON_UNESCAPED_UNICODE) : json_encode($rules), 1, -1);
360: $rules = preg_replace('#"([a-z0-9_]+)":#i', '$1:', $rules);
361: $rules = preg_replace('#(?<!\\\\)"(?!:[^a-z])([^\\\\\',]*)"#i', "'$1'", $rules);
362: $control->data('nette-rules', $rules ? $rules : NULL);
363:
364: return $control;
365: }
366:
367:
368: 369: 370: 371: 372:
373: public function getLabel($caption = NULL)
374: {
375: $label = clone $this->label;
376: $label->for = $this->getHtmlId();
377: if ($caption !== NULL) {
378: $label->setText($this->translate($caption));
379:
380: } elseif ($this->caption instanceof Html) {
381: $label->add($this->caption);
382:
383: } else {
384: $label->setText($this->translate($this->caption));
385: }
386: return $label;
387: }
388:
389:
390: 391: 392: 393:
394: final public function getControlPrototype()
395: {
396: return $this->control;
397: }
398:
399:
400: 401: 402: 403:
404: final public function getLabelPrototype()
405: {
406: return $this->label;
407: }
408:
409:
410:
411:
412:
413: 414: 415: 416: 417: 418: 419:
420: public function addRule($operation, $message = NULL, $arg = NULL)
421: {
422: $this->rules->addRule($operation, $message, $arg);
423: return $this;
424: }
425:
426:
427: 428: 429: 430: 431: 432:
433: public function addCondition($operation, $value = NULL)
434: {
435: return $this->rules->addCondition($operation, $value);
436: }
437:
438:
439: 440: 441: 442: 443: 444: 445:
446: public function addConditionOn(IFormControl $control, $operation, $value = NULL)
447: {
448: return $this->rules->addConditionOn($control, $operation, $value);
449: }
450:
451:
452: 453: 454:
455: final public function getRules()
456: {
457: return $this->rules;
458: }
459:
460:
461: 462: 463: 464: 465:
466: final public function setRequired($message = NULL)
467: {
468: return $this->addRule(Form::FILLED, $message);
469: }
470:
471:
472: 473: 474: 475:
476: final public function isRequired()
477: {
478: foreach ($this->rules as $rule) {
479: if ($rule->type === Rule::VALIDATOR && !$rule->isNegative && $rule->operation === Form::FILLED) {
480: return TRUE;
481: }
482: }
483: return FALSE;
484: }
485:
486:
487: 488: 489:
490: protected static function exportRules($rules)
491: {
492: $payload = array();
493: foreach ($rules as $rule) {
494: if (!is_string($op = $rule->operation)) {
495: $op = new Callback($op);
496: if (!$op->isStatic()) {
497: continue;
498: }
499: }
500: if ($rule->type === Rule::VALIDATOR) {
501: $item = array('op' => ($rule->isNegative ? '~' : '') . $op, 'msg' => $rules->formatMessage($rule, FALSE));
502:
503: } elseif ($rule->type === Rule::CONDITION) {
504: $item = array(
505: 'op' => ($rule->isNegative ? '~' : '') . $op,
506: 'rules' => self::exportRules($rule->subRules),
507: 'control' => $rule->control->getHtmlName()
508: );
509: if ($rule->subRules->getToggles()) {
510: $item['toggle'] = $rule->subRules->getToggles();
511: }
512: }
513:
514: if (is_array($rule->arg)) {
515: foreach ($rule->arg as $key => $value) {
516: $item['arg'][$key] = $value instanceof IFormControl ? (object) array('control' => $value->getHtmlName()) : $value;
517: }
518: } elseif ($rule->arg !== NULL) {
519: $item['arg'] = $rule->arg instanceof IFormControl ? (object) array('control' => $rule->arg->getHtmlName()) : $rule->arg;
520: }
521:
522: $payload[] = $item;
523: }
524: return $payload;
525: }
526:
527:
528:
529:
530:
531: 532: 533: 534:
535: public static function validateEqual(IFormControl $control, $arg)
536: {
537: $value = $control->getValue();
538: foreach ((is_array($value) ? $value : array($value)) as $val) {
539: foreach ((is_array($arg) ? $arg : array($arg)) as $item) {
540: if ((string) $val === (string) ($item instanceof IFormControl ? $item->value : $item)) {
541: return TRUE;
542: }
543: }
544: }
545: return FALSE;
546: }
547:
548:
549: 550: 551: 552:
553: public static function validateNotEqual(IFormControl $control, $arg)
554: {
555: return !self::validateEqual($control, $arg);
556: }
557:
558:
559: 560: 561: 562:
563: public static function validateFilled(IFormControl $control)
564: {
565: return $control->isFilled();
566: }
567:
568:
569: 570: 571: 572:
573: public static function validateBlank(IFormControl $control)
574: {
575: return !$control->isFilled();
576: }
577:
578:
579: 580: 581: 582:
583: public static function validateValid(IFormControl $control)
584: {
585: return $control->rules->validate(TRUE);
586: }
587:
588:
589: 590: 591: 592: 593:
594: public function addError($message)
595: {
596: if (!in_array($message, $this->errors, TRUE)) {
597: $this->errors[] = $message;
598: }
599: $this->getForm()->addError($message);
600: }
601:
602:
603: 604: 605: 606:
607: public function getErrors()
608: {
609: return $this->errors;
610: }
611:
612:
613: 614: 615:
616: public function hasErrors()
617: {
618: return (bool) $this->errors;
619: }
620:
621:
622: 623: 624:
625: public function cleanErrors()
626: {
627: $this->errors = array();
628: }
629:
630: }
631: