%PDF- %PDF-
Direktori : /www/varak.net/losik.varak.net/vendor/nette/forms/src/Forms/ |
Current File : /www/varak.net/losik.varak.net/vendor/nette/forms/src/Forms/Container.php |
<?php /** * This file is part of the Nette Framework (https://nette.org) * Copyright (c) 2004 David Grudl (https://davidgrudl.com) */ declare(strict_types=1); namespace Nette\Forms; use Nette; use Nette\Utils\ArrayHash; /** * Container for form controls. * * @property ArrayHash $values * @property-read \Iterator $controls * @property-read Form|null $form */ class Container extends Nette\ComponentModel\Container implements \ArrayAccess { use Nette\ComponentModel\ArrayAccess; private const Array = 'array'; /** * Occurs when the form was validated * @var array<callable(self, array|object): void|callable(array|object): void> */ public $onValidate = []; /** @var ControlGroup|null */ protected $currentGroup; /** @var callable[] extension methods */ private static $extMethods = []; /** @var ?bool */ private $validated = false; /** @var ?string */ private $mappedType; /********************* data exchange ****************d*g**/ /** * Fill-in with default values. * @param array|object $data * @return static */ public function setDefaults($data, bool $erase = false) { $form = $this->getForm(false); if (!$form || !$form->isAnchored() || !$form->isSubmitted()) { $this->setValues($data, $erase); } return $this; } /** * Fill-in with values. * @param array|object $data * @return static * @internal */ public function setValues($data, bool $erase = false) { if ($data instanceof \Traversable) { $values = iterator_to_array($data); } elseif (is_object($data) || is_array($data) || $data === null) { $values = (array) $data; } else { throw new Nette\InvalidArgumentException(sprintf('First parameter must be an array or object, %s given.', gettype($data))); } foreach ($this->getComponents() as $name => $control) { if ($control instanceof Control) { if (array_key_exists($name, $values)) { $control->setValue($values[$name]); } elseif ($erase) { $control->setValue(null); } } elseif ($control instanceof self) { if (array_key_exists($name, $values)) { $control->setValues($values[$name], $erase); } elseif ($erase) { $control->setValues([], $erase); } } } return $this; } /** * Returns the values submitted by the form. * @param string|object|null $returnType 'array' for array * @param Control[]|null $controls * @return object|array */ public function getValues($returnType = null, ?array $controls = null) { $form = $this->getForm(false); if ($form && ($submitter = $form->isSubmitted())) { if ($this->validated === null) { throw new Nette\InvalidStateException('You cannot call getValues() during the validation process. Use getUntrustedValues() instead.'); } elseif (!$this->isValid()) { trigger_error(__METHOD__ . "() invoked but the form is not valid (form '{$this->getName()}').", E_USER_WARNING); } if ($controls === null && $submitter instanceof SubmitterControl) { $controls = $submitter->getValidationScope(); } } $returnType = $returnType === true ? self::Array : $returnType; return $this->getUntrustedValues($returnType, $controls); } /** * Returns the potentially unvalidated values submitted by the form. * @param string|object|null $returnType 'array' for array * @param Control[]|null $controls * @return object|array */ public function getUntrustedValues($returnType = ArrayHash::class, ?array $controls = null) { if (is_object($returnType)) { $obj = $returnType; $rc = new \ReflectionClass($obj); } else { $returnType = ($returnType ?? $this->mappedType ?? ArrayHash::class); $rc = new \ReflectionClass($returnType === self::Array ? \stdClass::class : $returnType); if ($rc->hasMethod('__construct') && $rc->getMethod('__construct')->getNumberOfRequiredParameters()) { $obj = new \stdClass; $useConstructor = true; } else { $obj = $rc->newInstance(); } } foreach ($this->getComponents() as $name => $control) { $allowed = $controls === null || in_array($control, $controls, true); $name = (string) $name; if ( $control instanceof Control && $allowed && !$control->isOmitted() ) { $obj->$name = $control->getValue(); } elseif ($control instanceof self) { $type = $returnType === self::Array && !$control->mappedType ? self::Array : ($rc->hasProperty($name) ? Helpers::getSingleType($rc->getProperty($name)) : null); $obj->$name = $control->getUntrustedValues($type, $allowed ? null : $controls); } } if (isset($useConstructor)) { return new $returnType(...(array) $obj); } return $returnType === self::Array ? (array) $obj : $obj; } /** @eprecated use getUntrustedValues() */ public function getUnsafeValues($returnType, ?array $controls = null) { return $this->getUntrustedValues($returnType, $controls); } /** @return static */ public function setMappedType(string $type) { $this->mappedType = $type; return $this; } /********************* validation ****************d*g**/ /** * Is form valid? */ public function isValid(): bool { if ($this->validated === null) { throw new Nette\InvalidStateException('You cannot call isValid() during the validation process.'); } elseif (!$this->validated) { if ($this->getErrors()) { return false; } $this->validate(); } return !$this->getErrors(); } /** * Performs the server side validation. * @param Control[]|null $controls */ public function validate(?array $controls = null): void { $this->validated = null; foreach ($controls ?? $this->getComponents() as $control) { if ($control instanceof Control || $control instanceof self) { $control->validate(); } } $this->validated = true; foreach ($this->onValidate as $handler) { $params = Nette\Utils\Callback::toReflection($handler)->getParameters(); $types = array_map([Helpers::class, 'getSingleType'], $params); $args = isset($types[0]) && !$this instanceof $types[0] ? [$this->getUntrustedValues($types[0])] : [$this, isset($params[1]) ? $this->getUntrustedValues($types[1]) : null]; $handler(...$args); } } /** * Returns all validation errors. */ public function getErrors(): array { $errors = []; foreach ($this->getControls() as $control) { $errors = array_merge($errors, $control->getErrors()); } return array_unique($errors); } /********************* form building ****************d*g**/ /** @return static */ public function setCurrentGroup(?ControlGroup $group = null) { $this->currentGroup = $group; return $this; } /** * Returns current group. */ public function getCurrentGroup(): ?ControlGroup { return $this->currentGroup; } /** * Adds the specified component to the IContainer. * @return static * @throws Nette\InvalidStateException */ public function addComponent( Nette\ComponentModel\IComponent $component, ?string $name, ?string $insertBefore = null ) { parent::addComponent($component, $name, $insertBefore); if ($this->currentGroup !== null) { $this->currentGroup->add($component); } return $this; } /** * Iterates over all form controls. */ public function getControls(): \Iterator { return $this->getComponents(true, Control::class); } /** * Returns form. */ public function getForm(bool $throw = true): ?Form { return $this->lookup(Form::class, $throw); } /********************* control factories ****************d*g**/ /** * Adds single-line text input control to the form. * @param string|object $label */ public function addText(string $name, $label = null, ?int $cols = null, ?int $maxLength = null): Controls\TextInput { return $this[$name] = (new Controls\TextInput($label, $maxLength)) ->setHtmlAttribute('size', $cols); } /** * Adds single-line text input control used for sensitive input such as passwords. * @param string|object $label */ public function addPassword( string $name, $label = null, ?int $cols = null, ?int $maxLength = null ): Controls\TextInput { return $this[$name] = (new Controls\TextInput($label, $maxLength)) ->setHtmlAttribute('size', $cols) ->setHtmlType('password'); } /** * Adds multi-line text input control to the form. * @param string|object $label */ public function addTextArea(string $name, $label = null, ?int $cols = null, ?int $rows = null): Controls\TextArea { return $this[$name] = (new Controls\TextArea($label)) ->setHtmlAttribute('cols', $cols)->setHtmlAttribute('rows', $rows); } /** * Adds input for email. * @param string|object $label */ public function addEmail(string $name, $label = null): Controls\TextInput { return $this[$name] = (new Controls\TextInput($label)) ->addRule(Form::Email); } /** * Adds input for integer. * @param string|object $label */ public function addInteger(string $name, $label = null): Controls\TextInput { return $this[$name] = (new Controls\TextInput($label)) ->setNullable() ->addRule(Form::Integer); } /** * Adds control that allows the user to upload files. * @param string|object $label */ public function addUpload(string $name, $label = null): Controls\UploadControl { return $this[$name] = new Controls\UploadControl($label, false); } /** * Adds control that allows the user to upload multiple files. * @param string|object $label */ public function addMultiUpload(string $name, $label = null): Controls\UploadControl { return $this[$name] = new Controls\UploadControl($label, true); } /** * Adds hidden form control used to store a non-displayed value. */ public function addHidden(string $name, $default = null): Controls\HiddenField { return $this[$name] = (new Controls\HiddenField) ->setDefaultValue($default); } /** * Adds check box control to the form. * @param string|object $caption */ public function addCheckbox(string $name, $caption = null): Controls\Checkbox { return $this[$name] = new Controls\Checkbox($caption); } /** * Adds set of radio button controls to the form. * @param string|object $label */ public function addRadioList(string $name, $label = null, ?array $items = null): Controls\RadioList { return $this[$name] = new Controls\RadioList($label, $items); } /** * Adds set of checkbox controls to the form. * @param string|object $label */ public function addCheckboxList(string $name, $label = null, ?array $items = null): Controls\CheckboxList { return $this[$name] = new Controls\CheckboxList($label, $items); } /** * Adds select box control that allows single item selection. * @param string|object $label */ public function addSelect(string $name, $label = null, ?array $items = null, ?int $size = null): Controls\SelectBox { return $this[$name] = (new Controls\SelectBox($label, $items)) ->setHtmlAttribute('size', $size > 1 ? $size : null); } /** * Adds select box control that allows multiple item selection. * @param string|object $label */ public function addMultiSelect( string $name, $label = null, ?array $items = null, ?int $size = null ): Controls\MultiSelectBox { return $this[$name] = (new Controls\MultiSelectBox($label, $items)) ->setHtmlAttribute('size', $size > 1 ? $size : null); } /** * Adds button used to submit form. * @param string|object $caption */ public function addSubmit(string $name, $caption = null): Controls\SubmitButton { return $this[$name] = new Controls\SubmitButton($caption); } /** * Adds push buttons with no default behavior. * @param string|object $caption */ public function addButton(string $name, $caption = null): Controls\Button { return $this[$name] = new Controls\Button($caption); } /** * Adds graphical button used to submit form. * @param string $src URI of the image * @param string $alt alternate text for the image */ public function addImageButton(string $name, ?string $src = null, ?string $alt = null): Controls\ImageButton { return $this[$name] = new Controls\ImageButton($src, $alt); } /** @deprecated use addImageButton() */ public function addImage(): Controls\ImageButton { return $this->addImageButton(...func_get_args()); } /** * Adds naming container to the form. * @param string|int $name */ public function addContainer($name): self { $control = new self; $control->currentGroup = $this->currentGroup; if ($this->currentGroup !== null) { $this->currentGroup->add($control); } return $this[$name] = $control; } /********************* extension methods ****************d*g**/ public function __call(string $name, array $args) { if (isset(self::$extMethods[$name])) { return (self::$extMethods[$name])($this, ...$args); } return parent::__call($name, $args); } public static function extensionMethod(string $name, /*callable*/ $callback): void { if (strpos($name, '::') !== false) { // back compatibility [, $name] = explode('::', $name); } self::$extMethods[$name] = $callback; } /** * Prevents cloning. */ public function __clone() { throw new Nette\NotImplementedException('Form cloning is not supported yet.'); } }