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