PageRenderTime 54ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 0ms

/sally/core/lib/sly/Form.php

https://bitbucket.org/SallyCMS/trunk
PHP | 454 lines | 170 code | 46 blank | 238 comment | 11 complexity | 71500e7a86388e32aaedeab874fce176 MD5 | raw file
  1. <?php
  2. /*
  3. * Copyright (c) 2012, webvariants GbR, http://www.webvariants.de
  4. *
  5. * This file is released under the terms of the MIT license. You can find the
  6. * complete text in the attached LICENSE file or online at:
  7. *
  8. * http://www.opensource.org/licenses/mit-license.php
  9. */
  10. /**
  11. * A backend form
  12. *
  13. * This class renders the normal backend form, used on many Sally pages. The
  14. * form consists of multiple fieldsets (beginning with a implicitly created one)
  15. * and can also contain hidden values. It also supports direct access to all
  16. * relevant four buttons (submit, reset, delete, apply).
  17. *
  18. * If you want to build you own form, this is the class you want to use.
  19. *
  20. * @see http://docs.webvariants.de/sallycms/latest/sallycms/forms/index.html
  21. * @ingroup form
  22. * @author Christoph
  23. */
  24. class sly_Form extends sly_Form_Base {
  25. protected $action; ///< string
  26. protected $method; ///< string
  27. protected $title; ///< string
  28. protected $name; ///< string
  29. protected $id; ///< string
  30. protected $classes; ///< array
  31. protected $enctype; ///< string
  32. protected $submitButton; ///< sly_Form_Input_Button
  33. protected $resetButton; ///< sly_Form_Input_Button
  34. protected $deleteButton; ///< sly_Form_Input_Button
  35. protected $applyButton; ///< sly_Form_Input_Button
  36. protected $fieldsets; ///< array
  37. protected $currentFieldset; ///< sly_Form_Fieldset
  38. protected $focussedElement; ///< string
  39. protected $buttonClasses; ///< array
  40. protected $addCsrfToken; ///< boolean
  41. /**
  42. * Constructor
  43. *
  44. * Creates a new form and the first fieldset. It also sets up the submit and
  45. * reset button.
  46. *
  47. * @param string $action the action (in most cases, a URL like 'index.php')
  48. * @param string $method the HTTP method (GET or POST)
  49. * @param string $title the form title (is the title of the first fieldset)
  50. * @param string $name the form name (optional)
  51. * @param string $id the form ID (optional)
  52. */
  53. public function __construct($action, $method, $title, $name = '', $id = '') {
  54. $this->action = $action;
  55. $this->method = strtoupper($method) === 'GET' ? 'GET' : 'POST';
  56. $this->title = $title;
  57. $this->name = $name;
  58. $this->id = $id;
  59. $this->enctype = false;
  60. $this->classes = array();
  61. $this->submitButton = new sly_Form_Input_Button('submit', 'submit', t('save'));
  62. $this->resetButton = new sly_Form_Input_Button('reset', 'reset', t('reset'));
  63. $this->deleteButton = null;
  64. $this->applyButton = null;
  65. $this->hiddenValues = array();
  66. $this->fieldsets = array();
  67. $this->currentFieldset = null;
  68. $this->focussedElement = '';
  69. $this->buttonClasses = array('submit' => array('sly-form-submit'), 'reset' => array(), 'delete' => array('sly-form-submit'), 'apply' => array('sly-form-submit'));
  70. $this->addCsrfToken = true;
  71. }
  72. /**
  73. * Get the form's method (GET or POST)
  74. *
  75. * @return string the method
  76. */
  77. public function getMethod() {
  78. return $this->method;
  79. }
  80. /**
  81. * Set the encoding
  82. *
  83. * Use this method to alter the encoding, for example when you use the form
  84. * to upload files.
  85. *
  86. * @param string $enctype the new enctype
  87. * @return sly_Form the current object
  88. */
  89. public function setEncType($enctype) {
  90. $this->enctype = trim($enctype);
  91. return $this;
  92. }
  93. /**
  94. * Start a new fieldset
  95. *
  96. * This method creates a new fieldset, appends it to the form and marks it
  97. * as active (that means that new elements will be appended to this one).
  98. * The fieldset can use more than one column, independently from the other
  99. * fieldsets in this form. Note that fieldsets with more than one column
  100. * cannot contain multilingual form elements (because the XHTML would be
  101. * so darn complex, that we just disabled this option).
  102. *
  103. * @param string $title the fieldset title
  104. * @param string $id the HTML id
  105. * @param int $columns the number of columns
  106. * @return sly_Form_Fieldset the newly created fieldset
  107. */
  108. public function beginFieldset($title, $id = null, $columns = 1) {
  109. $this->currentFieldset = new sly_Form_Fieldset($title, $id, $columns);
  110. $this->fieldsets[] = $this->currentFieldset;
  111. return $this->currentFieldset;
  112. }
  113. /**
  114. * Adds a new row of elements
  115. *
  116. * This method will add a new row to the currently active fieldset. In most
  117. * cases, this is the last one, that has been created.
  118. *
  119. * @param array $row the array of form elements
  120. * @return sly_Form the current object
  121. */
  122. public function addRow(array $row) {
  123. if ($this->currentFieldset === null) {
  124. $this->beginFieldset($this->title);
  125. }
  126. $this->currentFieldset->addRow($row);
  127. return $this;
  128. }
  129. /**
  130. * Adds a new fieldset
  131. *
  132. * This methods just adds a new fieldset to the form and marks it as active.
  133. *
  134. * @param sly_Form_Fieldset $fieldset the fieldset to add
  135. * @return sly_Form the current object
  136. */
  137. public function addFieldset(sly_Form_Fieldset $fieldset) {
  138. $this->fieldsets[] = $fieldset;
  139. $this->currentFieldset = null;
  140. return $this;
  141. }
  142. /**
  143. * Set the submit button
  144. *
  145. * This method allows access to the special submit button. Use it to
  146. * overwrite the default button with your own (giving a new button) or to
  147. * remove the button (giving null).
  148. *
  149. * @param sly_Form_Input_Button $submitButton the new submit button
  150. * @return sly_Form the current object
  151. */
  152. public function setSubmitButton(sly_Form_Input_Button $submitButton = null) {
  153. $this->submitButton = $submitButton;
  154. return $this;
  155. }
  156. /**
  157. * Set the reset button
  158. *
  159. * This method allows access to the special reset button. Use it to
  160. * overwrite the default button with your own (giving a new button) or to
  161. * remove the button (giving null).
  162. *
  163. * @param sly_Form_Input_Button $resetButton the new reset button
  164. * @return sly_Form the current object
  165. */
  166. public function setResetButton(sly_Form_Input_Button $resetButton = null) {
  167. $this->resetButton = $resetButton;
  168. return $this;
  169. }
  170. /**
  171. * Set the apply button
  172. *
  173. * This method allows access to the special apply button. Use it to
  174. * overwrite the default button with your own (giving a new button) or to
  175. * remove the button (giving null).
  176. * This button does not exist by default.
  177. *
  178. * @param sly_Form_Input_Button $applyButton the new apply button
  179. * @return sly_Form the current object
  180. */
  181. public function setApplyButton(sly_Form_Input_Button $applyButton = null) {
  182. $this->applyButton = $applyButton;
  183. return $this;
  184. }
  185. /**
  186. * Set the delete button
  187. *
  188. * This method allows access to the special delete button. Use it to
  189. * overwrite the default button with your own (giving a new button) or to
  190. * remove the button (giving null).
  191. * This button does not exist by default.
  192. *
  193. * @param sly_Form_Input_Button $deleteButton the new delete button
  194. * @return sly_Form the current object
  195. */
  196. public function setDeleteButton(sly_Form_Input_Button $deleteButton = null) {
  197. $this->deleteButton = $deleteButton;
  198. return $this;
  199. }
  200. /**
  201. * Returns the submit button
  202. *
  203. * @return sly_Form_Input_Button the submit button
  204. */
  205. public function getSubmitButton() {
  206. return $this->submitButton;
  207. }
  208. /**
  209. * Returns the reset button
  210. *
  211. * @return sly_Form_Input_Button the reset button
  212. */
  213. public function getResetButton() {
  214. return $this->resetButton;
  215. }
  216. /**
  217. * Returns the apply button
  218. *
  219. * @return sly_Form_Input_Button the apply button
  220. */
  221. public function getApplyButton() {
  222. return $this->applyButton;
  223. }
  224. /**
  225. * Returns the delete button
  226. *
  227. * @return sly_Form_Input_Button the delete button
  228. */
  229. public function getDeleteButton() {
  230. return $this->deleteButton;
  231. }
  232. /**
  233. * Adds a new CSS class to a button
  234. *
  235. * This methods adds a class to a specific button. $type can be 'submit',
  236. * 'reset', 'delete' or 'apply'. The list of classes per type will be unique.
  237. *
  238. * @param string $type the button type (submit, reset, delete or apply)
  239. * @param string $class the new CSS class
  240. * @return sly_Form the current object
  241. */
  242. public function addButtonClass($type, $class) {
  243. $this->buttonClasses[$type][] = trim($class);
  244. $this->buttonClasses[$type] = array_unique($this->buttonClasses[$type]);
  245. return $this;
  246. }
  247. /**
  248. * Render the form
  249. *
  250. * Renders the form and returns its content.
  251. *
  252. * @param boolean $omitFormTag set this to true if you want to use your own <form> tag
  253. * @param sly_Request $request the request to use or null for the global one
  254. * @return string the generated XHTML
  255. */
  256. public function render($omitFormTag = false, sly_Request $request = null) {
  257. if ($this->addCsrfToken) {
  258. sly_Util_Csrf::prepareForm($this);
  259. }
  260. $request = $request ? $request : sly_Core::getRequest();
  261. return $this->renderView('form.phtml', array('form' => $this, 'omitFormTag' => $omitFormTag, 'request' => $request));
  262. }
  263. /**
  264. * Remove all elements
  265. *
  266. * This method will remove all fieldsets from the form and reset the active
  267. * fieldset to 'none'. This will make any add* method create a new fieldset
  268. * when called.
  269. *
  270. * @return sly_Form the current object
  271. */
  272. public function clearElements() {
  273. $this->fieldsets = array();
  274. $this->currentFieldset = null;
  275. return $this;
  276. }
  277. /**
  278. * Sets the focus
  279. *
  280. * This method sets the focus to one element, generating a bit of jQuery code
  281. * to set the cursor to it when the form is rendered.
  282. *
  283. * @param mixed $element the instance or ID of the element to focus
  284. * @return sly_Form the current object
  285. */
  286. public function setFocus($element) {
  287. $this->focussedElement = $element;
  288. return $this;
  289. }
  290. /**
  291. * Get the current fieldset
  292. *
  293. * @return sly_Form_Fieldset the current fieldset (or null after the form has been created or cleared)
  294. */
  295. public function getCurrentFieldset() {
  296. return $this->currentFieldset;
  297. }
  298. /**
  299. * Get all fieldsets
  300. *
  301. * @return array list of all fieldsets
  302. */
  303. public function getFieldsets() {
  304. return $this->fieldsets;
  305. }
  306. /**
  307. * Get element by name
  308. *
  309. * @param string $name the element's name
  310. * @return sly_Form_IElement the found element or null
  311. */
  312. public function findElementByName($name) {
  313. return $this->findElement('name', $name);
  314. }
  315. /**
  316. * Get element by ID
  317. *
  318. * @param string $name the element's ID
  319. * @return sly_Form_IElement the found element or null
  320. */
  321. public function findElementByID($id) {
  322. return $this->findElement('id', $id);
  323. }
  324. /**
  325. * Get element by name
  326. *
  327. * @param string $criterium 'id' or 'name'
  328. * @param string $value the value to find
  329. * @return sly_Form_IElement the found element or null
  330. */
  331. protected function findElement($criterium, $value) {
  332. foreach ($this->fieldsets as $fieldset) {
  333. foreach ($fieldset->getRows() as $row) {
  334. foreach ($row as $element) {
  335. if ($element instanceof sly_Form_IElement) {
  336. if ($criterium === 'name' && $element->getName() === $value) return $element;
  337. if ($criterium === 'id' && $element->getID() === $value) return $element;
  338. }
  339. }
  340. }
  341. }
  342. return null;
  343. }
  344. /**
  345. * Replace an existing element
  346. *
  347. * @param string $criterium 'id' or 'name'
  348. * @param string $value the value to find
  349. * @param sly_Form_IElement the new element
  350. * @return sly_Form_IElement the replaced element or null if not found
  351. */
  352. public function replaceElement($criterium, $value, sly_Form_IElement $element) {
  353. foreach ($this->fieldsets as $fIdx => $fieldset) {
  354. foreach ($fieldset->getRows() as $rowIdx => $row) {
  355. foreach ($row as $elemIdx => $elem) {
  356. if ($elem instanceof sly_Form_IElement) {
  357. if (
  358. ($criterium === 'name' && $elem->getName() === $value) ||
  359. ($criterium === 'id' && $elem->getID() === $value)
  360. ) {
  361. return $fieldset->replaceElement($rowIdx, $elemIdx, $element);
  362. }
  363. }
  364. }
  365. }
  366. }
  367. return null;
  368. }
  369. /**
  370. * Add a new class to the form
  371. *
  372. * This method will add a CSS class to the form tag. You can give mutliple
  373. * classes at once, the method will split them up and add them one at a time,
  374. * ensuring that they are unique.
  375. *
  376. * @param string $class the CSS class
  377. * @return sly_Form the current object
  378. */
  379. public function addClass($class) {
  380. $class = explode(' ', $class);
  381. foreach ($class as $c) $this->classes[] = $c;
  382. $this->classes = array_unique($this->classes);
  383. return $this;
  384. }
  385. /**
  386. * Remove all classes
  387. *
  388. * This method removes all set CSS classes for this form.
  389. *
  390. * @return sly_Form the current object
  391. */
  392. public function clearClasses() {
  393. $this->classes = array();
  394. return $this;
  395. }
  396. /**
  397. * Get all classes
  398. *
  399. * @return array the list of CSS classes for this form
  400. */
  401. public function getClasses() {
  402. return $this->classes;
  403. }
  404. public function setCsrfEnabled($flag = true) {
  405. $this->addCsrfToken = (boolean) $flag;
  406. return $this;
  407. }
  408. }