Namespaces

  • Nette
    • Application
      • Diagnostics
      • Responses
      • Routers
      • UI
    • Caching
      • Storages
    • ComponentModel
    • Config
      • Adapters
      • Extensions
    • Database
      • Diagnostics
      • Drivers
      • Reflection
      • Table
    • DI
      • Diagnostics
    • Diagnostics
    • Forms
      • Controls
      • Rendering
    • Http
    • Iterators
    • Latte
      • Macros
    • Loaders
    • Localization
    • Mail
    • Reflection
    • Security
      • Diagnostics
    • Templating
    • Utils
      • PhpGenerator
  • NetteModule
  • none

Classes

  • BaseControl
  • Button
  • Checkbox
  • HiddenField
  • ImageButton
  • MultiSelectBox
  • RadioList
  • SelectBox
  • SubmitButton
  • TextArea
  • TextBase
  • TextInput
  • UploadControl
  • Overview
  • Namespace
  • Class
  • Tree
  • Deprecated
  • Other releases
  • Nette homepage
  1: <?php
  2: 
  3: /**
  4:  * This file is part of the Nette Framework (https://nette.org)
  5:  * Copyright (c) 2004 David Grudl (http://davidgrudl.com)
  6:  */
  7: 
  8: namespace Nette\Forms\Controls;
  9: 
 10: use Nette,
 11:     Nette\Forms\IControl,
 12:     Nette\Utils\Html,
 13:     Nette\Forms\Form,
 14:     Nette\Forms\Rule;
 15: 
 16: 
 17: /**
 18:  * Base class that implements the basic functionality common to form controls.
 19:  *
 20:  * @author     David Grudl
 21:  *
 22:  * @property-read Nette\Forms\Form $form
 23:  * @property-read string $htmlName
 24:  * @property   string $htmlId
 25:  * @property-read array $options
 26:  * @property   Nette\Localization\ITranslator|NULL $translator
 27:  * @property   mixed $value
 28:  * @property-read bool $filled
 29:  * @property-write $defaultValue
 30:  * @property   bool $disabled
 31:  * @property-read Nette\Utils\Html $control
 32:  * @property-read Nette\Utils\Html $label
 33:  * @property-read Nette\Utils\Html $controlPrototype
 34:  * @property-read Nette\Utils\Html $labelPrototype
 35:  * @property-read Nette\Forms\Rules $rules
 36:  * @property   bool $required
 37:  * @property-read array $errors
 38:  */
 39: abstract class BaseControl extends Nette\ComponentModel\Component implements IControl
 40: {
 41:     /** @var string */
 42:     public static $idMask = 'frm%s-%s';
 43: 
 44:     /** @var string textual caption or label */
 45:     public $caption;
 46: 
 47:     /** @var mixed unfiltered control value */
 48:     protected $value;
 49: 
 50:     /** @var Nette\Utils\Html  control element template */
 51:     protected $control;
 52: 
 53:     /** @var Nette\Utils\Html  label element template */
 54:     protected $label;
 55: 
 56:     /** @var array */
 57:     private $errors = array();
 58: 
 59:     /** @var bool */
 60:     private $disabled = FALSE;
 61: 
 62:     /** @var string */
 63:     private $htmlId;
 64: 
 65:     /** @var string */
 66:     private $htmlName;
 67: 
 68:     /** @var Nette\Forms\Rules */
 69:     private $rules;
 70: 
 71:     /** @var Nette\Localization\ITranslator */
 72:     private $translator = TRUE; // means autodetect
 73: 
 74:     /** @var array user options */
 75:     private $options = array();
 76: 
 77: 
 78:     /**
 79:      * @param  string  caption
 80:      */
 81:     public function __construct($caption = NULL)
 82:     {
 83:         $this->monitor('Nette\Forms\Form');
 84:         parent::__construct();
 85:         $this->control = Html::el('input');
 86:         $this->label = Html::el('label');
 87:         $this->caption = $caption;
 88:         $this->rules = new Nette\Forms\Rules($this);
 89:     }
 90: 
 91: 
 92:     /**
 93:      * This method will be called when the component becomes attached to Form.
 94:      * @param  Nette\ComponentModel\IComponent
 95:      * @return void
 96:      */
 97:     protected function attached($form)
 98:     {
 99:         if (!$this->disabled && $form instanceof Form && $form->isAnchored() && $form->isSubmitted()) {
100:             $this->htmlName = NULL;
101:             $this->loadHttpData();
102:         }
103:     }
104: 
105: 
106:     /**
107:      * Returns form.
108:      * @param  bool   throw exception if form doesn't exist?
109:      * @return Nette\Forms\Form
110:      */
111:     public function getForm($need = TRUE)
112:     {
113:         return $this->lookup('Nette\Forms\Form', $need);
114:     }
115: 
116: 
117:     /**
118:      * Loads HTTP data.
119:      * @return void
120:      */
121:     public function loadHttpData()
122:     {
123:         $path = explode('[', strtr(str_replace(array('[]', ']'), '', $this->getHtmlName()), '.', '_'));
124:         $this->setValue(Nette\Utils\Arrays::get($this->getForm()->getHttpData(), $path, NULL));
125:     }
126: 
127: 
128:     /**
129:      * Returns HTML name of control.
130:      * @return string
131:      */
132:     public function getHtmlName()
133:     {
134:         if ($this->htmlName === NULL) {
135:             $name = str_replace(self::NAME_SEPARATOR, '][', $this->lookupPath('Nette\Forms\Form'), $count);
136:             if ($count) {
137:                 $name = substr_replace($name, '', strpos($name, ']'), 1) . ']';
138:             }
139:             if (is_numeric($name) || in_array($name, array('attributes','children','elements','focus','length','reset','style','submit','onsubmit'), TRUE)) {
140:                 $name .= '_';
141:             }
142:             $this->htmlName = $name;
143:         }
144:         return $this->htmlName;
145:     }
146: 
147: 
148:     /********************* interface IFormControl ****************d*g**/
149: 
150: 
151:     /**
152:      * Sets control's value.
153:      * @return self
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:         return (string) $this->getValue() !== ''; // NULL, FALSE, '' ==> FALSE
179:     }
180: 
181: 
182:     /**
183:      * Sets control's default value.
184:      * @return self
185:      */
186:     public function setDefaultValue($value)
187:     {
188:         $form = $this->getForm(FALSE);
189:         if (!$form || !$form->isAnchored() || !$form->isSubmitted()) {
190:             $this->setValue($value);
191:         }
192:         return $this;
193:     }
194: 
195: 
196:     /**
197:      * Disables or enables control.
198:      * @param  bool
199:      * @return self
200:      */
201:     public function setDisabled($value = TRUE)
202:     {
203:         $this->disabled = (bool) $value;
204:         return $this;
205:     }
206: 
207: 
208:     /**
209:      * Is control disabled?
210:      * @return bool
211:      */
212:     public function isDisabled()
213:     {
214:         return $this->disabled;
215:     }
216: 
217: 
218:     /********************* rendering ****************d*g**/
219: 
220: 
221:     /**
222:      * Generates control's HTML element.
223:      * @return Nette\Utils\Html
224:      */
225:     public function getControl()
226:     {
227:         $this->setOption('rendered', TRUE);
228: 
229:         $control = clone $this->control;
230:         $control->name = $this->getHtmlName();
231:         $control->disabled = $this->disabled;
232:         $control->id = $this->getHtmlId();
233:         $control->required = $this->isRequired();
234: 
235:         $rules = self::exportRules($this->rules);
236:         $rules = substr(PHP_VERSION_ID >= 50400 ? json_encode($rules, JSON_UNESCAPED_UNICODE) : json_encode($rules), 1, -1);
237:         $rules = preg_replace('#"([a-z0-9_]+)":#i', '$1:', $rules);
238:         $rules = preg_replace('#(?<!\\\\)"(?!:[^a-z])([^\\\\\',]*)"#i', "'$1'", $rules);
239:         $control->data('nette-rules', $rules ? $rules : NULL);
240: 
241:         return $control;
242:     }
243: 
244: 
245:     /**
246:      * Generates label's HTML element.
247:      * @param  string
248:      * @return Nette\Utils\Html
249:      */
250:     public function getLabel($caption = NULL)
251:     {
252:         $label = clone $this->label;
253:         $label->for = $this->getHtmlId();
254:         if ($caption !== NULL) {
255:             $label->setText($this->translate($caption));
256: 
257:         } elseif ($this->caption instanceof Html) {
258:             $label->add($this->caption);
259: 
260:         } else {
261:             $label->setText($this->translate($this->caption));
262:         }
263:         return $label;
264:     }
265: 
266: 
267:     /**
268:      * Returns control's HTML element template.
269:      * @return Nette\Utils\Html
270:      */
271:     public function getControlPrototype()
272:     {
273:         return $this->control;
274:     }
275: 
276: 
277:     /**
278:      * Returns label's HTML element template.
279:      * @return Nette\Utils\Html
280:      */
281:     public function getLabelPrototype()
282:     {
283:         return $this->label;
284:     }
285: 
286: 
287:     /**
288:      * Changes control's HTML id.
289:      * @param  string new ID, or FALSE or NULL
290:      * @return self
291:      */
292:     public function setHtmlId($id)
293:     {
294:         $this->htmlId = $id;
295:         return $this;
296:     }
297: 
298: 
299:     /**
300:      * Returns control's HTML id.
301:      * @return string
302:      */
303:     public function getHtmlId()
304:     {
305:         if ($this->htmlId === FALSE) {
306:             return NULL;
307: 
308:         } elseif ($this->htmlId === NULL) {
309:             $this->htmlId = sprintf(self::$idMask, $this->getForm()->getName(), $this->lookupPath('Nette\Forms\Form'));
310:         }
311:         return $this->htmlId;
312:     }
313: 
314: 
315:     /**
316:      * Changes control's HTML attribute.
317:      * @param  string name
318:      * @param  mixed  value
319:      * @return self
320:      */
321:     public function setAttribute($name, $value = TRUE)
322:     {
323:         $this->control->$name = $value;
324:         return $this;
325:     }
326: 
327: 
328:     /********************* translator ****************d*g**/
329: 
330: 
331:     /**
332:      * Sets translate adapter.
333:      * @return self
334:      */
335:     public function setTranslator(Nette\Localization\ITranslator $translator = NULL)
336:     {
337:         $this->translator = $translator;
338:         return $this;
339:     }
340: 
341: 
342:     /**
343:      * Returns translate adapter.
344:      * @return Nette\Localization\ITranslator|NULL
345:      */
346:     public function getTranslator()
347:     {
348:         if ($this->translator === TRUE) {
349:             return $this->getForm(FALSE) ? $this->getForm()->getTranslator() : NULL;
350:         }
351:         return $this->translator;
352:     }
353: 
354: 
355:     /**
356:      * Returns translated string.
357:      * @param  string
358:      * @param  int      plural count
359:      * @return string
360:      */
361:     public function translate($s, $count = NULL)
362:     {
363:         $translator = $this->getTranslator();
364:         return $translator === NULL || $s == NULL ? $s : $translator->translate($s, $count); // intentionally ==
365:     }
366: 
367: 
368:     /********************* rules ****************d*g**/
369: 
370: 
371:     /**
372:      * Adds a validation rule.
373:      * @param  mixed      rule type
374:      * @param  string     message to display for invalid data
375:      * @param  mixed      optional rule arguments
376:      * @return self
377:      */
378:     public function addRule($operation, $message = NULL, $arg = NULL)
379:     {
380:         $this->rules->addRule($operation, $message, $arg);
381:         return $this;
382:     }
383: 
384: 
385:     /**
386:      * Adds a validation condition a returns new branch.
387:      * @param  mixed     condition type
388:      * @param  mixed     optional condition arguments
389:      * @return Nette\Forms\Rules      new branch
390:      */
391:     public function addCondition($operation, $value = NULL)
392:     {
393:         return $this->rules->addCondition($operation, $value);
394:     }
395: 
396: 
397:     /**
398:      * Adds a validation condition based on another control a returns new branch.
399:      * @param  Nette\Forms\IControl form control
400:      * @param  mixed      condition type
401:      * @param  mixed      optional condition arguments
402:      * @return Nette\Forms\Rules      new branch
403:      */
404:     public function addConditionOn(IControl $control, $operation, $value = NULL)
405:     {
406:         return $this->rules->addConditionOn($control, $operation, $value);
407:     }
408: 
409: 
410:     /**
411:      * @return Nette\Forms\Rules
412:      */
413:     public function getRules()
414:     {
415:         return $this->rules;
416:     }
417: 
418: 
419:     /**
420:      * Makes control mandatory.
421:      * @param  string  error message
422:      * @return self
423:      */
424:     public function setRequired($message = NULL)
425:     {
426:         return $this->addRule(Form::FILLED, $message);
427:     }
428: 
429: 
430:     /**
431:      * Is control mandatory?
432:      * @return bool
433:      */
434:     public function isRequired()
435:     {
436:         foreach ($this->rules as $rule) {
437:             if ($rule->type === Rule::VALIDATOR && !$rule->isNegative && $rule->operation === Form::FILLED) {
438:                 return TRUE;
439:             }
440:         }
441:         return FALSE;
442:     }
443: 
444: 
445:     /**
446:      * Adds error message to the list.
447:      * @param  string  error message
448:      * @return void
449:      */
450:     public function addError($message)
451:     {
452:         if (!in_array($message, $this->errors, TRUE)) {
453:             $this->errors[] = $message;
454:         }
455:         $this->getForm()->addError($message);
456:     }
457: 
458: 
459:     /**
460:      * Returns errors corresponding to control.
461:      * @return array
462:      */
463:     public function getErrors()
464:     {
465:         return $this->errors;
466:     }
467: 
468: 
469:     /**
470:      * @return bool
471:      */
472:     public function hasErrors()
473:     {
474:         return (bool) $this->errors;
475:     }
476: 
477: 
478:     /**
479:      * @return void
480:      */
481:     public function cleanErrors()
482:     {
483:         $this->errors = array();
484:     }
485: 
486: 
487:     /**
488:      * @return array
489:      */
490:     protected static function exportRules($rules)
491:     {
492:         $payload = array();
493:         foreach ($rules as $rule) {
494:             if (!is_string($op = $rule->operation)) {
495:                 $op = new Nette\Callback($op);
496:                 if (!$op->isStatic()) {
497:                     continue;
498:                 }
499:             }
500:             if ($rule->type === Rule::VALIDATOR) {
501:                 $item = array('op' => ($rule->isNegative ? '~' : '') . $op, 'msg' => $rules->formatMessage($rule, FALSE));
502: 
503:             } elseif ($rule->type === Rule::CONDITION) {
504:                 $item = array(
505:                     'op' => ($rule->isNegative ? '~' : '') . $op,
506:                     'rules' => self::exportRules($rule->subRules),
507:                     'control' => $rule->control->getHtmlName()
508:                 );
509:                 if ($rule->subRules->getToggles()) {
510:                     $item['toggle'] = $rule->subRules->getToggles();
511:                 }
512:             }
513: 
514:             if (is_array($rule->arg)) {
515:                 foreach ($rule->arg as $key => $value) {
516:                     $item['arg'][$key] = $value instanceof IControl ? (object) array('control' => $value->getHtmlName()) : $value;
517:                 }
518:             } elseif ($rule->arg !== NULL) {
519:                 $item['arg'] = $rule->arg instanceof IControl ? (object) array('control' => $rule->arg->getHtmlName()) : $rule->arg;
520:             }
521: 
522:             $payload[] = $item;
523:         }
524:         return $payload;
525:     }
526: 
527: 
528:     /********************* validators ****************d*g**/
529: 
530: 
531:     /**
532:      * Is control's value equal with second parameter?
533:      * @return bool
534:      * @internal
535:      */
536:     public static function validateEqual(IControl $control, $arg)
537:     {
538:         $value = $control->getValue();
539:         foreach ((is_array($value) ? $value : array($value)) as $val) {
540:             foreach ((is_array($arg) ? $arg : array($arg)) as $item) {
541:                 if ((string) $val === (string) ($item instanceof IControl ? $item->value : $item)) {
542:                     return TRUE;
543:                 }
544:             }
545:         }
546:         return FALSE;
547:     }
548: 
549: 
550:     /**
551:      * Is control's value not equal with second parameter?
552:      * @return bool
553:      * @internal
554:      */
555:     public static function validateNotEqual(IControl $control, $arg)
556:     {
557:         return !static::validateEqual($control, $arg);
558:     }
559: 
560: 
561:     /**
562:      * Is control filled?
563:      * @return bool
564:      * @internal
565:      */
566:     public static function validateFilled(IControl $control)
567:     {
568:         return $control->isFilled();
569:     }
570: 
571: 
572:     /**
573:      * Is control not filled?
574:      * @return bool
575:      * @internal
576:      */
577:     public static function validateBlank(IControl $control)
578:     {
579:         return !$control->isFilled();
580:     }
581: 
582: 
583:     /**
584:      * Is control valid?
585:      * @return bool
586:      * @internal
587:      */
588:     public static function validateValid(IControl $control)
589:     {
590:         return $control->rules->validate(TRUE);
591:     }
592: 
593: 
594:     /********************* user data ****************d*g**/
595: 
596: 
597:     /**
598:      * Sets user-specific option.
599:      * Options recognized by DefaultFormRenderer
600:      * - 'description' - textual or Html object description
601:      * @return self
602:      */
603:     public function setOption($key, $value)
604:     {
605:         if ($value === NULL) {
606:             unset($this->options[$key]);
607:         } else {
608:             $this->options[$key] = $value;
609:         }
610:         return $this;
611:     }
612: 
613: 
614:     /**
615:      * Returns user-specific option.
616:      * @return mixed
617:      */
618:     public function getOption($key, $default = NULL)
619:     {
620:         return isset($this->options[$key]) ? $this->options[$key] : $default;
621:     }
622: 
623: 
624:     /**
625:      * Returns user-specific options.
626:      * @return array
627:      */
628:     public function getOptions()
629:     {
630:         return $this->options;
631:     }
632: 
633: }
634: 
Nette 2.0 API documentation generated by ApiGen 2.8.0