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