Namespaces

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

Classes

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