1: <?php
2:
3: 4: 5: 6:
7:
8: namespace Nette\Forms;
9:
10: use Nette;
11:
12:
13: 14: 15: 16: 17: 18: 19:
20: class Container extends Nette\ComponentModel\Container implements \ArrayAccess
21: {
22:
23: public $onValidate;
24:
25:
26: protected $currentGroup;
27:
28:
29: private $validated;
30:
31:
32:
33:
34:
35: 36: 37: 38: 39: 40:
41: public function setDefaults($values, $erase = FALSE)
42: {
43: $form = $this->getForm(FALSE);
44: if (!$form || !$form->isAnchored() || !$form->isSubmitted()) {
45: $this->setValues($values, $erase);
46: }
47: return $this;
48: }
49:
50:
51: 52: 53: 54: 55: 56: 57:
58: public function setValues($values, $erase = FALSE)
59: {
60: if ($values instanceof \Traversable) {
61: $values = iterator_to_array($values);
62:
63: } elseif (!is_array($values)) {
64: throw new Nette\InvalidArgumentException(sprintf('First parameter must be an array, %s given.', gettype($values)));
65: }
66:
67: foreach ($this->getComponents() as $name => $control) {
68: if ($control instanceof IControl) {
69: if (array_key_exists($name, $values)) {
70: $control->setValue($values[$name]);
71:
72: } elseif ($erase) {
73: $control->setValue(NULL);
74: }
75:
76: } elseif ($control instanceof self) {
77: if (array_key_exists($name, $values)) {
78: $control->setValues($values[$name], $erase);
79:
80: } elseif ($erase) {
81: $control->setValues([], $erase);
82: }
83: }
84: }
85: return $this;
86: }
87:
88:
89: 90: 91: 92: 93:
94: public function getValues($asArray = FALSE)
95: {
96: $values = $asArray ? [] : new Nette\Utils\ArrayHash;
97: foreach ($this->getComponents() as $name => $control) {
98: if ($control instanceof IControl && !$control->isOmitted()) {
99: $values[$name] = $control->getValue();
100:
101: } elseif ($control instanceof self) {
102: $values[$name] = $control->getValues($asArray);
103: }
104: }
105: return $values;
106: }
107:
108:
109:
110:
111:
112: 113: 114: 115:
116: public function isValid()
117: {
118: if (!$this->validated) {
119: if ($this->getErrors()) {
120: return FALSE;
121: }
122: $this->validate();
123: }
124: return !$this->getErrors();
125: }
126:
127:
128: 129: 130: 131: 132:
133: public function validate(array $controls = NULL)
134: {
135: foreach ($controls === NULL ? $this->getComponents() : $controls as $control) {
136: if ($control instanceof IControl || $control instanceof self) {
137: $control->validate();
138: }
139: }
140: if ($this->onValidate !== NULL) {
141: if (!is_array($this->onValidate) && !$this->onValidate instanceof \Traversable) {
142: throw new Nette\UnexpectedValueException('Property Form::$onValidate must be array or Traversable, ' . gettype($this->onValidate) . ' given.');
143: }
144: foreach ($this->onValidate as $handler) {
145: $params = Nette\Utils\Callback::toReflection($handler)->getParameters();
146: $values = isset($params[1]) ? $this->getValues($params[1]->isArray()) : NULL;
147: Nette\Utils\Callback::invoke($handler, $this, $values);
148: }
149: }
150: $this->validated = TRUE;
151: }
152:
153:
154: 155: 156: 157:
158: public function getErrors()
159: {
160: $errors = [];
161: foreach ($this->getControls() as $control) {
162: $errors = array_merge($errors, $control->getErrors());
163: }
164: return array_unique($errors);
165: }
166:
167:
168:
169:
170:
171: 172: 173:
174: public function setCurrentGroup(ControlGroup $group = NULL)
175: {
176: $this->currentGroup = $group;
177: return $this;
178: }
179:
180:
181: 182: 183: 184:
185: public function getCurrentGroup()
186: {
187: return $this->currentGroup;
188: }
189:
190:
191: 192: 193: 194: 195: 196: 197: 198:
199: public function addComponent(Nette\ComponentModel\IComponent $component, $name, $insertBefore = NULL)
200: {
201: parent::addComponent($component, $name, $insertBefore);
202: if ($this->currentGroup !== NULL) {
203: $this->currentGroup->add($component);
204: }
205: return $this;
206: }
207:
208:
209: 210: 211: 212:
213: public function getControls()
214: {
215: return $this->getComponents(TRUE, IControl::class);
216: }
217:
218:
219: 220: 221: 222: 223:
224: public function getForm($need = TRUE)
225: {
226: return $this->lookup(Form::class, $need);
227: }
228:
229:
230:
231:
232:
233: 234: 235: 236: 237: 238: 239: 240:
241: public function addText($name, $label = NULL, $cols = NULL, $maxLength = NULL)
242: {
243: return $this[$name] = (new Controls\TextInput($label, $maxLength))
244: ->setAttribute('size', $cols);
245: }
246:
247:
248: 249: 250: 251: 252: 253: 254: 255:
256: public function addPassword($name, $label = NULL, $cols = NULL, $maxLength = NULL)
257: {
258: return $this[$name] = (new Controls\TextInput($label, $maxLength))
259: ->setAttribute('size', $cols)
260: ->setType('password');
261: }
262:
263:
264: 265: 266: 267: 268: 269: 270: 271:
272: public function addTextArea($name, $label = NULL, $cols = NULL, $rows = NULL)
273: {
274: return $this[$name] = (new Controls\TextArea($label))
275: ->setAttribute('cols', $cols)->setAttribute('rows', $rows);
276: }
277:
278:
279: 280: 281: 282: 283: 284:
285: public function addEmail($name, $label = NULL)
286: {
287: return $this[$name] = (new Controls\TextInput($label))
288: ->setRequired(FALSE)
289: ->addRule(Form::EMAIL);
290: }
291:
292:
293: 294: 295: 296: 297: 298:
299: public function addInteger($name, $label = NULL)
300: {
301: return $this[$name] = (new Controls\TextInput($label))
302: ->setNullable()
303: ->setRequired(FALSE)
304: ->addRule(Form::INTEGER);
305: }
306:
307:
308: 309: 310: 311: 312: 313: 314:
315: public function addUpload($name, $label = NULL, $multiple = FALSE)
316: {
317: return $this[$name] = new Controls\UploadControl($label, $multiple);
318: }
319:
320:
321: 322: 323: 324: 325: 326:
327: public function addMultiUpload($name, $label = NULL)
328: {
329: return $this[$name] = new Controls\UploadControl($label, TRUE);
330: }
331:
332:
333: 334: 335: 336: 337: 338:
339: public function addHidden($name, $default = NULL)
340: {
341: return $this[$name] = (new Controls\HiddenField)
342: ->setDefaultValue($default);
343: }
344:
345:
346: 347: 348: 349: 350: 351:
352: public function addCheckbox($name, $caption = NULL)
353: {
354: return $this[$name] = new Controls\Checkbox($caption);
355: }
356:
357:
358: 359: 360: 361: 362: 363: 364:
365: public function addRadioList($name, $label = NULL, array $items = NULL)
366: {
367: return $this[$name] = new Controls\RadioList($label, $items);
368: }
369:
370:
371: 372: 373: 374:
375: public function addCheckboxList($name, $label = NULL, array $items = NULL)
376: {
377: return $this[$name] = new Controls\CheckboxList($label, $items);
378: }
379:
380:
381: 382: 383: 384: 385: 386: 387: 388:
389: public function addSelect($name, $label = NULL, array $items = NULL, $size = NULL)
390: {
391: return $this[$name] = (new Controls\SelectBox($label, $items))
392: ->setAttribute('size', $size > 1 ? (int) $size : NULL);
393: }
394:
395:
396: 397: 398: 399: 400: 401: 402: 403:
404: public function addMultiSelect($name, $label = NULL, array $items = NULL, $size = NULL)
405: {
406: return $this[$name] = (new Controls\MultiSelectBox($label, $items))
407: ->setAttribute('size', $size > 1 ? (int) $size : NULL);
408: }
409:
410:
411: 412: 413: 414: 415: 416:
417: public function addSubmit($name, $caption = NULL)
418: {
419: return $this[$name] = new Controls\SubmitButton($caption);
420: }
421:
422:
423: 424: 425: 426: 427: 428:
429: public function addButton($name, $caption = NULL)
430: {
431: return $this[$name] = new Controls\Button($caption);
432: }
433:
434:
435: 436: 437: 438: 439: 440: 441:
442: public function addImage($name, $src = NULL, $alt = NULL)
443: {
444: return $this[$name] = new Controls\ImageButton($src, $alt);
445: }
446:
447:
448: 449: 450: 451: 452:
453: public function addContainer($name)
454: {
455: $control = new self;
456: $control->currentGroup = $this->currentGroup;
457: if ($this->currentGroup !== NULL) {
458: $this->currentGroup->add($control);
459: }
460: return $this[$name] = $control;
461: }
462:
463:
464:
465:
466:
467: public function __call($name, $args)
468: {
469: if ($callback = Nette\Utils\ObjectMixin::getExtensionMethod(__CLASS__, $name)) {
470: return Nette\Utils\Callback::invoke($callback, $this, ...$args);
471: }
472: return parent::__call($name, $args);
473: }
474:
475:
476: public static function extensionMethod($name, $callback = NULL)
477: {
478: if (strpos($name, '::') !== FALSE) {
479: list(, $name) = explode('::', $name);
480: }
481: Nette\Utils\ObjectMixin::setExtensionMethod(__CLASS__, $name, $callback);
482: }
483:
484:
485:
486:
487:
488: 489: 490: 491: 492: 493:
494: public function offsetSet($name, $component)
495: {
496: $this->addComponent($component, $name);
497: }
498:
499:
500: 501: 502: 503: 504: 505:
506: public function offsetGet($name)
507: {
508: return $this->getComponent($name, TRUE);
509: }
510:
511:
512: 513: 514: 515: 516:
517: public function offsetExists($name)
518: {
519: return $this->getComponent($name, FALSE) !== NULL;
520: }
521:
522:
523: 524: 525: 526: 527:
528: public function offsetUnset($name)
529: {
530: $component = $this->getComponent($name, FALSE);
531: if ($component !== NULL) {
532: $this->removeComponent($component);
533: }
534: }
535:
536:
537: 538: 539:
540: public function __clone()
541: {
542: throw new Nette\NotImplementedException('Form cloning is not supported yet.');
543: }
544:
545: }
546: