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 setHtmlAttribute($name, $value = TRUE)
348: {
349: return $this->setAttribute($name, $value);
350: }
351:
352:
353: 354: 355: 356: 357: 358:
359: public function setAttribute($name, $value = TRUE)
360: {
361: $this->control->$name = $value;
362: return $this;
363: }
364:
365:
366:
367:
368:
369: 370: 371: 372:
373: public function setTranslator(Nette\Localization\ITranslator $translator = NULL)
374: {
375: $this->translator = $translator;
376: return $this;
377: }
378:
379:
380: 381: 382: 383:
384: public function getTranslator()
385: {
386: if ($this->translator === TRUE) {
387: return $this->getForm(FALSE) ? $this->getForm()->getTranslator() : NULL;
388: }
389: return $this->translator;
390: }
391:
392:
393: 394: 395: 396: 397: 398:
399: public function translate($value, $count = NULL)
400: {
401: if ($translator = $this->getTranslator()) {
402: $tmp = is_array($value) ? [& $value] : [[& $value]];
403: foreach ($tmp[0] as & $v) {
404: if ($v != NULL && !$v instanceof Html) {
405: $v = $translator->translate($v, $count);
406: }
407: }
408: }
409: return $value;
410: }
411:
412:
413:
414:
415:
416: 417: 418: 419: 420: 421: 422:
423: public function addRule($validator, $message = NULL, $arg = NULL)
424: {
425: $this->rules->addRule($validator, $message, $arg);
426: return $this;
427: }
428:
429:
430: 431: 432: 433: 434: 435:
436: public function addCondition($validator, $value = NULL)
437: {
438: return $this->rules->addCondition($validator, $value);
439: }
440:
441:
442: 443: 444: 445: 446: 447: 448:
449: public function addConditionOn(IControl $control, $validator, $value = NULL)
450: {
451: return $this->rules->addConditionOn($control, $validator, $value);
452: }
453:
454:
455: 456: 457:
458: public function getRules()
459: {
460: return $this->rules;
461: }
462:
463:
464: 465: 466: 467: 468:
469: public function setRequired($value = TRUE)
470: {
471: $this->rules->setRequired($value);
472: return $this;
473: }
474:
475:
476: 477: 478: 479:
480: public function isRequired()
481: {
482: return $this->rules->isRequired();
483: }
484:
485:
486: 487: 488: 489:
490: public function validate()
491: {
492: if ($this->isDisabled()) {
493: return;
494: }
495: $this->cleanErrors();
496: $this->rules->validate();
497: }
498:
499:
500: 501: 502: 503: 504:
505: public function addError($message)
506: {
507: $this->errors[] = $message;
508: }
509:
510:
511: 512: 513: 514:
515: public function getError()
516: {
517: return $this->errors ? implode(' ', array_unique($this->errors)) : NULL;
518: }
519:
520:
521: 522: 523: 524:
525: public function getErrors()
526: {
527: return array_unique($this->errors);
528: }
529:
530:
531: 532: 533:
534: public function hasErrors()
535: {
536: return (bool) $this->errors;
537: }
538:
539:
540: 541: 542:
543: public function cleanErrors()
544: {
545: $this->errors = [];
546: }
547:
548:
549: 550: 551: 552:
553: public static function enableAutoOptionalMode()
554: {
555: self::$autoOptional = TRUE;
556: }
557:
558:
559:
560:
561:
562: 563: 564: 565:
566: public function setOption($key, $value)
567: {
568: if ($value === NULL) {
569: unset($this->options[$key]);
570: } else {
571: $this->options[$key] = $value;
572: }
573: return $this;
574: }
575:
576:
577: 578: 579: 580:
581: public function getOption($key, $default = NULL)
582: {
583: return isset($this->options[$key]) ? $this->options[$key] : $default;
584: }
585:
586:
587: 588: 589: 590:
591: public function getOptions()
592: {
593: return $this->options;
594: }
595:
596:
597:
598:
599:
600: public function __call($name, $args)
601: {
602: if ($callback = Nette\Utils\ObjectMixin::getExtensionMethod(get_class($this), $name)) {
603: return Nette\Utils\Callback::invoke($callback, $this, ...$args);
604: }
605: return parent::__call($name, $args);
606: }
607:
608:
609: public static function extensionMethod($name, $callback = NULL)
610: {
611: if (strpos($name, '::') !== FALSE) {
612: list(, $name) = explode('::', $name);
613: }
614: Nette\Utils\ObjectMixin::setExtensionMethod(get_called_class(), $name, $callback);
615: }
616:
617: }
618: