1: <?php
2:
3: 4: 5: 6: 7: 8: 9: 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: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42:
43: abstract class BaseControl extends Nette\ComponentModel\Component implements IControl
44: {
45:
46: public static $idMask = 'frm%s-%s';
47:
48:
49: public $caption;
50:
51:
52: protected $value;
53:
54:
55: protected $control;
56:
57:
58: protected $label;
59:
60:
61: private $errors = array();
62:
63:
64: private $disabled = FALSE;
65:
66:
67: private $htmlId;
68:
69:
70: private $htmlName;
71:
72:
73: private $rules;
74:
75:
76: private $translator = TRUE;
77:
78:
79: private $options = array();
80:
81:
82: 83: 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: 99: 100:
101: protected function attached($form)
102: {
103: if (!$this->disabled && $form instanceof Form && $form->isAnchored() && $form->isSubmitted()) {
104: $this->htmlName = NULL;
105: $this->loadHttpData();
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: public function getHtmlName()
126: {
127: if ($this->htmlName === NULL) {
128: $name = str_replace(self::NAME_SEPARATOR, '][', $this->lookupPath('Nette\Forms\Form'), $count);
129: if ($count) {
130: $name = substr_replace($name, '', strpos($name, ']'), 1) . ']';
131: }
132: if (is_numeric($name) || in_array($name, array('attributes','children','elements','focus','length','reset','style','submit','onsubmit'))) {
133: $name .= '_';
134: }
135: $this->htmlName = $name;
136: }
137: return $this->htmlName;
138: }
139:
140:
141: 142: 143: 144: 145:
146: public function setHtmlId($id)
147: {
148: $this->htmlId = $id;
149: return $this;
150: }
151:
152:
153: 154: 155: 156:
157: public function getHtmlId()
158: {
159: if ($this->htmlId === FALSE) {
160: return NULL;
161:
162: } elseif ($this->htmlId === NULL) {
163: $this->htmlId = sprintf(self::$idMask, $this->getForm()->getName(), $this->lookupPath('Nette\Forms\Form'));
164: }
165: return $this->htmlId;
166: }
167:
168:
169: 170: 171: 172: 173: 174:
175: public function setAttribute($name, $value = TRUE)
176: {
177: $this->control->$name = $value;
178: return $this;
179: }
180:
181:
182: 183: 184: 185: 186: 187: 188: 189: 190:
191: public function setOption($key, $value)
192: {
193: if ($value === NULL) {
194: unset($this->options[$key]);
195:
196: } else {
197: $this->options[$key] = $value;
198: }
199: return $this;
200: }
201:
202:
203: 204: 205: 206: 207: 208:
209: final public function getOption($key, $default = NULL)
210: {
211: return isset($this->options[$key]) ? $this->options[$key] : $default;
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: public function setTranslator(Nette\Localization\ITranslator $translator = NULL)
233: {
234: $this->translator = $translator;
235: return $this;
236: }
237:
238:
239: 240: 241: 242:
243: final public function getTranslator()
244: {
245: if ($this->translator === TRUE) {
246: return $this->getForm(FALSE) ? $this->getForm()->getTranslator() : NULL;
247: }
248: return $this->translator;
249: }
250:
251:
252: 253: 254: 255: 256: 257:
258: public function translate($s, $count = NULL)
259: {
260: $translator = $this->getTranslator();
261: return $translator === NULL || $s == NULL ? $s : $translator->translate($s, $count);
262: }
263:
264:
265:
266:
267:
268: 269: 270: 271:
272: public function setValue($value)
273: {
274: $this->value = $value;
275: return $this;
276: }
277:
278:
279: 280: 281: 282:
283: public function getValue()
284: {
285: return $this->value;
286: }
287:
288:
289: 290: 291: 292:
293: public function isFilled()
294: {
295: return (string) $this->getValue() !== '';
296: }
297:
298:
299: 300: 301: 302:
303: public function setDefaultValue($value)
304: {
305: $form = $this->getForm(FALSE);
306: if (!$form || !$form->isAnchored() || !$form->isSubmitted()) {
307: $this->setValue($value);
308: }
309: return $this;
310: }
311:
312:
313: 314: 315: 316:
317: public function loadHttpData()
318: {
319: $path = explode('[', strtr(str_replace(array('[]', ']'), '', $this->getHtmlName()), '.', '_'));
320: $this->setValue(Nette\Utils\Arrays::get($this->getForm()->getHttpData(), $path, NULL));
321: }
322:
323:
324: 325: 326: 327: 328:
329: public function setDisabled($value = TRUE)
330: {
331: $this->disabled = (bool) $value;
332: return $this;
333: }
334:
335:
336: 337: 338: 339:
340: public function isDisabled()
341: {
342: return $this->disabled;
343: }
344:
345:
346:
347:
348:
349: 350: 351: 352:
353: public function getControl()
354: {
355: $this->setOption('rendered', TRUE);
356:
357: $control = clone $this->control;
358: $control->name = $this->getHtmlName();
359: $control->disabled = $this->disabled;
360: $control->id = $this->getHtmlId();
361: $control->required = $this->isRequired();
362:
363: $rules = self::exportRules($this->rules);
364: $rules = substr(PHP_VERSION_ID >= 50400 ? json_encode($rules, JSON_UNESCAPED_UNICODE) : json_encode($rules), 1, -1);
365: $rules = preg_replace('#"([a-z0-9_]+)":#i', '$1:', $rules);
366: $rules = preg_replace('#(?<!\\\\)"(?!:[^a-z])([^\\\\\',]*)"#i', "'$1'", $rules);
367: $control->data('nette-rules', $rules ? $rules : NULL);
368:
369: return $control;
370: }
371:
372:
373: 374: 375: 376: 377:
378: public function getLabel($caption = NULL)
379: {
380: $label = clone $this->label;
381: $label->for = $this->getHtmlId();
382: if ($caption !== NULL) {
383: $label->setText($this->translate($caption));
384:
385: } elseif ($this->caption instanceof Html) {
386: $label->add($this->caption);
387:
388: } else {
389: $label->setText($this->translate($this->caption));
390: }
391: return $label;
392: }
393:
394:
395: 396: 397: 398:
399: final public function getControlPrototype()
400: {
401: return $this->control;
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: 423: 424:
425: public function addRule($operation, $message = NULL, $arg = NULL)
426: {
427: $this->rules->addRule($operation, $message, $arg);
428: return $this;
429: }
430:
431:
432: 433: 434: 435: 436: 437:
438: public function addCondition($operation, $value = NULL)
439: {
440: return $this->rules->addCondition($operation, $value);
441: }
442:
443:
444: 445: 446: 447: 448: 449: 450:
451: public function addConditionOn(IControl $control, $operation, $value = NULL)
452: {
453: return $this->rules->addConditionOn($control, $operation, $value);
454: }
455:
456:
457: 458: 459:
460: final public function getRules()
461: {
462: return $this->rules;
463: }
464:
465:
466: 467: 468: 469: 470:
471: final public function setRequired($message = NULL)
472: {
473: return $this->addRule(Form::FILLED, $message);
474: }
475:
476:
477: 478: 479: 480:
481: final public function isRequired()
482: {
483: foreach ($this->rules as $rule) {
484: if ($rule->type === Rule::VALIDATOR && !$rule->isNegative && $rule->operation === Form::FILLED) {
485: return TRUE;
486: }
487: }
488: return FALSE;
489: }
490:
491:
492: 493: 494:
495: protected static function exportRules($rules)
496: {
497: $payload = array();
498: foreach ($rules as $rule) {
499: if (!is_string($op = $rule->operation)) {
500: $op = new Nette\Callback($op);
501: if (!$op->isStatic()) {
502: continue;
503: }
504: }
505: if ($rule->type === Rule::VALIDATOR) {
506: $item = array('op' => ($rule->isNegative ? '~' : '') . $op, 'msg' => $rules->formatMessage($rule, FALSE));
507:
508: } elseif ($rule->type === Rule::CONDITION) {
509: $item = array(
510: 'op' => ($rule->isNegative ? '~' : '') . $op,
511: 'rules' => self::exportRules($rule->subRules),
512: 'control' => $rule->control->getHtmlName()
513: );
514: if ($rule->subRules->getToggles()) {
515: $item['toggle'] = $rule->subRules->getToggles();
516: }
517: }
518:
519: if (is_array($rule->arg)) {
520: foreach ($rule->arg as $key => $value) {
521: $item['arg'][$key] = $value instanceof IControl ? (object) array('control' => $value->getHtmlName()) : $value;
522: }
523: } elseif ($rule->arg !== NULL) {
524: $item['arg'] = $rule->arg instanceof IControl ? (object) array('control' => $rule->arg->getHtmlName()) : $rule->arg;
525: }
526:
527: $payload[] = $item;
528: }
529: return $payload;
530: }
531:
532:
533:
534:
535:
536: 537: 538: 539:
540: public static function validateEqual(IControl $control, $arg)
541: {
542: $value = $control->getValue();
543: foreach ((is_array($value) ? $value : array($value)) as $val) {
544: foreach ((is_array($arg) ? $arg : array($arg)) as $item) {
545: if ((string) $val === (string) ($item instanceof IControl ? $item->value : $item)) {
546: return TRUE;
547: }
548: }
549: }
550: return FALSE;
551: }
552:
553:
554: 555: 556: 557:
558: public static function validateFilled(IControl $control)
559: {
560: return $control->isFilled();
561: }
562:
563:
564: 565: 566: 567:
568: public static function validateValid(IControl $control)
569: {
570: return $control->rules->validate(TRUE);
571: }
572:
573:
574: 575: 576: 577: 578:
579: public function addError($message)
580: {
581: if (!in_array($message, $this->errors, TRUE)) {
582: $this->errors[] = $message;
583: }
584: $this->getForm()->addError($message);
585: }
586:
587:
588: 589: 590: 591:
592: public function getErrors()
593: {
594: return $this->errors;
595: }
596:
597:
598: 599: 600:
601: public function hasErrors()
602: {
603: return (bool) $this->errors;
604: }
605:
606:
607: 608: 609:
610: public function cleanErrors()
611: {
612: $this->errors = array();
613: }
614:
615: }
616: