Namespaces

  • Nette
    • Application
    • Caching
    • Collections
    • Config
    • Forms
    • IO
    • Loaders
    • Mail
    • Reflection
    • Security
    • Templates
    • Web
  • None
  • PHP

Classes

  • Button
  • Checkbox
  • ConventionalRenderer
  • FileUpload
  • Form
  • FormContainer
  • FormControl
  • FormGroup
  • HiddenField
  • ImageButton
  • InstantClientScript
  • MultiSelectBox
  • RadioList
  • Rule
  • Rules
  • SelectBox
  • SubmitButton
  • TextArea
  • TextBase
  • TextInput

Interfaces

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