PageRenderTime 45ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/vendor/nette/forms/src/Forms/Container.php

https://gitlab.com/kubinos/writeoff
PHP | 498 lines | 214 code | 86 blank | 198 comment | 19 complexity | 32b8ba9c0236a02b5046c6aabae8ff02 MD5 | raw file
  1. <?php
  2. /**
  3. * This file is part of the Nette Framework (https://nette.org)
  4. * Copyright (c) 2004 David Grudl (https://davidgrudl.com)
  5. */
  6. namespace Nette\Forms;
  7. use Nette;
  8. /**
  9. * Container for form controls.
  10. *
  11. * @property Nette\Utils\ArrayHash $values
  12. * @property-read \ArrayIterator $controls
  13. * @property-read Form $form
  14. */
  15. class Container extends Nette\ComponentModel\Container implements \ArrayAccess
  16. {
  17. /** @var callable[] function (Container $sender); Occurs when the form is validated */
  18. public $onValidate;
  19. /** @var ControlGroup */
  20. protected $currentGroup;
  21. /** @var bool */
  22. private $validated;
  23. /********************* data exchange ****************d*g**/
  24. /**
  25. * Fill-in with default values.
  26. * @param array|\Traversable values used to fill the form
  27. * @param bool erase other default values?
  28. * @return self
  29. */
  30. public function setDefaults($values, $erase = FALSE)
  31. {
  32. $form = $this->getForm(FALSE);
  33. if (!$form || !$form->isAnchored() || !$form->isSubmitted()) {
  34. $this->setValues($values, $erase);
  35. }
  36. return $this;
  37. }
  38. /**
  39. * Fill-in with values.
  40. * @param array|\Traversable values used to fill the form
  41. * @param bool erase other controls?
  42. * @return self
  43. */
  44. public function setValues($values, $erase = FALSE)
  45. {
  46. if ($values instanceof \Traversable) {
  47. $values = iterator_to_array($values);
  48. } elseif (!is_array($values)) {
  49. throw new Nette\InvalidArgumentException(sprintf('First parameter must be an array, %s given.', gettype($values)));
  50. }
  51. foreach ($this->getComponents() as $name => $control) {
  52. if ($control instanceof IControl) {
  53. if (array_key_exists($name, $values)) {
  54. $control->setValue($values[$name]);
  55. } elseif ($erase) {
  56. $control->setValue(NULL);
  57. }
  58. } elseif ($control instanceof self) {
  59. if (array_key_exists($name, $values)) {
  60. $control->setValues($values[$name], $erase);
  61. } elseif ($erase) {
  62. $control->setValues(array(), $erase);
  63. }
  64. }
  65. }
  66. return $this;
  67. }
  68. /**
  69. * Returns the values submitted by the form.
  70. * @param bool return values as an array?
  71. * @return Nette\Utils\ArrayHash|array
  72. */
  73. public function getValues($asArray = FALSE)
  74. {
  75. $values = $asArray ? array() : new Nette\Utils\ArrayHash;
  76. foreach ($this->getComponents() as $name => $control) {
  77. if ($control instanceof IControl && !$control->isOmitted()) {
  78. $values[$name] = $control->getValue();
  79. } elseif ($control instanceof self) {
  80. $values[$name] = $control->getValues($asArray);
  81. }
  82. }
  83. return $values;
  84. }
  85. /********************* validation ****************d*g**/
  86. /**
  87. * Is form valid?
  88. * @return bool
  89. */
  90. public function isValid()
  91. {
  92. if (!$this->validated) {
  93. if ($this->getErrors()) {
  94. return FALSE;
  95. }
  96. $this->validate();
  97. }
  98. return !$this->getErrors();
  99. }
  100. /**
  101. * Performs the server side validation.
  102. * @param IControl[]
  103. * @return void
  104. */
  105. public function validate(array $controls = NULL)
  106. {
  107. foreach ($controls === NULL ? $this->getComponents() : $controls as $control) {
  108. $control->validate();
  109. }
  110. if ($this->onValidate !== NULL) {
  111. if (!is_array($this->onValidate) && !$this->onValidate instanceof \Traversable) {
  112. throw new Nette\UnexpectedValueException('Property Form::$onValidate must be array or Traversable, ' . gettype($this->onValidate) . ' given.');
  113. }
  114. foreach ($this->onValidate as $handler) {
  115. $params = Nette\Utils\Callback::toReflection($handler)->getParameters();
  116. $values = isset($params[1]) ? $this->getValues($params[1]->isArray()) : NULL;
  117. Nette\Utils\Callback::invoke($handler, $this, $values);
  118. }
  119. }
  120. $this->validated = TRUE;
  121. }
  122. /**
  123. * Returns all validation errors.
  124. * @return array
  125. */
  126. public function getErrors()
  127. {
  128. $errors = array();
  129. foreach ($this->getControls() as $control) {
  130. $errors = array_merge($errors, $control->getErrors());
  131. }
  132. return array_unique($errors);
  133. }
  134. /********************* form building ****************d*g**/
  135. /**
  136. * @return self
  137. */
  138. public function setCurrentGroup(ControlGroup $group = NULL)
  139. {
  140. $this->currentGroup = $group;
  141. return $this;
  142. }
  143. /**
  144. * Returns current group.
  145. * @return ControlGroup
  146. */
  147. public function getCurrentGroup()
  148. {
  149. return $this->currentGroup;
  150. }
  151. /**
  152. * Adds the specified component to the IContainer.
  153. * @param Nette\ComponentModel\IComponent
  154. * @param string
  155. * @param string
  156. * @return self
  157. * @throws Nette\InvalidStateException
  158. */
  159. public function addComponent(Nette\ComponentModel\IComponent $component, $name, $insertBefore = NULL)
  160. {
  161. parent::addComponent($component, $name, $insertBefore);
  162. if ($this->currentGroup !== NULL && $component instanceof IControl) {
  163. $this->currentGroup->add($component);
  164. }
  165. return $this;
  166. }
  167. /**
  168. * Iterates over all form controls.
  169. * @return \ArrayIterator
  170. */
  171. public function getControls()
  172. {
  173. return $this->getComponents(TRUE, 'Nette\Forms\IControl');
  174. }
  175. /**
  176. * Returns form.
  177. * @param bool throw exception if form doesn't exist?
  178. * @return Form
  179. */
  180. public function getForm($need = TRUE)
  181. {
  182. return $this->lookup('Nette\Forms\Form', $need);
  183. }
  184. /********************* control factories ****************d*g**/
  185. /**
  186. * Adds single-line text input control to the form.
  187. * @param string control name
  188. * @param string label
  189. * @param int width of the control (deprecated)
  190. * @param int maximum number of characters the user may enter
  191. * @return Nette\Forms\Controls\TextInput
  192. */
  193. public function addText($name, $label = NULL, $cols = NULL, $maxLength = NULL)
  194. {
  195. $control = new Controls\TextInput($label, $maxLength);
  196. $control->setAttribute('size', $cols);
  197. return $this[$name] = $control;
  198. }
  199. /**
  200. * Adds single-line text input control used for sensitive input such as passwords.
  201. * @param string control name
  202. * @param string label
  203. * @param int width of the control (deprecated)
  204. * @param int maximum number of characters the user may enter
  205. * @return Nette\Forms\Controls\TextInput
  206. */
  207. public function addPassword($name, $label = NULL, $cols = NULL, $maxLength = NULL)
  208. {
  209. $control = new Controls\TextInput($label, $maxLength);
  210. $control->setAttribute('size', $cols);
  211. return $this[$name] = $control->setType('password');
  212. }
  213. /**
  214. * Adds multi-line text input control to the form.
  215. * @param string control name
  216. * @param string label
  217. * @param int width of the control
  218. * @param int height of the control in text lines
  219. * @return Nette\Forms\Controls\TextArea
  220. */
  221. public function addTextArea($name, $label = NULL, $cols = NULL, $rows = NULL)
  222. {
  223. $control = new Controls\TextArea($label);
  224. $control->setAttribute('cols', $cols)->setAttribute('rows', $rows);
  225. return $this[$name] = $control;
  226. }
  227. /**
  228. * Adds control that allows the user to upload files.
  229. * @param string control name
  230. * @param string label
  231. * @param bool allows to upload multiple files
  232. * @return Nette\Forms\Controls\UploadControl
  233. */
  234. public function addUpload($name, $label = NULL, $multiple = FALSE)
  235. {
  236. return $this[$name] = new Controls\UploadControl($label, $multiple);
  237. }
  238. /**
  239. * Adds control that allows the user to upload multiple files.
  240. * @param string control name
  241. * @param string label
  242. * @return Nette\Forms\Controls\UploadControl
  243. */
  244. public function addMultiUpload($name, $label = NULL)
  245. {
  246. return $this[$name] = new Controls\UploadControl($label, TRUE);
  247. }
  248. /**
  249. * Adds hidden form control used to store a non-displayed value.
  250. * @param string control name
  251. * @param mixed default value
  252. * @return Nette\Forms\Controls\HiddenField
  253. */
  254. public function addHidden($name, $default = NULL)
  255. {
  256. $control = new Controls\HiddenField;
  257. $control->setDefaultValue($default);
  258. return $this[$name] = $control;
  259. }
  260. /**
  261. * Adds check box control to the form.
  262. * @param string control name
  263. * @param string caption
  264. * @return Nette\Forms\Controls\Checkbox
  265. */
  266. public function addCheckbox($name, $caption = NULL)
  267. {
  268. return $this[$name] = new Controls\Checkbox($caption);
  269. }
  270. /**
  271. * Adds set of radio button controls to the form.
  272. * @param string control name
  273. * @param string label
  274. * @param array options from which to choose
  275. * @return Nette\Forms\Controls\RadioList
  276. */
  277. public function addRadioList($name, $label = NULL, array $items = NULL)
  278. {
  279. return $this[$name] = new Controls\RadioList($label, $items);
  280. }
  281. /**
  282. * Adds set of checkbox controls to the form.
  283. * @return Nette\Forms\Controls\CheckboxList
  284. */
  285. public function addCheckboxList($name, $label = NULL, array $items = NULL)
  286. {
  287. return $this[$name] = new Controls\CheckboxList($label, $items);
  288. }
  289. /**
  290. * Adds select box control that allows single item selection.
  291. * @param string control name
  292. * @param string label
  293. * @param array items from which to choose
  294. * @param int number of rows that should be visible
  295. * @return Nette\Forms\Controls\SelectBox
  296. */
  297. public function addSelect($name, $label = NULL, array $items = NULL, $size = NULL)
  298. {
  299. $control = new Controls\SelectBox($label, $items);
  300. if ($size > 1) {
  301. $control->setAttribute('size', (int) $size);
  302. }
  303. return $this[$name] = $control;
  304. }
  305. /**
  306. * Adds select box control that allows multiple item selection.
  307. * @param string control name
  308. * @param string label
  309. * @param array options from which to choose
  310. * @param int number of rows that should be visible
  311. * @return Nette\Forms\Controls\MultiSelectBox
  312. */
  313. public function addMultiSelect($name, $label = NULL, array $items = NULL, $size = NULL)
  314. {
  315. $control = new Controls\MultiSelectBox($label, $items);
  316. if ($size > 1) {
  317. $control->setAttribute('size', (int) $size);
  318. }
  319. return $this[$name] = $control;
  320. }
  321. /**
  322. * Adds button used to submit form.
  323. * @param string control name
  324. * @param string caption
  325. * @return Nette\Forms\Controls\SubmitButton
  326. */
  327. public function addSubmit($name, $caption = NULL)
  328. {
  329. return $this[$name] = new Controls\SubmitButton($caption);
  330. }
  331. /**
  332. * Adds push buttons with no default behavior.
  333. * @param string control name
  334. * @param string caption
  335. * @return Nette\Forms\Controls\Button
  336. */
  337. public function addButton($name, $caption = NULL)
  338. {
  339. return $this[$name] = new Controls\Button($caption);
  340. }
  341. /**
  342. * Adds graphical button used to submit form.
  343. * @param string control name
  344. * @param string URI of the image
  345. * @param string alternate text for the image
  346. * @return Nette\Forms\Controls\ImageButton
  347. */
  348. public function addImage($name, $src = NULL, $alt = NULL)
  349. {
  350. return $this[$name] = new Controls\ImageButton($src, $alt);
  351. }
  352. /**
  353. * Adds naming container to the form.
  354. * @param string name
  355. * @return Container
  356. */
  357. public function addContainer($name)
  358. {
  359. $control = new self;
  360. $control->currentGroup = $this->currentGroup;
  361. return $this[$name] = $control;
  362. }
  363. /********************* interface \ArrayAccess ****************d*g**/
  364. /**
  365. * Adds the component to the container.
  366. * @param string component name
  367. * @param Nette\ComponentModel\IComponent
  368. * @return void
  369. */
  370. public function offsetSet($name, $component)
  371. {
  372. $this->addComponent($component, $name);
  373. }
  374. /**
  375. * Returns component specified by name. Throws exception if component doesn't exist.
  376. * @param string component name
  377. * @return Nette\ComponentModel\IComponent
  378. * @throws Nette\InvalidArgumentException
  379. */
  380. public function offsetGet($name)
  381. {
  382. return $this->getComponent($name, TRUE);
  383. }
  384. /**
  385. * Does component specified by name exists?
  386. * @param string component name
  387. * @return bool
  388. */
  389. public function offsetExists($name)
  390. {
  391. return $this->getComponent($name, FALSE) !== NULL;
  392. }
  393. /**
  394. * Removes component from the container.
  395. * @param string component name
  396. * @return void
  397. */
  398. public function offsetUnset($name)
  399. {
  400. $component = $this->getComponent($name, FALSE);
  401. if ($component !== NULL) {
  402. $this->removeComponent($component);
  403. }
  404. }
  405. /**
  406. * Prevents cloning.
  407. */
  408. public function __clone()
  409. {
  410. throw new Nette\NotImplementedException('Form cloning is not supported yet.');
  411. }
  412. }