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