1: <?php
  2: 
  3:   4:   5:   6:   7:   8:   9:  10: 
 11: 
 12: namespace Nette\Forms;
 13: 
 14: use Nette,
 15:     Nette\Web\Html;
 16: 
 17: 
 18: 
 19:  20:  21:  22:  23:  24:  25:  26:  27:  28:  29:  30:  31:  32:  33:  34:  35:  36:  37:  38:  39: 
 40: abstract class FormControl extends Nette\Component implements IFormControl
 41: {
 42:     
 43:     public static $idMask = 'frm%s-%s';
 44: 
 45:     
 46:     public $caption;
 47: 
 48:     
 49:     protected $value;
 50: 
 51:     
 52:     protected $control;
 53: 
 54:     
 55:     protected $label;
 56: 
 57:     
 58:     private $errors = array();
 59: 
 60:     
 61:     private $disabled = FALSE;
 62: 
 63:     
 64:     private $htmlId;
 65: 
 66:     
 67:     private $htmlName;
 68: 
 69:     
 70:     private $rules;
 71: 
 72:     
 73:     private $translator = TRUE; 
 74: 
 75:     
 76:     private $options = array();
 77: 
 78: 
 79: 
 80:      81:  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:  97:  98:  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: 112: 113: 114: 
115:     public function getForm($need = TRUE)
116:     {
117:         return $this->lookup('Nette\Forms\Form', $need);
118:     }
119: 
120: 
121: 
122:     123: 124: 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: 150: 151: 152: 
153:     public function setHtmlId($id)
154:     {
155:         $this->htmlId = $id;
156:         return $this;
157:     }
158: 
159: 
160: 
161:     162: 163: 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: 181: 182: 183: 184: 185: 186: 187: 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: 204: 205: 206: 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: 217: 218: 
219:     final public function getOptions()
220:     {
221:         return $this->options;
222:     }
223: 
224: 
225: 
226:     
227: 
228: 
229: 
230:     231: 232: 233: 234: 
235:     public function setTranslator(Nette\ITranslator $translator = NULL)
236:     {
237:         $this->translator = $translator;
238:         return $this;
239:     }
240: 
241: 
242: 
243:     244: 245: 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: 259: 260: 261: 262: 
263:     public function translate($s, $count = NULL)
264:     {
265:         $translator = $this->getTranslator();
266:         return $translator === NULL || $s == NULL ? $s : $translator->translate($s, $count); 
267:     }
268: 
269: 
270: 
271:     
272: 
273: 
274: 
275:     276: 277: 278: 279: 
280:     public function setValue($value)
281:     {
282:         $this->value = $value;
283:         return $this;
284:     }
285: 
286: 
287: 
288:     289: 290: 291: 
292:     public function getValue()
293:     {
294:         return $this->value;
295:     }
296: 
297: 
298: 
299:     300: 301: 302: 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: 317: 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: 329: 330: 331: 
332:     public function setDisabled($value = TRUE)
333:     {
334:         $this->disabled = (bool) $value;
335:         return $this;
336:     }
337: 
338: 
339: 
340:     341: 342: 343: 
344:     public function isDisabled()
345:     {
346:         return $this->disabled;
347:     }
348: 
349: 
350: 
351:     
352: 
353: 
354: 
355:     356: 357: 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: 373: 374: 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: 396: 397: 
398:     final public function getControlPrototype()
399:     {
400:         return $this->control;
401:     }
402: 
403: 
404: 
405:     406: 407: 408: 
409:     final public function getLabelPrototype()
410:     {
411:         return $this->label;
412:     }
413: 
414: 
415: 
416:     417: 418: 419: 420: 421: 
422:     public function setRendered($value = TRUE)
423:     {
424:         $this->setOption('rendered', $value);
425:         return $this;
426:     }
427: 
428: 
429: 
430:     431: 432: 433: 434: 
435:     public function isRendered()
436:     {
437:         return !empty($this->options['rendered']);
438:     }
439: 
440: 
441: 
442:     
443: 
444: 
445: 
446:     447: 448: 449: 450: 451: 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: 463: 464: 465: 466: 
467:     public function addCondition($operation, $value = NULL)
468:     {
469:         return $this->rules->addCondition($operation, $value);
470:     }
471: 
472: 
473: 
474:     475: 476: 477: 478: 479: 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: 490: 
491:     final public function getRules()
492:     {
493:         return $this->rules;
494:     }
495: 
496: 
497: 
498:     499: 500: 501: 502: 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: 514: 515: 516: 
517:     final public function isRequired()
518:     {
519:         return !empty($this->options['required']);
520:     }
521: 
522: 
523: 
524:     525: 526: 527: 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:     
539: 
540: 
541: 
542:     543: 544: 545: 546: 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: 565: 566: 567: 
568:     public static function validateFilled(IFormControl $control)
569:     {
570:         return (string) $control->getValue() !== ''; 
571:     }
572: 
573: 
574: 
575:     576: 577: 578: 579: 
580:     public static function validateValid(IFormControl $control)
581:     {
582:         return $control->rules->validate(TRUE);
583:     }
584: 
585: 
586: 
587:     588: 589: 590: 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: 604: 605: 
606:     public function getErrors()
607:     {
608:         return $this->errors;
609:     }
610: 
611: 
612: 
613:     614: 615: 
616:     public function hasErrors()
617:     {
618:         return (bool) $this->errors;
619:     }
620: 
621: 
622: 
623:     624: 625: 
626:     public function cleanErrors()
627:     {
628:         $this->errors = array();
629:     }
630: 
631: }
632: