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\Forms\Form;
14: use Nette\Forms\Rule;
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:
252: $rules = self::exportRules($this->rules);
253: $el = clone $this->control;
254: return $el->addAttributes(array(
255: 'name' => $this->getHtmlName(),
256: 'id' => $this->getHtmlId(),
257: 'required' => $this->isRequired(),
258: 'disabled' => $this->isDisabled(),
259: 'data-nette-rules' => $rules ? Nette\Utils\Json::encode($rules) : NULL,
260: ));
261: }
262:
263:
264: 265: 266: 267: 268:
269: public function getLabel($caption = NULL)
270: {
271: $label = clone $this->label;
272: $label->for = $this->getHtmlId();
273: $label->setText($this->translate($caption === NULL ? $this->caption : $caption));
274: return $label;
275: }
276:
277:
278: 279: 280: 281:
282: public function getControlPrototype()
283: {
284: return $this->control;
285: }
286:
287:
288: 289: 290: 291:
292: public function getLabelPrototype()
293: {
294: return $this->label;
295: }
296:
297:
298: 299: 300: 301: 302:
303: public function setHtmlId($id)
304: {
305: $this->control->id = $id;
306: return $this;
307: }
308:
309:
310: 311: 312: 313:
314: public function getHtmlId()
315: {
316: if (!isset($this->control->id)) {
317: $this->control->id = sprintf(self::$idMask, $this->lookupPath(NULL));
318: }
319: return $this->control->id;
320: }
321:
322:
323: 324: 325: 326: 327: 328:
329: public function setAttribute($name, $value = TRUE)
330: {
331: $this->control->$name = $value;
332: return $this;
333: }
334:
335:
336:
337:
338:
339: 340: 341: 342:
343: public function setTranslator(Nette\Localization\ITranslator $translator = NULL)
344: {
345: $this->translator = $translator;
346: return $this;
347: }
348:
349:
350: 351: 352: 353:
354: public function getTranslator()
355: {
356: if ($this->translator === TRUE) {
357: return $this->getForm(FALSE) ? $this->getForm()->getTranslator() : NULL;
358: }
359: return $this->translator;
360: }
361:
362:
363: 364: 365: 366: 367: 368:
369: public function translate($value, $count = NULL)
370: {
371: if ($translator = $this->getTranslator()) {
372: $tmp = is_array($value) ? array(& $value) : array(array(& $value));
373: foreach ($tmp[0] as & $v) {
374: if ($v != NULL && !$v instanceof Html) {
375: $v = $translator->translate($v, $count);
376: }
377: }
378: }
379: return $value;
380: }
381:
382:
383:
384:
385:
386: 387: 388: 389: 390: 391: 392:
393: public function addRule($operation, $message = NULL, $arg = NULL)
394: {
395: $this->rules->addRule($operation, $message, $arg);
396: return $this;
397: }
398:
399:
400: 401: 402: 403: 404: 405:
406: public function addCondition($operation, $value = NULL)
407: {
408: return $this->rules->addCondition($operation, $value);
409: }
410:
411:
412: 413: 414: 415: 416: 417: 418:
419: public function addConditionOn(IControl $control, $operation, $value = NULL)
420: {
421: return $this->rules->addConditionOn($control, $operation, $value);
422: }
423:
424:
425: 426: 427:
428: public function getRules()
429: {
430: return $this->rules;
431: }
432:
433:
434: 435: 436: 437: 438:
439: public function setRequired($value = TRUE)
440: {
441: $this->rules->setRequired($value);
442: return $this;
443: }
444:
445:
446: 447: 448: 449:
450: public function isRequired()
451: {
452: return $this->rules->isRequired();
453: }
454:
455:
456: 457: 458: 459:
460: public function validate()
461: {
462: if ($this->isDisabled()) {
463: return;
464: }
465: $this->cleanErrors();
466: $this->rules->validate();
467: }
468:
469:
470: 471: 472: 473: 474:
475: public function addError($message)
476: {
477: $this->errors[] = $message;
478: }
479:
480:
481: 482: 483: 484:
485: public function getError()
486: {
487: return $this->errors ? implode(' ', array_unique($this->errors)) : NULL;
488: }
489:
490:
491: 492: 493: 494:
495: public function getErrors()
496: {
497: return array_unique($this->errors);
498: }
499:
500:
501: 502: 503:
504: public function hasErrors()
505: {
506: return (bool) $this->errors;
507: }
508:
509:
510: 511: 512:
513: public function cleanErrors()
514: {
515: $this->errors = array();
516: }
517:
518:
519: 520: 521:
522: protected static function exportRules($rules)
523: {
524: $payload = array();
525: foreach ($rules as $rule) {
526: if (!is_string($op = $rule->operation)) {
527: if (!Nette\Utils\Callback::isStatic($op)) {
528: continue;
529: }
530: $op = Nette\Utils\Callback::toString($op);
531: }
532: if ($rule->type === Rule::VALIDATOR) {
533: $item = array('op' => ($rule->isNegative ? '~' : '') . $op, 'msg' => $rules->formatMessage($rule, FALSE));
534:
535: } elseif ($rule->type === Rule::CONDITION) {
536: $item = array(
537: 'op' => ($rule->isNegative ? '~' : '') . $op,
538: 'rules' => static::exportRules($rule->subRules),
539: 'control' => $rule->control->getHtmlName()
540: );
541: if ($rule->subRules->getToggles()) {
542: $item['toggle'] = $rule->subRules->getToggles();
543: }
544: }
545:
546: if (is_array($rule->arg)) {
547: foreach ($rule->arg as $key => $value) {
548: $item['arg'][$key] = $value instanceof IControl ? array('control' => $value->getHtmlName()) : $value;
549: }
550: } elseif ($rule->arg !== NULL) {
551: $item['arg'] = $rule->arg instanceof IControl ? array('control' => $rule->arg->getHtmlName()) : $rule->arg;
552: }
553:
554: $payload[] = $item;
555: }
556: return $payload;
557: }
558:
559:
560:
561:
562:
563: 564: 565: 566: 567:
568: public static function validateEqual(IControl $control, $arg)
569: {
570: $value = $control->getValue();
571: foreach ((is_array($value) ? $value : array($value)) as $val) {
572: foreach ((is_array($arg) ? $arg : array($arg)) as $item) {
573: if ((string) $val === (string) $item) {
574: continue 2;
575: }
576: }
577: return FALSE;
578: }
579: return TRUE;
580: }
581:
582:
583: 584: 585: 586: 587:
588: public static function validateNotEqual(IControl $control, $arg)
589: {
590: return !static::validateEqual($control, $arg);
591: }
592:
593:
594: 595: 596: 597: 598:
599: public static function validateFilled(IControl $control)
600: {
601: return $control->isFilled();
602: }
603:
604:
605: 606: 607: 608: 609:
610: public static function validateBlank(IControl $control)
611: {
612: return !$control->isFilled();
613: }
614:
615:
616: 617: 618: 619: 620:
621: public static function validateValid(IControl $control)
622: {
623: return $control->rules->validate();
624: }
625:
626:
627: 628: 629: 630: 631: 632: 633:
634: public static function validateRange(IControl $control, $range)
635: {
636: return Nette\Utils\Validators::isInRange($control->getValue(), $range);
637: }
638:
639:
640: 641: 642: 643: 644:
645: public static function validateLength(IControl $control, $range)
646: {
647: if (!is_array($range)) {
648: $range = array($range, $range);
649: }
650: $value = $control->getValue();
651: return Nette\Utils\Validators::isInRange(is_array($value) ? count($value) : Nette\Utils\Strings::length($value), $range);
652: }
653:
654:
655: 656: 657: 658: 659:
660: public static function validateMinLength(IControl $control, $length)
661: {
662: return static::validateLength($control, array($length, NULL));
663: }
664:
665:
666: 667: 668: 669: 670:
671: public static function validateMaxLength(IControl $control, $length)
672: {
673: return static::validateLength($control, array(NULL, $length));
674: }
675:
676:
677:
678:
679:
680: 681: 682: 683:
684: public function setOption($key, $value)
685: {
686: if ($value === NULL) {
687: unset($this->options[$key]);
688: } else {
689: $this->options[$key] = $value;
690: }
691: return $this;
692: }
693:
694:
695: 696: 697: 698:
699: public function getOption($key, $default = NULL)
700: {
701: return isset($this->options[$key]) ? $this->options[$key] : $default;
702: }
703:
704:
705: 706: 707: 708:
709: public function getOptions()
710: {
711: return $this->options;
712: }
713:
714: }
715: