Namespaces

  • Latte
    • Loaders
    • Macros
    • Runtime
  • Nette
    • Application
      • Responses
      • Routers
      • UI
    • Bridges
      • ApplicationDI
      • ApplicationLatte
      • ApplicationTracy
      • CacheDI
      • CacheLatte
      • DatabaseDI
      • DatabaseTracy
      • DITracy
      • FormsDI
      • FormsLatte
      • Framework
      • HttpDI
      • HttpTracy
      • MailDI
      • ReflectionDI
      • SecurityDI
      • SecurityTracy
    • Caching
      • Storages
    • ComponentModel
    • Database
      • Conventions
      • Drivers
      • Table
    • DI
      • Config
        • Adapters
      • Extensions
    • Forms
      • Controls
      • Rendering
    • Http
    • Iterators
    • Loaders
    • Localization
    • Mail
    • Neon
    • PhpGenerator
      • Traits
    • Reflection
    • Security
    • Tokenizer
    • Utils
  • Tracy
    • Bridges
      • Nette
  • none

Classes

  • BaseControl
  • Button
  • Checkbox
  • CheckboxList
  • ChoiceControl
  • CsrfProtection
  • HiddenField
  • ImageButton
  • MultiChoiceControl
  • MultiSelectBox
  • RadioList
  • SelectBox
  • SubmitButton
  • TextArea
  • TextBase
  • TextInput
  • UploadControl
  • Overview
  • Namespace
  • Class
  • Tree
  • Deprecated
  • Other releases
  1: <?php
  2: 
  3: /**
  4:  * This file is part of the Nette Framework (https://nette.org)
  5:  * Copyright (c) 2004 David Grudl (https://davidgrudl.com)
  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:  * Base class that implements the basic functionality common to form controls.
 19:  *
 20:  * @property-read Form $form
 21:  * @property-read string $htmlName
 22:  * @property   mixed $htmlId
 23:  * @property   mixed $value
 24:  * @property   bool $disabled
 25:  * @property   bool $omitted
 26:  * @property-read Html $control
 27:  * @property-read Html $label
 28:  * @property-read Html $controlPrototype
 29:  * @property-read Html $labelPrototype
 30:  * @property   bool $required
 31:  * @property-read bool $filled
 32:  * @property-read array $errors
 33:  * @property-read array $options
 34:  * @property-read string $error
 35:  */
 36: abstract class BaseControl extends Nette\ComponentModel\Component implements IControl
 37: {
 38:     /** @var string */
 39:     public static $idMask = 'frm-%s';
 40: 
 41:     /** @var string|object textual caption or label */
 42:     public $caption;
 43: 
 44:     /** @var mixed current control value */
 45:     protected $value;
 46: 
 47:     /** @var Html  control element template */
 48:     protected $control;
 49: 
 50:     /** @var Html  label element template */
 51:     protected $label;
 52: 
 53:     /** @var bool */
 54:     protected $disabled = false;
 55: 
 56:     /** @var array */
 57:     private $errors = [];
 58: 
 59:     /** @var bool|null */
 60:     private $omitted;
 61: 
 62:     /** @var Rules */
 63:     private $rules;
 64: 
 65:     /** @var Nette\Localization\ITranslator */
 66:     private $translator = true; // means autodetect
 67: 
 68:     /** @var array user options */
 69:     private $options = [];
 70: 
 71:     /** @var bool */
 72:     private static $autoOptional = false;
 73: 
 74: 
 75:     /**
 76:      * @param  string|object
 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:      * This method will be called when the component becomes attached to Form.
 95:      * @param  Nette\ComponentModel\IComponent
 96:      * @return void
 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:      * Returns form.
108:      * @param  bool
109:      * @return Form|null
110:      */
111:     public function getForm($throw = true)
112:     {
113:         return $this->lookup(Form::class, $throw);
114:     }
115: 
116: 
117:     /**
118:      * Loads HTTP data.
119:      * @return void
120:      */
121:     public function loadHttpData()
122:     {
123:         $this->setValue($this->getHttpData(Form::DATA_TEXT));
124:     }
125: 
126: 
127:     /**
128:      * Loads HTTP data.
129:      * @return mixed
130:      */
131:     protected function getHttpData($type, $htmlTail = null)
132:     {
133:         return $this->getForm()->getHttpData($type, $this->getHtmlName() . $htmlTail);
134:     }
135: 
136: 
137:     /**
138:      * Returns HTML name of control.
139:      * @return string
140:      */
141:     public function getHtmlName()
142:     {
143:         return Nette\Forms\Helpers::generateHtmlName($this->lookupPath(Form::class));
144:     }
145: 
146: 
147:     /********************* interface IControl ****************d*g**/
148: 
149: 
150:     /**
151:      * Sets control's value.
152:      * @return static
153:      * @internal
154:      */
155:     public function setValue($value)
156:     {
157:         $this->value = $value;
158:         return $this;
159:     }
160: 
161: 
162:     /**
163:      * Returns control's value.
164:      * @return mixed
165:      */
166:     public function getValue()
167:     {
168:         return $this->value;
169:     }
170: 
171: 
172:     /**
173:      * Is control filled?
174:      * @return bool
175:      */
176:     public function isFilled()
177:     {
178:         $value = $this->getValue();
179:         return $value !== null && $value !== [] && $value !== '';
180:     }
181: 
182: 
183:     /**
184:      * Sets control's default value.
185:      * @return static
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:      * Disables or enables control.
199:      * @param  bool
200:      * @return static
201:      */
202:     public function setDisabled($value = true)
203:     {
204:         if ($this->disabled = (bool) $value) {
205:             $this->setValue(null);
206:         } elseif (($form = $this->getForm(false)) && $form->isAnchored() && $form->isSubmitted()) {
207:             $this->loadHttpData();
208:         }
209:         return $this;
210:     }
211: 
212: 
213:     /**
214:      * Is control disabled?
215:      * @return bool
216:      */
217:     public function isDisabled()
218:     {
219:         return $this->disabled === true;
220:     }
221: 
222: 
223:     /**
224:      * Sets whether control value is excluded from $form->getValues() result.
225:      * @param  bool
226:      * @return static
227:      */
228:     public function setOmitted($value = true)
229:     {
230:         $this->omitted = (bool) $value;
231:         return $this;
232:     }
233: 
234: 
235:     /**
236:      * Is control value excluded from $form->getValues() result?
237:      * @return bool
238:      */
239:     public function isOmitted()
240:     {
241:         return $this->omitted || ($this->isDisabled() && $this->omitted === null);
242:     }
243: 
244: 
245:     /********************* rendering ****************d*g**/
246: 
247: 
248:     /**
249:      * Generates control's HTML element.
250:      * @return Html|string
251:      */
252:     public function getControl()
253:     {
254:         $this->setOption('rendered', true);
255:         $el = clone $this->control;
256:         return $el->addAttributes([
257:             'name' => $this->getHtmlName(),
258:             'id' => $this->getHtmlId(),
259:             'required' => $this->isRequired(),
260:             'disabled' => $this->isDisabled(),
261:             'data-nette-rules' => Nette\Forms\Helpers::exportRules($this->rules) ?: null,
262:         ]);
263:     }
264: 
265: 
266:     /**
267:      * Generates label's HTML element.
268:      * @param  string|object
269:      * @return Html|string
270:      */
271:     public function getLabel($caption = null)
272:     {
273:         $label = clone $this->label;
274:         $label->for = $this->getHtmlId();
275:         $label->setText($this->translate($caption === null ? $this->caption : $caption));
276:         return $label;
277:     }
278: 
279: 
280:     /**
281:      * @return Nette\Utils\Html|null
282:      */
283:     public function getControlPart()
284:     {
285:         return $this->getControl();
286:     }
287: 
288: 
289:     /**
290:      * @return Nette\Utils\Html|null
291:      */
292:     public function getLabelPart()
293:     {
294:         return $this->getLabel();
295:     }
296: 
297: 
298:     /**
299:      * Returns control's HTML element template.
300:      * @return Html
301:      */
302:     public function getControlPrototype()
303:     {
304:         return $this->control;
305:     }
306: 
307: 
308:     /**
309:      * Returns label's HTML element template.
310:      * @return Html
311:      */
312:     public function getLabelPrototype()
313:     {
314:         return $this->label;
315:     }
316: 
317: 
318:     /**
319:      * Changes control's HTML id.
320:      * @param  mixed  new ID, or false or null
321:      * @return static
322:      */
323:     public function setHtmlId($id)
324:     {
325:         $this->control->id = $id;
326:         return $this;
327:     }
328: 
329: 
330:     /**
331:      * Returns control's HTML id.
332:      * @return mixed
333:      */
334:     public function getHtmlId()
335:     {
336:         if (!isset($this->control->id)) {
337:             $form = $this->getForm(false);
338:             $this->control->id = sprintf(self::$idMask, $this->lookupPath(), $form ? $form->getName() : '');
339:         }
340:         return $this->control->id;
341:     }
342: 
343: 
344:     /**
345:      * Changes control's HTML attribute.
346:      * @param  string
347:      * @param  mixed
348:      * @return static
349:      */
350:     public function setHtmlAttribute($name, $value = true)
351:     {
352:         return $this->setAttribute($name, $value);
353:     }
354: 
355: 
356:     /**
357:      * Alias for setHtmlAttribute()
358:      * @param  string
359:      * @param  mixed
360:      * @return static
361:      */
362:     public function setAttribute($name, $value = true)
363:     {
364:         $this->control->$name = $value;
365:         return $this;
366:     }
367: 
368: 
369:     /********************* translator ****************d*g**/
370: 
371: 
372:     /**
373:      * Sets translate adapter.
374:      * @return static
375:      */
376:     public function setTranslator(Nette\Localization\ITranslator $translator = null)
377:     {
378:         $this->translator = $translator;
379:         return $this;
380:     }
381: 
382: 
383:     /**
384:      * Returns translate adapter.
385:      * @return Nette\Localization\ITranslator|null
386:      */
387:     public function getTranslator()
388:     {
389:         if ($this->translator === true) {
390:             return $this->getForm(false) ? $this->getForm()->getTranslator() : null;
391:         }
392:         return $this->translator;
393:     }
394: 
395: 
396:     /**
397:      * Returns translated string.
398:      * @param  mixed
399:      * @param  int      plural count
400:      * @return mixed
401:      */
402:     public function translate($value, $count = null)
403:     {
404:         if ($translator = $this->getTranslator()) {
405:             $tmp = is_array($value) ? [&$value] : [[&$value]];
406:             foreach ($tmp[0] as &$v) {
407:                 if ($v != null && !$v instanceof Html) { // intentionally ==
408:                     $v = $translator->translate($v, $count);
409:                 }
410:             }
411:         }
412:         return $value;
413:     }
414: 
415: 
416:     /********************* rules ****************d*g**/
417: 
418: 
419:     /**
420:      * Adds a validation rule.
421:      * @param  mixed
422:      * @param  string|object
423:      * @param  mixed
424:      * @return static
425:      */
426:     public function addRule($validator, $errorMessage = null, $arg = null)
427:     {
428:         $this->rules->addRule($validator, $errorMessage, $arg);
429:         return $this;
430:     }
431: 
432: 
433:     /**
434:      * Adds a validation condition a returns new branch.
435:      * @param  mixed
436:      * @param  mixed
437:      * @return Rules      new branch
438:      */
439:     public function addCondition($validator, $value = null)
440:     {
441:         return $this->rules->addCondition($validator, $value);
442:     }
443: 
444: 
445:     /**
446:      * Adds a validation condition based on another control a returns new branch.
447:      * @param  IControl
448:      * @param  mixed
449:      * @param  mixed
450:      * @return Rules      new branch
451:      */
452:     public function addConditionOn(IControl $control, $validator, $value = null)
453:     {
454:         return $this->rules->addConditionOn($control, $validator, $value);
455:     }
456: 
457: 
458:     /**
459:      * @return Rules
460:      */
461:     public function getRules()
462:     {
463:         return $this->rules;
464:     }
465: 
466: 
467:     /**
468:      * Makes control mandatory.
469:      * @param  mixed  state or error message
470:      * @return static
471:      */
472:     public function setRequired($value = true)
473:     {
474:         $this->rules->setRequired($value);
475:         return $this;
476:     }
477: 
478: 
479:     /**
480:      * Is control mandatory?
481:      * @return bool
482:      */
483:     public function isRequired()
484:     {
485:         return $this->rules->isRequired();
486:     }
487: 
488: 
489:     /**
490:      * Performs the server side validation.
491:      * @return void
492:      */
493:     public function validate()
494:     {
495:         if ($this->isDisabled()) {
496:             return;
497:         }
498:         $this->cleanErrors();
499:         $this->rules->validate();
500:     }
501: 
502: 
503:     /**
504:      * Adds error message to the list.
505:      * @param  string|object
506:      * @return void
507:      */
508:     public function addError($message, $translate = true)
509:     {
510:         $this->errors[] = $translate ? $this->translate($message) : $message;
511:     }
512: 
513: 
514:     /**
515:      * Returns errors corresponding to control.
516:      * @return string|null
517:      */
518:     public function getError()
519:     {
520:         return $this->errors ? implode(' ', array_unique($this->errors)) : null;
521:     }
522: 
523: 
524:     /**
525:      * Returns errors corresponding to control.
526:      * @return array
527:      */
528:     public function getErrors()
529:     {
530:         return array_unique($this->errors);
531:     }
532: 
533: 
534:     /**
535:      * @return bool
536:      */
537:     public function hasErrors()
538:     {
539:         return (bool) $this->errors;
540:     }
541: 
542: 
543:     /**
544:      * @return void
545:      */
546:     public function cleanErrors()
547:     {
548:         $this->errors = [];
549:     }
550: 
551: 
552:     /**
553:      * Globally enables new required/optional behavior.
554:      * This method will be deprecated in next version.
555:      */
556:     public static function enableAutoOptionalMode()
557:     {
558:         self::$autoOptional = true;
559:     }
560: 
561: 
562:     /********************* user data ****************d*g**/
563: 
564: 
565:     /**
566:      * Sets user-specific option.
567:      * @return static
568:      */
569:     public function setOption($key, $value)
570:     {
571:         if ($value === null) {
572:             unset($this->options[$key]);
573:         } else {
574:             $this->options[$key] = $value;
575:         }
576:         return $this;
577:     }
578: 
579: 
580:     /**
581:      * Returns user-specific option.
582:      * @return mixed
583:      */
584:     public function getOption($key, $default = null)
585:     {
586:         return isset($this->options[$key]) ? $this->options[$key] : $default;
587:     }
588: 
589: 
590:     /**
591:      * Returns user-specific options.
592:      * @return array
593:      */
594:     public function getOptions()
595:     {
596:         return $this->options;
597:     }
598: 
599: 
600:     /********************* extension methods ****************d*g**/
601: 
602: 
603:     public function __call($name, $args)
604:     {
605:         if ($callback = Nette\Utils\ObjectMixin::getExtensionMethod(get_class($this), $name)) {
606:             return Nette\Utils\Callback::invoke($callback, $this, ...$args);
607:         }
608:         return parent::__call($name, $args);
609:     }
610: 
611: 
612:     public static function extensionMethod($name, $callback = null)
613:     {
614:         if (strpos($name, '::') !== false) { // back compatibility
615:             list(, $name) = explode('::', $name);
616:         }
617:         Nette\Utils\ObjectMixin::setExtensionMethod(get_called_class(), $name, $callback);
618:     }
619: }
620: 
Nette 2.4-20180918 API API documentation generated by ApiGen 2.8.0