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