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