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