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