Packages

  • 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
  • PHP

Classes

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