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