diff options
author | vipsoft <vipsoft@59fd770c-687e-43c8-a1e3-f5a4ff64c105> | 2010-07-06 21:28:27 +0400 |
---|---|---|
committer | vipsoft <vipsoft@59fd770c-687e-43c8-a1e3-f5a4ff64c105> | 2010-07-06 21:28:27 +0400 |
commit | adb9a40abd2c4049c5fc7bcd15692f8d3957774c (patch) | |
tree | 46629aa66fb5f130b5eed07902f3930d8404d25c /libs | |
parent | 27961c62ce494b0e2e5a3b022202fd820425a4e4 (diff) |
refs #1442 - add HTML_Common2 and HTML_QuickForm2 - New BSD licensed
Diffstat (limited to 'libs')
62 files changed, 11883 insertions, 0 deletions
diff --git a/libs/HTML/Common2.php b/libs/HTML/Common2.php new file mode 100644 index 0000000000..0228889b12 --- /dev/null +++ b/libs/HTML/Common2.php @@ -0,0 +1,488 @@ +<?php +/** + * HTML_Common2: port of HTML_Common package to PHP5 + * + * PHP version 5 + * + * LICENSE: + * + * Copyright (c) 2004-2009, Alexey Borzov <avb@php.net> + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * The names of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @category HTML + * @package HTML_Common2 + * @author Alexey Borzov <avb@php.net> + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Common2.php 295050 2010-02-14 05:01:19Z clockwerx $ + * @link http://pear.php.net/package/HTML_Common2 + */ + +/** + * Base class for HTML classes + * + * Implements methods for working with HTML attributes, parsing and generating + * attribute strings. Port of HTML_Common class for PHP4 originally written by + * Adam Daniel with contributions from numerous other developers. + * + * @category HTML + * @package HTML_Common2 + * @author Alexey Borzov <avb@php.net> + * @version Release: @package_version@ + */ +abstract class HTML_Common2 +{ + /** + * Associative array of attributes + * @var array + */ + protected $attributes = array(); + + /** + * List of attribites changes to which will be announced via onAttributeChange() + * method rather than performed by HTML_Common2 class itself + * @var array + * @see onAttributeChange() + */ + protected $watchedAttributes = array(); + + /** + * Indentation level of the element + * @var int + */ + private $_indentLevel = 0; + + /** + * Comment associated with the element + * @var string + */ + private $_comment = null; + + /** + * Global options for all elements generated by subclasses of HTML_Common2 + * + * Preset options are + * - 'charset': charset parameter used in htmlspecialchars() calls, + * defaults to 'ISO-8859-1' + * - 'indent': string used to indent HTML elements, defaults to "\11" + * - 'linebreak': string used to indicate linebreak, defaults to "\12" + * + * @var array + */ + private static $_options = array( + 'charset' => 'ISO-8859-1', + 'indent' => "\11", + 'linebreak' => "\12" + ); + + /** + * Sets global option(s) + * + * @param string|array Option name or array ('option name' => 'option value') + * @param mixed Option value, if first argument is not an array + */ + public static function setOption($nameOrOptions, $value = null) + { + if (is_array($nameOrOptions)) { + foreach ($nameOrOptions as $k => $v) { + self::setOption($k, $v); + } + } else { + $linebreaks = array('win' => "\15\12", 'unix' => "\12", 'mac' => "\15"); + if ('linebreak' == $nameOrOptions && isset($linebreaks[$value])) { + $value = $linebreaks[$value]; + } + self::$_options[$nameOrOptions] = $value; + } + } + + /** + * Returns global option(s) + * + * @param string Option name + * @return mixed Option value, null if option does not exist, + * array of all options if $name is not given + */ + public static function getOption($name = null) + { + if (null === $name) { + return self::$_options; + } else { + return isset(self::$_options[$name])? self::$_options[$name]: null; + } + } + + /** + * Parses the HTML attributes given as string + * + * @param string HTML attribute string + * @return array An associative aray of attributes + */ + protected static function parseAttributes($attrString) + { + $attributes = array(); + if (preg_match_all( + "/(([A-Za-z_:]|[^\\x00-\\x7F])([A-Za-z0-9_:.-]|[^\\x00-\\x7F])*)" . + "([ \\n\\t\\r]+)?(=([ \\n\\t\\r]+)?(\"[^\"]*\"|'[^']*'|[^ \\n\\t\\r]*))?/", + $attrString, + $regs + )) { + for ($i = 0; $i < count($regs[1]); $i++) { + $name = trim($regs[1][$i]); + $check = trim($regs[0][$i]); + $value = trim($regs[7][$i]); + if ($name == $check) { + $attributes[strtolower($name)] = strtolower($name); + } else { + if (!empty($value) && ($value[0] == '\'' || $value[0] == '"')) { + $value = substr($value, 1, -1); + } + $attributes[strtolower($name)] = $value; + } + } + } + return $attributes; + } + + /** + * Creates a valid attribute array from either a string or an array + * + * @param mixed Array of attributes or HTML attribute string + * @return array An associative aray of attributes + */ + protected static function prepareAttributes($attributes) + { + $prepared = array(); + if (is_string($attributes)) { + return self::parseAttributes($attributes); + + } elseif (is_array($attributes)) { + foreach ($attributes as $key => $value) { + if (is_int($key)) { + $key = strtolower($value); + $prepared[$key] = $key; + } else { + $prepared[strtolower($key)] = (string)$value; + } + } + } + return $prepared; + } + + /** + * Removes an attribute from an attribute array + * + * @param array Attribute array + * @param string Name of attribute to remove + */ + protected static function removeAttributeArray(&$attributes, $name) + { + unset($attributes[strtolower($name)]); + } + + /** + * Creates HTML attribute string from array + * + * @param array Attribute array + * @return string Attribute string + */ + protected static function getAttributesString($attributes) + { + $str = ''; + if (is_array($attributes)) { + $charset = self::getOption('charset'); + foreach ($attributes as $key => $value) { + $str .= ' ' . $key . '="' . htmlspecialchars($value, ENT_QUOTES, $charset) . '"'; + } + } + return $str; + } + + /** + * Class constructor, sets default attributes + * + * @param mixed Array of attribute 'name' => 'value' pairs or HTML attribute string + */ + public function __construct($attributes = null) + { + $this->mergeAttributes($attributes); + } + + /** + * Sets the value of the attribute + * + * @param string Attribute name + * @param string Attribute value (will be set to $name if omitted) + * @return HTML_Common2 + */ + public function setAttribute($name, $value = null) + { + $name = strtolower($name); + if (is_null($value)) { + $value = $name; + } + if (in_array($name, $this->watchedAttributes)) { + $this->onAttributeChange($name, $value); + } else { + $this->attributes[$name] = (string)$value; + } + return $this; + } + + /** + * Returns the value of an attribute + * + * @param string Attribute name + * @return string Attribute value, null if attribute does not exist + */ + public function getAttribute($name) + { + $name = strtolower($name); + return isset($this->attributes[$name])? $this->attributes[$name]: null; + } + + /** + * Sets the attributes + * + * @param mixed Array of attribute 'name' => 'value' pairs or HTML attribute string + * @return HTML_Common2 + */ + public function setAttributes($attributes) + { + $attributes = self::prepareAttributes($attributes); + $watched = array(); + foreach ($this->watchedAttributes as $watchedKey) { + if (isset($attributes[$watchedKey])) { + $this->setAttribute($watchedKey, $attributes[$watchedKey]); + unset($attributes[$watchedKey]); + } else { + $this->removeAttribute($watchedKey); + } + if (isset($this->attributes[$watchedKey])) { + $watched[$watchedKey] = $this->attributes[$watchedKey]; + } + } + $this->attributes = array_merge($watched, $attributes); + return $this; + } + + /** + * Returns the attribute array or string + * + * @param bool Whether to return attributes as string + * @return mixed Either an array or string of attributes + */ + public function getAttributes($asString = false) + { + if ($asString) { + return self::getAttributesString($this->attributes); + } else { + return $this->attributes; + } + } + + /** + * Merges the existing attributes with the new ones + * + * @param mixed Array of attribute 'name' => 'value' pairs or HTML attribute string + * @return HTML_Common2 + */ + public function mergeAttributes($attributes) + { + $attributes = self::prepareAttributes($attributes); + foreach ($this->watchedAttributes as $watchedKey) { + if (isset($attributes[$watchedKey])) { + $this->onAttributeChange($watchedKey, $attributes[$watchedKey]); + unset($attributes[$watchedKey]); + } + } + $this->attributes = array_merge($this->attributes, $attributes); + return $this; + } + + /** + * Removes an attribute + * + * @param string Name of attribute to remove + * @return HTML_Common2 + */ + public function removeAttribute($attribute) + { + if (in_array(strtolower($attribute), $this->watchedAttributes)) { + $this->onAttributeChange(strtolower($attribute), null); + } else { + self::removeAttributeArray($this->attributes, $attribute); + } + return $this; + } + + /** + * Sets the indentation level + * + * @param int + * @return HTML_Common2 + */ + public function setIndentLevel($level) + { + $level = intval($level); + if (0 <= $level) { + $this->_indentLevel = $level; + } + return $this; + } + + /** + * Gets the indentation level + * + * @return int + */ + public function getIndentLevel() + { + return $this->_indentLevel; + } + + /** + * Returns the string to indent the element + * + * @return string + */ + protected function getIndent() + { + return str_repeat(self::getOption('indent'), $this->getIndentLevel()); + } + + /** + * Sets the comment for the element + * + * @param string + * @return HTML_Common2 + */ + public function setComment($comment) + { + $this->_comment = $comment; + return $this; + } + + /** + * Returns the comment associated with the element + * + * @return string + */ + public function getComment() + { + return $this->_comment; + } + + /** + * Checks whether the element has given CSS class + * + * @param string Class name + * @return bool + */ + public function hasClass($class) + { + $regex = '/(^|\s)' . preg_quote($class, '/') . '(\s|$)/'; + return (bool)preg_match($regex, $this->getAttribute('class')); + } + + /** + * Adds the given CSS class(es) to the element + * + * @param string|array Class name, multiple class names separated by + * whitespace, array of class names + * @return HTML_Common2 + */ + public function addClass($class) + { + if (!is_array($class)) { + $class = preg_split('/\s+/', $class, null, PREG_SPLIT_NO_EMPTY); + } + $curClass = preg_split('/\s+/', $this->getAttribute('class'), + null, PREG_SPLIT_NO_EMPTY); + foreach ($class as $c) { + if (!in_array($c, $curClass)) { + $curClass[] = $c; + } + } + $this->setAttribute('class', implode(' ', $curClass)); + + return $this; + } + + /** + * Removes the given CSS class(es) from the element + * + * @param string|array Class name, multiple class names separated by + * whitespace, array of class names + * @return HTML_Common2 + */ + public function removeClass($class) + { + if (!is_array($class)) { + $class = preg_split('/\s+/', $class, null, PREG_SPLIT_NO_EMPTY); + } + $curClass = array_diff( + preg_split('/\s+/', $this->getAttribute('class'), + null, PREG_SPLIT_NO_EMPTY), + $class + ); + if (0 == count($curClass)) { + $this->removeAttribute('class'); + } else { + $this->setAttribute('class', implode(' ', $curClass)); + } + return $this; + } + + /** + * Returns the HTML representation of the element + * + * This magic method allows using the instances of HTML_Common2 in string + * contexts + * + * @return string + */ + abstract public function __toString(); + + /** + * Called if trying to change an attribute with name in $watchedAttributes + * + * This method is called for each attribute whose name is in the + * $watchedAttributes array and which is being changed by setAttribute(), + * setAttributes() or mergeAttributes() or removed via removeAttribute(). + * Note that the operation for the attribute is not carried on after calling + * this method, it is the responsibility of this method to change or remove + * (or not) the attribute. + * + * @param string Attribute name + * @param string Attribute value, null if attribute is being removed + */ + protected function onAttributeChange($name, $value = null) + { + } +} +?> diff --git a/libs/HTML/QuickForm2.php b/libs/HTML/QuickForm2.php new file mode 100644 index 0000000000..787b6001bd --- /dev/null +++ b/libs/HTML/QuickForm2.php @@ -0,0 +1,224 @@ +<?php +/** + * Class representing a HTML form + * + * PHP version 5 + * + * LICENSE: + * + * Copyright (c) 2006-2010, Alexey Borzov <avb@php.net>, + * Bertrand Mansion <golgote@mamasam.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * The names of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version SVN: $Id: QuickForm2.php 299706 2010-05-24 18:32:37Z avb $ + * @link http://pear.php.net/package/HTML_QuickForm2 + */ + +/** + * Abstract base class for QuickForm2 containers + */ +require_once 'HTML/QuickForm2/Container.php'; + +/** + * Data source for HTML_QuickForm2 objects based on superglobal arrays + */ +require_once 'HTML/QuickForm2/DataSource/SuperGlobal.php'; + +/** + * Class representing a HTML form + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @version Release: @package_version@ + */ +class HTML_QuickForm2 extends HTML_QuickForm2_Container +{ + /** + * Data sources providing values for form elements + * @var array + */ + protected $datasources = array(); + + /** + * We do not allow setting "method" and "id" other than through constructor + * @var array + */ + protected $watchedAttributes = array('id', 'method'); + + /** + * Class constructor, form's "id" and "method" attributes can only be set here + * + * @param string "id" attribute of <form> tag + * @param string HTTP method used to submit the form + * @param mixed Additional attributes (either a string or an array) + * @param bool Whether to track if the form was submitted by adding + * a special hidden field + */ + public function __construct($id, $method = 'post', $attributes = null, $trackSubmit = true) + { + $method = ('GET' == strtoupper($method))? 'get': 'post'; + if (empty($id)) { + $id = self::generateId(''); + $trackSubmit = false; + } else { + self::storeId($id); + } + $this->attributes = array_merge( + self::prepareAttributes($attributes), + array('id' => (string)$id, 'method' => $method) + ); + if (!isset($this->attributes['action'])) { + $this->attributes['action'] = $_SERVER['PHP_SELF']; + } + if ($trackSubmit && isset($_REQUEST['_qf__' . $id]) || + !$trackSubmit && ('get' == $method && !empty($_GET) || + 'post' == $method && (!empty($_POST) || !empty($_FILES)))) + { + $this->addDataSource(new HTML_QuickForm2_DataSource_SuperGlobal( + $method, get_magic_quotes_gpc() + )); + } + if ($trackSubmit) { + $this->appendChild(HTML_QuickForm2_Factory::createElement( + 'hidden', '_qf__' . $id + )); + } + } + + protected function onAttributeChange($name, $value = null) + { + throw new HTML_QuickForm2_InvalidArgumentException( + 'Attribute \'' . $name . '\' is read-only' + ); + } + + protected function setContainer(HTML_QuickForm2_Container $container = null) + { + throw new HTML_QuickForm2_Exception('Form cannot be added to container'); + } + + public function setId($id = null) + { + throw new HTML_QuickForm2_InvalidArgumentException( + "Attribute 'id' is read-only" + ); + } + + + /** + * Adds a new data source to the form + * + * @param HTML_QuickForm2_DataSource Data source + */ + public function addDataSource(HTML_QuickForm2_DataSource $datasource) + { + $this->datasources[] = $datasource; + $this->updateValue(); + } + + /** + * Replaces the list of form's data sources with a completely new one + * + * @param array A new data source list + * @throws HTML_QuickForm2_InvalidArgumentException if given array + * contains something that is not a valid data source + */ + public function setDataSources(array $datasources) + { + foreach ($datasources as $ds) { + if (!$ds instanceof HTML_QuickForm2_DataSource) { + throw new HTML_QuickForm2_InvalidArgumentException( + 'Array should contain only DataSource instances' + ); + } + } + $this->datasources = $datasources; + $this->updateValue(); + } + + /** + * Returns the list of data sources attached to the form + * + * @return array + */ + public function getDataSources() + { + return $this->datasources; + } + + public function getType() + { + return 'form'; + } + + public function setValue($value) + { + throw new HTML_QuickForm2_Exception('Not implemented'); + } + + /** + * Performs the server-side validation + * + * @return boolean Whether all form's elements are valid + */ + public function validate() + { + $isSubmitted = false; + foreach ($this->datasources as $ds) { + if ($ds instanceof HTML_QuickForm2_DataSource_Submit) { + $isSubmitted = true; + break; + } + } + return $isSubmitted? parent::validate(): false; + } + + /** + * Renders the form using the given renderer + * + * @param HTML_QuickForm2_Renderer Renderer instance + * @return HTML_QuickForm2_Renderer + */ + public function render(HTML_QuickForm2_Renderer $renderer) + { + $renderer->startForm($this); + $renderer->getJavascriptBuilder()->startForm($this); + foreach ($this as $element) { + $element->render($renderer); + } + $renderer->finishForm($this); + return $renderer; + } +} +?> diff --git a/libs/HTML/QuickForm2/Container.php b/libs/HTML/QuickForm2/Container.php new file mode 100644 index 0000000000..b62a435f06 --- /dev/null +++ b/libs/HTML/QuickForm2/Container.php @@ -0,0 +1,487 @@ +<?php +/** + * Base class for simple HTML_QuickForm2 containers + * + * PHP version 5 + * + * LICENSE: + * + * Copyright (c) 2006-2010, Alexey Borzov <avb@php.net>, + * Bertrand Mansion <golgote@mamasam.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * The names of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version SVN: $Id: Container.php 300722 2010-06-24 10:15:52Z mansion $ + * @link http://pear.php.net/package/HTML_QuickForm2 + */ + +/** + * Base class for all HTML_QuickForm2 elements + */ +require_once 'HTML/QuickForm2/Node.php'; + +/** + * Abstract base class for simple QuickForm2 containers + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @version Release: @package_version@ + */ +abstract class HTML_QuickForm2_Container extends HTML_QuickForm2_Node + implements IteratorAggregate, Countable +{ + /** + * Array of elements contained in this container + * @var array + */ + protected $elements = array(); + + + public function setName($name) + { + $this->attributes['name'] = (string)$name; + return $this; + } + + public function toggleFrozen($freeze = null) + { + if (null !== $freeze) { + foreach ($this as $child) { + $child->toggleFrozen($freeze); + } + } + return parent::toggleFrozen($freeze); + } + + public function persistentFreeze($persistent = null) + { + if (null !== $persistent) { + foreach ($this as $child) { + $child->persistentFreeze($persistent); + } + } + return parent::persistentFreeze($persistent); + } + + /** + * Whether container prepends its name to names of contained elements + * + * @return bool + */ + protected function prependsName() + { + return false; + } + + /** + * Returns the element's value + * + * The default implementation for Containers is to return an array with + * contained elements' values. The array is indexed the same way $_GET and + * $_POST arrays would be for these elements. + * + * @return array|null + */ + public function getValue() + { + $values = array(); + foreach ($this as $child) { + $value = $child->getValue(); + if (null !== $value) { + if ($child instanceof HTML_QuickForm2_Container + && !$child->prependsName() + ) { + $values = self::arrayMerge($values, $value); + } else { + $name = $child->getName(); + if (!strpos($name, '[')) { + $values[$name] = $value; + } else { + $tokens = explode('[', str_replace(']', '', $name)); + $valueAry =& $values; + do { + $token = array_shift($tokens); + if (!isset($valueAry[$token])) { + $valueAry[$token] = array(); + } + $valueAry =& $valueAry[$token]; + } while (count($tokens) > 1); + $valueAry[$tokens[0]] = $value; + } + } + } + } + return empty($values)? null: $this->applyFilters($values); + } + + /** + * Merges two arrays + * + * Merges two arrays like the PHP function array_merge_recursive does, + * the difference being that existing integer keys will not be renumbered. + * + * @param array + * @param array + * @return array resulting array + */ + protected static function arrayMerge($a, $b) + { + foreach ($b as $k => $v) { + if (!is_array($v) || isset($a[$k]) && !is_array($a[$k])) { + $a[$k] = $v; + } else { + $a[$k] = self::arrayMerge(isset($a[$k])? $a[$k]: array(), $v); + } + } + return $a; + } + + /** + * Returns an array of this container's elements + * + * @return array Container elements + */ + public function getElements() + { + return $this->elements; + } + + /** + * Appends an element to the container + * + * If the element was previously added to the container or to another + * container, it is first removed there. + * + * @param HTML_QuickForm2_Node Element to add + * @return HTML_QuickForm2_Node Added element + * @throws HTML_QuickForm2_InvalidArgumentException + */ + public function appendChild(HTML_QuickForm2_Node $element) + { + if ($this === $element->getContainer()) { + $this->removeChild($element); + } + $element->setContainer($this); + $this->elements[] = $element; + return $element; + } + + /** + * Appends an element to the container (possibly creating it first) + * + * If the first parameter is an instance of HTML_QuickForm2_Node then all + * other parameters are ignored and the method just calls {@link appendChild()}. + * In the other case the element is first created via + * {@link HTML_QuickForm2_Factory::createElement()} and then added via the + * same method. This is a convenience method to reduce typing and ease + * porting from HTML_QuickForm. + * + * @param string|HTML_QuickForm2_Node Either type name (treated + * case-insensitively) or an element instance + * @param mixed Element name + * @param mixed Element attributes + * @param array Element-specific data + * @return HTML_QuickForm2_Node Added element + * @throws HTML_QuickForm2_InvalidArgumentException + * @throws HTML_QuickForm2_NotFoundException + */ + public function addElement($elementOrType, $name = null, $attributes = null, + array $data = array()) + { + if ($elementOrType instanceof HTML_QuickForm2_Node) { + return $this->appendChild($elementOrType); + } else { + return $this->appendChild(HTML_QuickForm2_Factory::createElement( + $elementOrType, $name, $attributes, $data + )); + } + } + + /** + * Removes the element from this container + * + * If the reference object is not given, the element will be appended. + * + * @param HTML_QuickForm2_Node Element to remove + * @return HTML_QuickForm2_Node Removed object + */ + public function removeChild(HTML_QuickForm2_Node $element) + { + + if ($element->getContainer() !== $this) { + throw new HTML_QuickForm2_NotFoundException( + "Element with name '".$element->getName()."' was not found" + ); + } + foreach ($this as $key => $child){ + if ($child === $element) { + unset($this->elements[$key]); + $element->setContainer(null); + break; + } + } + return $element; + } + + + /** + * Returns an element if its id is found + * + * @param string Element id to find + * @return HTML_QuickForm2_Node|null + */ + public function getElementById($id) + { + foreach ($this->getRecursiveIterator() as $element) { + if ($id == $element->getId()) { + return $element; + } + } + return null; + } + + /** + * Returns an array of elements which name corresponds to element + * + * @param string Elements name to find + * @return array + */ + public function getElementsByName($name) + { + $found = array(); + foreach ($this->getRecursiveIterator() as $element) { + if ($element->getName() == $name) { + $found[] = $element; + } + } + return $found; + } + + /** + * Inserts an element in the container + * + * If the reference object is not given, the element will be appended. + * + * @param HTML_QuickForm2_Node Element to insert + * @param HTML_QuickForm2_Node Reference to insert before + * @return HTML_QuickForm2_Node Inserted element + */ + public function insertBefore(HTML_QuickForm2_Node $element, HTML_QuickForm2_Node $reference = null) + { + if (null === $reference) { + return $this->appendChild($element); + } + $offset = 0; + foreach ($this as $child) { + if ($child === $reference) { + if ($this === $element->getContainer()) { + $this->removeChild($element); + } + $element->setContainer($this); + array_splice($this->elements, $offset, 0, array($element)); + return $element; + } + $offset++; + } + throw new HTML_QuickForm2_NotFoundException( + "Reference element with name '".$reference->getName()."' was not found" + ); + } + + /** + * Returns a recursive iterator for the container elements + * + * @return HTML_QuickForm2_ContainerIterator + */ + public function getIterator() + { + return new HTML_QuickForm2_ContainerIterator($this); + } + + /** + * Returns a recursive iterator iterator for the container elements + * + * @param int mode passed to RecursiveIteratorIterator + * @return RecursiveIteratorIterator + */ + public function getRecursiveIterator($mode = RecursiveIteratorIterator::SELF_FIRST) + { + return new RecursiveIteratorIterator( + new HTML_QuickForm2_ContainerIterator($this), $mode + ); + } + + /** + * Returns the number of elements in the container + * + * @return int + */ + public function count() + { + return count($this->elements); + } + + /** + * Called when the element needs to update its value from form's data sources + * + * The default behaviour is just to call the updateValue() methods of + * contained elements, since default Container doesn't have any value itself + */ + protected function updateValue() + { + foreach ($this as $child) { + $child->updateValue(); + } + } + + + /** + * Performs the server-side validation + * + * This method also calls validate() on all contained elements. + * + * @return boolean Whether the container and all contained elements are valid + */ + protected function validate() + { + $valid = parent::validate(); + foreach ($this as $child) { + $valid = $child->validate() && $valid; + } + return $valid; + } + + /** + * Appends an element to the container, creating it first + * + * The element will be created via {@link HTML_QuickForm2_Factory::createElement()} + * and then added via the {@link appendChild()} method. + * The element type is deduced from the method name. + * This is a convenience method to reduce typing. + * + * @param mixed Element name + * @param mixed Element attributes + * @param array Element-specific data + * @return HTML_QuickForm2_Node Added element + * @throws HTML_QuickForm2_InvalidArgumentException + * @throws HTML_QuickForm2_NotFoundException + */ + public function __call($m, $a) + { + if (preg_match('/^(add)([a-zA-Z0-9_]+)$/', $m, $match)) { + if ($match[1] == 'add') { + $type = strtolower($match[2]); + $name = isset($a[0]) ? $a[0] : null; + $attr = isset($a[1]) ? $a[1] : null; + $data = isset($a[2]) ? $a[2] : array(); + return $this->addElement($type, $name, $attr, $data); + } + } + trigger_error("Fatal error: Call to undefined method ".get_class($this)."::".$m."()", E_USER_ERROR); + } + + /** + * Renders the container using the given renderer + * + * @param HTML_QuickForm2_Renderer Renderer instance + * @return HTML_QuickForm2_Renderer + */ + public function render(HTML_QuickForm2_Renderer $renderer) + { + foreach ($this->rules as $rule) { + if ($rule[1] & HTML_QuickForm2_Rule::RUNAT_CLIENT) { + $renderer->getJavascriptBuilder()->addRule($rule[0]); + } + } + $renderer->startContainer($this); + foreach ($this as $element) { + $element->render($renderer); + } + $renderer->finishContainer($this); + return $renderer; + } + + public function __toString() + { + require_once 'HTML/QuickForm2/Renderer.php'; + + return $this->render(HTML_QuickForm2_Renderer::factory('default'))->__toString(); + } + + /** + * Returns Javascript code for getting the element's value + * + * @return string + */ + public function getJavascriptValue() + { + $args = array(); + foreach ($this as $child) { + if ($child instanceof HTML_QuickForm2_Container) { + $args[] = $child->getJavascriptValue(); + } else { + $args[] = "'" . $child->getId() . "'"; + } + } + return 'qf.form.getContainerValue(' . implode(', ', $args) . ')'; + } +} + +/** + * Implements a recursive iterator for the container elements + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @version Release: @package_version@ + */ +class HTML_QuickForm2_ContainerIterator extends RecursiveArrayIterator implements RecursiveIterator +{ + public function __construct(HTML_QuickForm2_Container $container) + { + parent::__construct($container->getElements()); + } + + public function hasChildren() + { + return $this->current() instanceof HTML_QuickForm2_Container; + } + + public function getChildren() + { + return new HTML_QuickForm2_ContainerIterator($this->current()); + } +} + +?>
\ No newline at end of file diff --git a/libs/HTML/QuickForm2/Container/Fieldset.php b/libs/HTML/QuickForm2/Container/Fieldset.php new file mode 100644 index 0000000000..bf362431c8 --- /dev/null +++ b/libs/HTML/QuickForm2/Container/Fieldset.php @@ -0,0 +1,92 @@ +<?php +/** + * Base class for fieldsets + * + * PHP version 5 + * + * LICENSE: + * + * Copyright (c) 2006-2010, Alexey Borzov <avb@php.net>, + * Bertrand Mansion <golgote@mamasam.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * The names of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version SVN: $Id: Fieldset.php 294052 2010-01-26 20:00:22Z avb $ + * @link http://pear.php.net/package/HTML_QuickForm2 + */ + +/** + * Base class for fieldsets + */ +require_once 'HTML/QuickForm2/Container.php'; + +/** + * Concrete implementation of a container for fieldsets + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @version Release: @package_version@ + */ +class HTML_QuickForm2_Container_Fieldset extends HTML_QuickForm2_Container +{ + /** + * Fieldsets don't have a 'name' attribute, so we only handle 'id' + * @var array + */ + protected $watchedAttributes = array('id'); + + public function getType() + { + return 'fieldset'; + } + + + public function getName() + { + return null; + } + + + public function setName($name) + { + // Fieldsets do not have a name attribute + return $this; + } + + + public function setValue($value) + { + throw new HTML_QuickForm2_Exception('Not implemented'); + } +} +?>
\ No newline at end of file diff --git a/libs/HTML/QuickForm2/Container/Group.php b/libs/HTML/QuickForm2/Container/Group.php new file mode 100644 index 0000000000..4ef7b1b552 --- /dev/null +++ b/libs/HTML/QuickForm2/Container/Group.php @@ -0,0 +1,328 @@ +<?php +/** + * Base class for HTML_QuickForm2 groups + * + * PHP version 5 + * + * LICENSE: + * + * Copyright (c) 2006-2010, Alexey Borzov <avb@php.net>, + * Bertrand Mansion <golgote@mamasam.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * The names of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version SVN: $Id: Group.php 294057 2010-01-26 21:10:28Z avb $ + * @link http://pear.php.net/package/HTML_QuickForm2 + */ + +/** + * Base class for all HTML_QuickForm2 containers + */ +require_once 'HTML/QuickForm2/Container.php'; + +/** + * Base class for QuickForm2 groups of elements + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @version Release: @package_version@ + */ +class HTML_QuickForm2_Container_Group extends HTML_QuickForm2_Container +{ + /** + * Group name + * If set, group name will be used as prefix for contained + * element names, like groupname[elementname]. + * @var string + */ + protected $name; + + /** + * Previous group name + * Stores the previous group name when the group name is changed. + * Used to restore children names if necessary. + * @var string + */ + protected $previousName; + + public function getType() + { + return 'group'; + } + + protected function prependsName() + { + return strlen($this->name) > 0; + } + + public function getValue() + { + $value = parent::getValue(); + if (!$this->prependsName()) { + return $value; + + } elseif (!strpos($this->getName(), '[')) { + return isset($value[$this->getName()])? $value[$this->getName()]: null; + + } else { + $tokens = explode('[', str_replace(']', '', $this->getName())); + $valueAry =& $value; + do { + $token = array_shift($tokens); + if (!isset($valueAry[$token])) { + return null; + } + $valueAry =& $valueAry[$token]; + } while ($tokens); + return $valueAry; + } + } + + public function setValue($value) + { + // Prepare a mapper for element names as array + + if ($this->prependsName()) { + $prefix = explode('[', str_replace(']', '', $this->getName())); + } + + $elements = array(); + foreach ($this as $child) { + $tokens = explode('[', str_replace(']', '', $child->getName())); + if (!empty($prefix)) { + $tokens = array_slice($tokens, count($prefix)); + } + $elements[] = $tokens; + } + + // Iterate over values to find corresponding element + + $index = 0; + + foreach ($value as $k => $v) { + $val = array($k => $v); + $found = null; + foreach ($elements as $i => $tokens) { + do { + $token = array_shift($tokens); + $numeric = false; + if ($token == "") { + // Deal with numeric indexes in values + $token = $index; + $numeric = true; + } + if (isset($val[$token])) { + // Found a value + $val = $val[$token]; + $found = $val; + if ($numeric) { + $index += 1; + } + } else { + // Not found, skip next iterations + $found = null; + break; + } + + } while (!empty($tokens)); + + if (!is_null($found)) { + // Found a value corresponding to element name + $child = $this->elements[$i]; + $child->setValue($val); + unset($val); + if (!($child instanceof HTML_QuickForm2_Container_Group)) { + // Speed up next iterations + unset($elements[$i]); + } + break; + } + } + } + } + + + public function getName() + { + return $this->name; + } + + public function setName($name) + { + $this->previousName = $this->name; + $this->name = $name; + foreach ($this as $child) { + $this->renameChild($child); + } + return $this; + } + + protected function renameChild(HTML_QuickForm2_Node $element) + { + $tokens = explode('[', str_replace(']', '', $element->getName())); + if ($this === $element->getContainer()) { + // Child has already been renamed by its group before + if (!is_null($this->previousName) && + $this->previousName !== '') { + $gtokens = explode('[', str_replace(']', '', $this->previousName)); + $pos = array_search(end($gtokens), $tokens); + if (!is_null($pos)) { + $tokens = array_slice($tokens, $pos+1); + } + } + } + if (is_null($this->name) || $this->name === '') { + if (is_null($this->previousName) || $this->previousName === '') { + return $element; + } else { + $elname = $tokens[0]; + unset($tokens[0]); + foreach ($tokens as $v) { + $elname .= '['.$v.']'; + } + } + } else { + $elname = $this->getName().'['.implode('][', $tokens).']'; + } + $element->setName($elname); + return $element; + } + + /** + * Appends an element to the container + * + * If the element was previously added to the container or to another + * container, it is first removed there. + * + * @param HTML_QuickForm2_Node Element to add + * @return HTML_QuickForm2_Node Added element + * @throws HTML_QuickForm2_InvalidArgumentException + */ + public function appendChild(HTML_QuickForm2_Node $element) + { + if (null !== ($container = $element->getContainer())) { + $container->removeChild($element); + } + // Element can be renamed only after being removed from container + $this->renameChild($element); + + $element->setContainer($this); + $this->elements[] = $element; + return $element; + } + + /** + * Removes the element from this container + * + * If the reference object is not given, the element will be appended. + * + * @param HTML_QuickForm2_Node Element to remove + * @return HTML_QuickForm2_Node Removed object + */ + public function removeChild(HTML_QuickForm2_Node $element) + { + $element = parent::removeChild($element); + if ($this->prependsName()) { + $name = preg_replace('/^' . $this->getName() . '\[([^\]]*)\]/', '\1', $element->getName()); + $element->setName($name); + } + return $element; + } + + /** + * Inserts an element in the container + * + * If the reference object is not given, the element will be appended. + * + * @param HTML_QuickForm2_Node Element to insert + * @param HTML_QuickForm2_Node Reference to insert before + * @return HTML_QuickForm2_Node Inserted element + */ + public function insertBefore(HTML_QuickForm2_Node $element, HTML_QuickForm2_Node $reference = null) + { + if (null === $reference) { + return $this->appendChild($element); + } + return parent::insertBefore($this->renameChild($element), $reference); + } + + /** + * Sets string(s) to separate grouped elements + * + * @param string|array Use a string for one separator, array for + * alternating separators + * @return HTML_QuickForm2_Container_Group + */ + public function setSeparator($separator) + { + $this->data['separator'] = $separator; + return $this; + } + + /** + * Returns string(s) to separate grouped elements + * + * @return string|array Separator, null if not set + */ + public function getSeparator() + { + return isset($this->data['separator'])? $this->data['separator']: null; + } + + /** + * Renders the group using the given renderer + * + * @param HTML_QuickForm2_Renderer Renderer instance + * @return HTML_QuickForm2_Renderer + */ + public function render(HTML_QuickForm2_Renderer $renderer) + { + $renderer->startGroup($this); + foreach ($this as $element) { + $element->render($renderer); + } + $renderer->finishGroup($this); + return $renderer; + } + + public function __toString() + { + require_once 'HTML/QuickForm2/Renderer.php'; + + return $this->render( + HTML_QuickForm2_Renderer::factory('default') + ->setTemplateForId($this->getId(), '{content}') + )->__toString(); + } +} +?>
\ No newline at end of file diff --git a/libs/HTML/QuickForm2/Controller.php b/libs/HTML/QuickForm2/Controller.php new file mode 100644 index 0000000000..d2aa144fdc --- /dev/null +++ b/libs/HTML/QuickForm2/Controller.php @@ -0,0 +1,506 @@ +<?php +/** + * Class implementing the Page Controller pattern for multipage forms + * + * PHP version 5 + * + * LICENSE: + * + * Copyright (c) 2006-2010, Alexey Borzov <avb@php.net>, + * Bertrand Mansion <golgote@mamasam.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * The names of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version SVN: $Id: Controller.php 295963 2010-03-08 14:33:43Z avb $ + * @link http://pear.php.net/package/HTML_QuickForm2 + */ + +/** The class representing a page of a multipage form */ +require_once 'HTML/QuickForm2/Controller/Page.php'; + +/** Object wrapping around session variable used to store controller data */ +require_once 'HTML/QuickForm2/Controller/SessionContainer.php'; + +/** Class presenting the values stored in session by Controller as submitted ones */ +require_once 'HTML/QuickForm2/DataSource/Session.php'; + +/** + * Class implementing the Page Controller pattern for multipage forms + * + * This class keeps track of pages and (default) action handlers for the form, + * it manages $_SESSION container for the form values, allows setting + * DataSources for the form as a whole and getting its value. + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @version Release: @package_version@ + */ +class HTML_QuickForm2_Controller implements IteratorAggregate +{ + /** + * Key in $_REQUEST array that contains the ID of the Controller + */ + const KEY_ID = '_qfc_id'; + + /** + * Key in $_SESSION array that contains the Controller data (needs ID substituted via sprintf()) + */ + const KEY_CONTAINER = '_%s_container'; + + /** + * Whether the form is a wizard + * @var boolean + */ + protected $wizard = true; + + /** + * Whether Controller ID should be sent in GET and POST parameters + * @var boolean + */ + protected $propagate = true; + + /** + * Controller ID + * @var string + */ + protected $id = null; + + /** + * Contains the pages (instances of HTML_QuickForm2_Controller_Page) of the multipage form + * @var array + */ + protected $pages = array(); + + /** + * Contains the mapping of action names to handlers (objects implementing HTML_QuickForm2_Controller_Action) + * @var array + */ + protected $handlers = array(); + + /** + * The action extracted from HTTP request: array('page', 'action') + * @var array + */ + protected $actionName = null; + + /** + * A wrapper around session variable used to store form data + * @var HTML_QuickForm2_Controller_SessionContainer + */ + protected $sessionContainer = null; + + /** + * Finds a controller name in $_REQUEST + * + * @return string|null Returns nulle if either a KEY_ID is not present + * in $_REQUEST or KEY_CONTAINER is not present in + * $_SESSION + */ + public static function findControllerID() + { + if (empty($_REQUEST[self::KEY_ID]) + || empty($_SESSION[sprintf(self::KEY_CONTAINER, $_REQUEST[self::KEY_ID])]) + ) { + return null; + } else { + return $_REQUEST[self::KEY_ID]; + } + } + + /** + * Class constructor + * + * Sets the form ID, whether to send this ID in POST and GET parameters, + * wizard / non-wizard behaviour. + * + * Different forms should be given different IDs, as they are used to store + * values in session. If $id is empty, the controller will try to find it + * in $_REQUEST, throwing the exception if this fails. + * + * Wizard forms only allow going to the next page if all the previous ones + * are valid. + * + * @param string Form ID + * @param boolean Whether the form is a wizard + * @param boolean Whether form's ID should be sent with GET and POST parameters + * @throws HTML_QuickForm2_NotFoundException if ID is not given and cannot + * be found in $_REQUEST, or session container is empty + */ + public function __construct($id = null, $wizard = true, $propagateId = false) + { + if (empty($id)) { + $propagateId = true; + $id = self::findControllerID(); + } + if (empty($id)) { + throw new HTML_QuickForm2_NotFoundException( + 'Controller ID not available in $_REQUEST or session ' . + 'container is empty, please provide ID to constructor' + ); + } + $this->id = $id; + $this->wizard = (bool)$wizard; + $this->propagate = (bool)$propagateId; + } + + /** + * Returns whether the form is a wizard + * + * @return boolean + */ + public function isWizard() + { + return $this->wizard; + } + + /** + * Returns the form ID + * + * @return string + */ + public function getId() + { + return $this->id; + } + + /** + * Returns whether to send form id with GET and POST parameters + * + * @return boolean + */ + public function propagateId() + { + return $this->propagate; + } + + /** + * Returns the session container with the controller data + * + * @return HTML_QuickForm2_Controller_SessionContainer + */ + public function getSessionContainer() + { + if (empty($this->sessionContainer)) { + $this->sessionContainer = new HTML_QuickForm2_Controller_SessionContainer($this); + } + return $this->sessionContainer; + } + + /** + * Removes the session variable containing the controller data + */ + public function destroySessionContainer() + { + unset($_SESSION[sprintf(self::KEY_CONTAINER, $this->id)]); + $this->sessionContainer = null; + } + + /** + * Extracts the name of the page and the action to perform with it from HTTP request data + * + * @return array first element is page name, second is action name + */ + public function getActionName() + { + if (is_array($this->actionName)) { + return $this->actionName; + } + if (empty($this->pages)) { + throw new HTML_QuickForm2_NotFoundException('No pages added to the form'); + } + $names = array_map('preg_quote', array_keys($this->pages)); + $regex = '/^_qf_(' . implode('|', $names) . ')_(.+?)(_x)?$/'; + foreach (array_keys($_REQUEST) as $key) { + if (preg_match($regex, $key, $matches)) { + $this->actionName = array($matches[1], $matches[2]); + break; + } + } + if (!is_array($this->actionName)) { + reset($this->pages); + $this->actionName = array(key($this->pages), 'display'); + } + return $this->actionName; + } + + /** + * Processes the request + * + * This finds the page, the action to perform with it and passes the action + * to the page's handle() method. + * + * @throws HTML_QuickForm2_Exception + */ + public function run() + { + list($page, $action) = $this->getActionName(); + return $this->pages[$page]->handle($action); + } + + /** + * Adds a handler for a specific action + * + * @param string action name + * @param HTML_QuickForm2_Controller_Action the handler for the action + */ + public function addHandler($actionName, HTML_QuickForm2_Controller_Action $action) + { + $this->handlers[$actionName] = $action; + } + + /** + * Handles an action + * + * This will be called if the page itself does not have a handler for a + * specific action. The method also loads and uses default handlers for + * common actions, if specific ones were not added. + * + * @param HTML_QuickForm2_Controller_Page form page + * @param string action name + * @throws HTML_QuickForm2_NotFoundException if handler for an action is missing + */ + public function handle(HTML_QuickForm2_Controller_Page $page, $actionName) + { + if (!isset($this->handlers[$actionName]) + && in_array($actionName, array('next', 'back', 'submit', 'display', 'jump')) + ) { + $className = 'HTML_QuickForm2_Controller_Action_' . ucfirst($actionName); + HTML_QuickForm2_Loader::loadClass($className); + $this->addHandler($actionName, new $className()); + } + if (isset($this->handlers[$actionName])) { + return $this->handlers[$actionName]->perform($page, $actionName); + } else { + throw new HTML_QuickForm2_NotFoundException( + "Unhandled action '{$actionName}' for page '{$page->getForm()->getId()}'" + ); + } + } + + /** + * Adds a new page to the form + * + * @param HTML_QuickForm2_Controller_Page + */ + public function addPage(HTML_QuickForm2_Controller_Page $page) + { + $pageId = $page->getForm()->getId(); + if (!empty($this->pages[$pageId])) { + throw new HTML_QuickForm2_InvalidArgumentException( + "Duplicate page ID '{$pageId}'" + ); + } + $page->setController($this); + $this->pages[$pageId] = $page; + } + + /** + * Returns a page + * + * @param string Page ID + * @return HTML_QuickForm2_Controller_Page + * @throws HTML_QuickForm2_NotFoundException if there is no page with + * the given ID + */ + public function getPage($pageId) + { + if (!empty($this->pages[$pageId])) { + return $this->pages[$pageId]; + } else { + throw new HTML_QuickForm2_NotFoundException( + "Unknown page '{$pageId}'" + ); + } + } + + /** + * Returns the page preceding the given one + * + * @param HTML_QuickForm2_Controller_Page + * @return HTML_QuickForm2_Controller_Page|null + */ + public function previousPage(HTML_QuickForm2_Controller_Page $reference) + { + $previous = null; + foreach ($this->pages as $page) { + if ($page === $reference) { + return $previous; + } + $previous = $page; + } + return null; + } + + /** + * Returns the page following the given one + * + * @param HTML_QuickForm2_Controller_Page + * @return HTML_QuickForm2_Controller_Page|null + */ + public function nextPage(HTML_QuickForm2_Controller_Page $reference) + { + $previous = null; + foreach ($this->pages as $page) { + if ($previous === $reference) { + return $page; + } + $previous = $page; + } + return null; + } + + /** + * Checks whether the pages of the controller are valid + * + * @param HTML_QuickForm2_Controller_Page If given, check only the pages + * before (not including) that page + * @return bool + */ + public function isValid(HTML_QuickForm2_Controller_Page $reference = null) + { + $container = $this->getSessionContainer(); + foreach ($this->pages as $id => $page) { + if ($reference === $page) { + return true; + } + if (!$container->getValidationStatus($id)) { + // We should handle the possible situation when the user has never + // seen a page of a non-modal multipage form + if (!$this->isWizard() + && null === $container->getValidationStatus($id) + ) { + // Empty Session datasource makes the form look submitted + $page->getForm()->setDatasources(array_merge( + $container->getDatasources(), + array(new HTML_QuickForm2_DataSource_Session(array())) + )); + // This will store the "submitted" values in session and + // return validation status + if ($page->storeValues()) { + continue; + } + } + return false; + } + } + return true; + } + + /** + * Returns the first page that failed validation + * + * @return HTML_QuickForm2_Controller_Page|null + */ + public function getFirstInvalidPage() + { + foreach ($this->pages as $id => $page) { + if (!$this->getSessionContainer()->getValidationStatus($id)) { + return $page; + } + } + return null; + } + + /** + * Adds a new data source to the Controller + * + * Note that Controller data sources are stored in session, so your data source + * implementation should properly handle its (un)serialization. + * + * @param HTML_QuickForm2_DataSource Data source + */ + public function addDataSource(HTML_QuickForm2_DataSource $datasource) + { + $this->getSessionContainer()->storeDatasources( + array_merge($this->getSessionContainer()->getDatasources(), + array($datasource)) + ); + } + + /** + * Returns the form's values + * + * @return array + */ + public function getValue() + { + $values = array(); + foreach (array_keys($this->pages) as $id) { + $pageValues = $this->getSessionContainer()->getValues($id); + // skip elements representing actions + foreach ($pageValues as $key => $value) { + if (0 !== strpos($key, '_qf')) { + if (isset($values[$key]) && is_array($value)) { + $values[$key] = self::arrayMerge($values[$key], $value); + } else { + $values[$key] = $value; + } + } + } + } + return $values; + } + + /** + * Merges two arrays + * + * Merges two arrays like the PHP function array_merge_recursive does, + * the difference being that existing integer keys will not be renumbered. + * + * @param array + * @param array + * @return array resulting array + */ + protected static function arrayMerge($a, $b) + { + foreach ($b as $k => $v) { + if (!is_array($v) || isset($a[$k]) && !is_array($a[$k])) { + $a[$k] = $v; + } else { + $a[$k] = self::arrayMerge(isset($a[$k])? $a[$k]: array(), $v); + } + } + return $a; + } + + /** + * Returns an Iterator for the form's pages + * + * @return ArrayIterator + */ + public function getIterator() + { + return new ArrayIterator($this->pages); + } +} +?>
\ No newline at end of file diff --git a/libs/HTML/QuickForm2/Controller/Action.php b/libs/HTML/QuickForm2/Controller/Action.php new file mode 100644 index 0000000000..85e0c0cd77 --- /dev/null +++ b/libs/HTML/QuickForm2/Controller/Action.php @@ -0,0 +1,68 @@ +<?php +/** + * Interface for Controller action handlers + * + * PHP version 5 + * + * LICENSE: + * + * Copyright (c) 2006-2010, Alexey Borzov <avb@php.net>, + * Bertrand Mansion <golgote@mamasam.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * The names of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version SVN: $Id: Action.php 293335 2010-01-09 20:14:38Z avb $ + * @link http://pear.php.net/package/HTML_QuickForm2 + */ + + +/** + * Interface for Controller action handlers + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @version Release: @package_version@ + */ +interface HTML_QuickForm2_Controller_Action +{ + /** + * Performs the given action upon the given page + * + * @param HTML_QuickForm2_Controller_Page page of the multipage form + * @param string action name, some action handlers + * may perform different tasks depending + * on this + */ + public function perform(HTML_QuickForm2_Controller_Page $page, $name); +} +?>
\ No newline at end of file diff --git a/libs/HTML/QuickForm2/Controller/Action/Back.php b/libs/HTML/QuickForm2/Controller/Action/Back.php new file mode 100644 index 0000000000..1e591b4a42 --- /dev/null +++ b/libs/HTML/QuickForm2/Controller/Action/Back.php @@ -0,0 +1,74 @@ +<?php +/** + * Action handler for a 'back' button of wizard-type multipage form + * + * PHP version 5 + * + * LICENSE: + * + * Copyright (c) 2006-2010, Alexey Borzov <avb@php.net>, + * Bertrand Mansion <golgote@mamasam.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * The names of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version SVN: $Id: Back.php 293411 2010-01-11 16:51:32Z avb $ + * @link http://pear.php.net/package/HTML_QuickForm2 + */ + +/** Interface for Controller action handlers */ +require_once 'HTML/QuickForm2/Controller/Action.php'; + +/** + * Action handler for a 'back' button of wizard-type multipage form + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @version Release: @package_version@ + */ +class HTML_QuickForm2_Controller_Action_Back + implements HTML_QuickForm2_Controller_Action +{ + public function perform(HTML_QuickForm2_Controller_Page $page, $name) + { + $page->storeValues(!$page->getController()->isWizard()); + + // go to the previous page if one is available + // we don't check validation status here, 'jump' handler should + if ($previous = $page->getController()->previousPage($page)) { + return $previous->handle('jump'); + } else { + return $page->handle('jump'); + } + } +} +?> diff --git a/libs/HTML/QuickForm2/Controller/Action/Direct.php b/libs/HTML/QuickForm2/Controller/Action/Direct.php new file mode 100644 index 0000000000..1c760a0432 --- /dev/null +++ b/libs/HTML/QuickForm2/Controller/Action/Direct.php @@ -0,0 +1,71 @@ +<?php +/** + * Action handler for going to a specific page of a multipage form + * + * PHP version 5 + * + * LICENSE: + * + * Copyright (c) 2006-2010, Alexey Borzov <avb@php.net>, + * Bertrand Mansion <golgote@mamasam.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * The names of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version SVN: $Id: Direct.php 293411 2010-01-11 16:51:32Z avb $ + * @link http://pear.php.net/package/HTML_QuickForm2 + */ + +/** Interface for Controller action handlers */ +require_once 'HTML/QuickForm2/Controller/Action.php'; + +/** + * Action handler for going to a specific page of a multipage form + * + * When an instance of this class is added in addHandler(), action name + * should be set to ID of a page you want to go to, not 'direct' + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @version Release: @package_version@ + */ +class HTML_QuickForm2_Controller_Action_Direct + implements HTML_QuickForm2_Controller_Action +{ + public function perform(HTML_QuickForm2_Controller_Page $page, $name) + { + $page->storeValues(); + + return $page->getController()->getPage($name)->handle('jump'); + } +} +?> diff --git a/libs/HTML/QuickForm2/Controller/Action/Display.php b/libs/HTML/QuickForm2/Controller/Action/Display.php new file mode 100644 index 0000000000..dc75a8dfe1 --- /dev/null +++ b/libs/HTML/QuickForm2/Controller/Action/Display.php @@ -0,0 +1,117 @@ +<?php +/** + * Action handler for outputting the form + * + * PHP version 5 + * + * LICENSE: + * + * Copyright (c) 2006-2010, Alexey Borzov <avb@php.net>, + * Bertrand Mansion <golgote@mamasam.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * The names of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version SVN: $Id: Display.php 294028 2010-01-25 23:09:11Z avb $ + * @link http://pear.php.net/package/HTML_QuickForm2 + */ + +/** Interface for Controller action handlers */ +require_once 'HTML/QuickForm2/Controller/Action.php'; + +/** Class presenting the values stored in session by Controller as submitted ones */ +require_once 'HTML/QuickForm2/DataSource/Session.php'; + +/** + * Action handler for outputting the form + * + * If you want to customize the form display, subclass this class and override + * the renderForm() method, you don't need to change the perform() method. + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @version Release: @package_version@ + */ +class HTML_QuickForm2_Controller_Action_Display + implements HTML_QuickForm2_Controller_Action +{ + public function perform(HTML_QuickForm2_Controller_Page $page, $name) + { + $validate = false; + $datasources = $page->getForm()->getDataSources(); + $container = $page->getController()->getSessionContainer(); + list(, $oldName) = $page->getController()->getActionName(); + // Check the original action name, we need to do additional processing + // if it was 'display' + if ('display' == $oldName) { + // In case of wizard-type controller we should not allow access to + // a page unless all previous pages are valid (see also bug #2323) + if ($page->getController()->isWizard() + && !$page->getController()->isValid($page) + ) { + return $page->getController()->getFirstInvalidPage()->handle('jump'); + } + // If we have values in container then we should inject the Session + // DataSource, if page was invalid previously we should later call + // validate() to get the errors + if (count($container->getValues($page->getForm()->getId()))) { + array_unshift($datasources, new HTML_QuickForm2_DataSource_Session( + $container->getValues($page->getForm()->getId()) + )); + $validate = false === $container->getValidationStatus($page->getForm()->getId()); + } + } + + // Add "defaults" datasources stored in session + $page->getForm()->setDataSources(array_merge($datasources, $container->getDatasources())); + $page->populateFormOnce(); + if ($validate) { + $page->getForm()->validate(); + } + return $this->renderForm($page->getForm()); + } + + /** + * Outputs the form + * + * Default behaviour is to rely on form's __toString() magic method. + * If you want to customize form appearance or use a different Renderer, + * you should override this method. + * + * @param HTML_QuickForm2 + */ + protected function renderForm(HTML_QuickForm2 $form) + { + echo $form; + } +} +?> diff --git a/libs/HTML/QuickForm2/Controller/Action/Jump.php b/libs/HTML/QuickForm2/Controller/Action/Jump.php new file mode 100644 index 0000000000..4e29492f83 --- /dev/null +++ b/libs/HTML/QuickForm2/Controller/Action/Jump.php @@ -0,0 +1,209 @@ +<?php +/** + * This handler performs an HTTP redirect to a specific page + * + * PHP version 5 + * + * LICENSE: + * + * Copyright (c) 2006-2010, Alexey Borzov <avb@php.net>, + * Bertrand Mansion <golgote@mamasam.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * The names of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version SVN: $Id: Jump.php 294039 2010-01-26 12:29:46Z avb $ + * @link http://pear.php.net/package/HTML_QuickForm2 + */ + +/** Interface for Controller action handlers */ +require_once 'HTML/QuickForm2/Controller/Action.php'; + +/** + * This handler performs an HTTP redirect to a specific page + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @version Release: @package_version@ + */ +class HTML_QuickForm2_Controller_Action_Jump + implements HTML_QuickForm2_Controller_Action +{ + /** + * Splits (part of) the URI into path and query components + * + * @param string String of the form 'foo?bar' + * @return array Array of the form array('foo', '?bar) + */ + protected static function splitUri($uri) + { + if (false === ($qm = strpos($uri, '?'))) { + return array($uri, ''); + } else { + return array(substr($uri, 0, $qm), substr($uri, $qm)); + } + } + + /** + * Removes the '..' and '.' segments from the path component + * + * @param string Path component of the URL, possibly with '.' and '..' segments + * @return string Path component of the URL with '.' and '..' segments removed + */ + protected static function normalizePath($path) + { + $pathAry = explode('/', $path); + $i = 1; + + do { + if ('.' == $pathAry[$i]) { + if ($i < count($pathAry) - 1) { + array_splice($pathAry, $i, 1); + } else { + $pathAry[$i] = ''; + $i++; + } + + } elseif ('..' == $pathAry[$i]) { + if (1 == $i) { + array_splice($pathAry, 1, 1); + + } elseif ('..' != $pathAry[$i - 1]) { + if ($i < count($pathAry) - 1) { + array_splice($pathAry, $i - 1, 2); + $i--; + } else { + array_splice($pathAry, $i - 1, 2, ''); + } + } + + } else { + $i++; + } + } while ($i < count($pathAry)); + + return implode('/', $pathAry); + } + + /** + * Resolves relative URL using current page's URL as base + * + * The method follows procedure described in section 4 of RFC 1808 and + * passes the examples provided in section 5 of said RFC. Values from + * $_SERVER array are used for calculation of "current URL" + * + * @param string Relative URL, probably from form's action attribute + * @return string Absolute URL + */ + protected static function resolveRelativeURL($url) + { + $https = !empty($_SERVER['HTTPS']) && ('off' != strtolower($_SERVER['HTTPS'])); + $scheme = ($https? 'https:': 'http:'); + if ('//' == substr($url, 0, 2)) { + return $scheme . $url; + + } else { + $host = $scheme . '//' . $_SERVER['SERVER_NAME'] . + (($https && 443 == $_SERVER['SERVER_PORT'] || + !$https && 80 == $_SERVER['SERVER_PORT'])? '': ':' . $_SERVER['SERVER_PORT']); + if ('' == $url) { + return $host . $_SERVER['REQUEST_URI']; + + } elseif ('/' == $url[0]) { + list($actPath, $actQuery) = self::splitUri($url); + return $host . self::normalizePath($actPath) . $actQuery; + + } else { + list($basePath, $baseQuery) = self::splitUri($_SERVER['REQUEST_URI']); + list($actPath, $actQuery) = self::splitUri($url); + if ('' == $actPath) { + return $host . $basePath . $actQuery; + } else { + $path = substr($basePath, 0, strrpos($basePath, '/') + 1) . $actPath; + return $host . self::normalizePath($path) . $actQuery; + } + } + } + } + + public function perform(HTML_QuickForm2_Controller_Page $page, $name) + { + // we check whether *all* pages up to current are valid + // if there is an invalid page we go to it, instead of the + // requested one + if ($page->getController()->isWizard() + && !$page->getController()->isValid($page) + ) { + $page = $page->getController()->getFirstInvalidPage(); + } + + // generate the URL for the page 'display' event and redirect to it + $action = $page->getForm()->getAttribute('action'); + // Bug #13087: RFC 2616 requires an absolute URI in Location header + if (!preg_match('@^([a-z][a-z0-9.+-]*):@i', $action)) { + $action = self::resolveRelativeURL($action); + } + + if (!$page->getController()->propagateId()) { + $controllerId = ''; + } else { + $controllerId = '&' . HTML_QuickForm2_Controller::KEY_ID . '=' . + $page->getController()->getId(); + } + if (!defined('SID') || '' == SID || ini_get('session.use_only_cookies')) { + $sessionId = ''; + } else { + $sessionId = '&' . SID; + } + + return $this->doRedirect( + $action . (false === strpos($action, '?')? '?': '&') . + $page->getButtonName('display') . '=true' . $controllerId . $sessionId + ); + } + + + /** + * Redirects to a given URL via Location: header and exits the script + * + * A separate method is mostly needed for creating mocks of this class + * during testing. + * + * @param string URL to redirect to + */ + protected function doRedirect($url) + { + header('Location: ' . $url); + exit; + } +} +?> diff --git a/libs/HTML/QuickForm2/Controller/Action/Next.php b/libs/HTML/QuickForm2/Controller/Action/Next.php new file mode 100644 index 0000000000..b01b9c6413 --- /dev/null +++ b/libs/HTML/QuickForm2/Controller/Action/Next.php @@ -0,0 +1,88 @@ +<?php +/** + * Action handler for a 'next' button of wizard-type multipage form + * + * PHP version 5 + * + * LICENSE: + * + * Copyright (c) 2006-2010, Alexey Borzov <avb@php.net>, + * Bertrand Mansion <golgote@mamasam.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * The names of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version SVN: $Id: Next.php 293411 2010-01-11 16:51:32Z avb $ + * @link http://pear.php.net/package/HTML_QuickForm2 + */ + +/** Interface for Controller action handlers */ +require_once 'HTML/QuickForm2/Controller/Action.php'; + +/** + * Action handler for a 'next' button of wizard-type multipage form + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @version Release: @package_version@ + */ +class HTML_QuickForm2_Controller_Action_Next + implements HTML_QuickForm2_Controller_Action +{ + public function perform(HTML_QuickForm2_Controller_Page $page, $name) + { + $valid = $page->storeValues(); + + // Wizard and page is invalid: don't go further + if ($page->getController()->isWizard() && !$valid) { + return $page->handle('display'); + } + + // More pages? + if (null !== ($next = $page->getController()->nextPage($page))) { + return $next->handle('jump'); + + // Consider this a 'finish' button, if there is no explicit one + } elseif($page->getController()->isWizard()) { + if ($page->getController()->isValid()) { + return $page->handle('process'); + } else { + // redirect to the first invalid page + return $page->getController()->getFirstInvalidPage()->handle('jump'); + } + + } else { + return $page->handle('display'); + } + } +} +?> diff --git a/libs/HTML/QuickForm2/Controller/Action/Submit.php b/libs/HTML/QuickForm2/Controller/Action/Submit.php new file mode 100644 index 0000000000..67fb436240 --- /dev/null +++ b/libs/HTML/QuickForm2/Controller/Action/Submit.php @@ -0,0 +1,79 @@ +<?php +/** + * Action handler for a 'submit' button + * + * PHP version 5 + * + * LICENSE: + * + * Copyright (c) 2006-2010, Alexey Borzov <avb@php.net>, + * Bertrand Mansion <golgote@mamasam.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * The names of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version SVN: $Id: Submit.php 293411 2010-01-11 16:51:32Z avb $ + * @link http://pear.php.net/package/HTML_QuickForm2 + */ + +/** Interface for Controller action handlers */ +require_once 'HTML/QuickForm2/Controller/Action.php'; + +/** + * Action handler for a 'submit' button + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @version Release: @package_version@ + */ +class HTML_QuickForm2_Controller_Action_Submit + implements HTML_QuickForm2_Controller_Action +{ + public function perform(HTML_QuickForm2_Controller_Page $page, $name) + { + $valid = $page->storeValues(); + + // All pages are valid, process + if ($page->getController()->isValid()) { + return $page->handle('process'); + + // Current page is invalid, display it + } elseif (!$valid) { + return $page->handle('display'); + + // Some other page is invalid, redirect to it + } else { + return $page->getController()->getFirstInvalidPage()->handle('jump'); + } + } +} +?> diff --git a/libs/HTML/QuickForm2/Controller/DefaultAction.php b/libs/HTML/QuickForm2/Controller/DefaultAction.php new file mode 100644 index 0000000000..d88a07a47b --- /dev/null +++ b/libs/HTML/QuickForm2/Controller/DefaultAction.php @@ -0,0 +1,106 @@ +<?php +/** + * A hidden button used to submit the form when the user presses Enter + * + * PHP version 5 + * + * LICENSE: + * + * Copyright (c) 2006-2010, Alexey Borzov <avb@php.net>, + * Bertrand Mansion <golgote@mamasam.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * The names of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version SVN: $Id: DefaultAction.php 293465 2010-01-12 18:24:37Z avb $ + * @link http://pear.php.net/package/HTML_QuickForm2 + */ + +/** Class for <input type="image" /> elements */ +require_once 'HTML/QuickForm2/Element/InputImage.php'; + +/** + * A hidden button used to submit the form when the user presses Enter + * + * This element is used by {@link HTML_QuickForm2_Controller_Page::setDefaultAction()} + * to define the action that will take place if the user presses Enter on one + * of the form elements instead of explicitly clicking one of the submit + * buttons. Injecting a hidden <input type="image" /> element is about the + * only cross-browser way to achieve this. + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @version Release: @package_version@ + * @link http://www.alanflavell.org.uk/www/formquestion.html + * @link http://muffinresearch.co.uk/archives/2005/12/08/fun-with-multiple-submit-buttons/ + */ +class HTML_QuickForm2_Controller_DefaultAction + extends HTML_QuickForm2_Element_InputImage +{ + protected $attributes = array('type' => 'image', 'id' => '_qf_default', + 'width' => '1', 'height' => '1'); + + /** + * Disallow changing the 'id' attribute + * + * @param string Attribute name + * @param string Attribute value, null if attribute is being removed + */ + protected function onAttributeChange($name, $value = null) + { + if ('id' == $name) { + throw new HTML_QuickForm2_InvalidArgumentException( + "Attribute 'id' is read-only" + ); + } + parent::onAttributeChange($name, $value); + } + + /** + * This element is rendered using renderHidden() method + * + * renderHidden() is used to + * - prevent using the standard element template as this button is + * expected to be hidden + * - render it above all other submit buttons since hidden elements + * are usually at the top of the form + * + * @param HTML_QuickForm2_Renderer Renderer instance + * @return HTML_QuickForm2_Renderer + */ + public function render(HTML_QuickForm2_Renderer $renderer) + { + $renderer->renderHidden($this); + return $renderer; + } +} +?> diff --git a/libs/HTML/QuickForm2/Controller/Page.php b/libs/HTML/QuickForm2/Controller/Page.php new file mode 100644 index 0000000000..1d639161d6 --- /dev/null +++ b/libs/HTML/QuickForm2/Controller/Page.php @@ -0,0 +1,258 @@ +<?php +/** + * Class representing a page of a multipage form + * + * PHP version 5 + * + * LICENSE: + * + * Copyright (c) 2006-2010, Alexey Borzov <avb@php.net>, + * Bertrand Mansion <golgote@mamasam.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * The names of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version SVN: $Id: Page.php 295963 2010-03-08 14:33:43Z avb $ + * @link http://pear.php.net/package/HTML_QuickForm2 + */ + +/** + * Class representing a page of a multipage form + * + * Unlike old HTML_QuickForm_Controller, this does not extend HTML_QuickForm2 + * but accepts an instance of that in the constructor. You need to create a + * subclass of this class and implement its populateForm() method. + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @version Release: @package_version@ + */ +abstract class HTML_QuickForm2_Controller_Page +{ + /** + * Button name template (needs form ID and action name substituted by sprintf()) + */ + const KEY_NAME = '_qf_%s_%s'; + + /** + * Whether populateForm() was already called + * @var boolean + */ + private $_formPopulated = false; + + /** + * The form wrapped by this page + * @var HTML_QuickForm2 + */ + protected $form = null; + + /** + * Controller this page belongs to + * @var HTML_QuickForm2_Controller + */ + protected $controller = null; + + /** + * Contains the mapping of action names to handlers (objects implementing HTML_QuickForm2_Controller_Action) + * @var array + */ + protected $handlers = array(); + + /** + * Class constructor, accepts the form to wrap around + * + * @param HTML_QuickForm2 + */ + public function __construct(HTML_QuickForm2 $form) + { + $this->form = $form; + } + + /** + * Returns the form this page wraps around + * + * @return HTML_QuickForm2 + */ + public function getForm() + { + return $this->form; + } + + /** + * Sets the controller owning the page + * + * @param HTML_QuickForm2_Controller controller the page belongs to + */ + public function setController(HTML_QuickForm2_Controller $controller) + { + $this->controller = $controller; + } + + /** + * Returns the controller owning this page + * + * @return HTML_QuickForm2_Controller + */ + public function getController() + { + return $this->controller; + } + + /** + * Adds a handler for a specific action + * + * @param string action name + * @param HTML_QuickForm2_Controller_Action the handler for the action + */ + public function addHandler($actionName, HTML_QuickForm2_Controller_Action $action) + { + $this->handlers[$actionName] = $action; + } + + /** + * Handles an action + * + * If the page does not contain a handler for this action, controller's + * handle() method will be called. + * + * @param string Name of the action + * @throws HTML_QuickForm2_NotFoundException if handler for an action is missing + */ + public function handle($actionName) + { + if (isset($this->handlers[$actionName])) { + return $this->handlers[$actionName]->perform($this, $actionName); + } else { + return $this->getController()->handle($this, $actionName); + } + } + + /** + * Returns a name for a submit button that will invoke a specific action + * + * @param string Name of the action + * @return string "name" attribute for a submit button + */ + public function getButtonName($actionName) + { + return sprintf(self::KEY_NAME, $this->getForm()->getId(), $actionName); + } + + /** + * Sets the default action invoked on page-form submit + * + * This is necessary as the user may just press Enter instead of + * clicking one of the named submit buttons and then no action name will + * be passed to the script. + * + * @param string Default action name + * @param string Path to a 1x1 transparent GIF image + * @return object Returns the image input used for default action + */ + public function setDefaultAction($actionName, $imageSrc = '') + { + require_once 'HTML/QuickForm2/Controller/DefaultAction.php'; + + if (0 == count($this->form)) { + $image = $this->form->appendChild( + new HTML_QuickForm2_Controller_DefaultAction( + $this->getButtonName($actionName), array('src' => $imageSrc) + ) + ); + + // replace the existing DefaultAction + } elseif ($image = $this->form->getElementById('_qf_default')) { + $image->setName($this->getButtonName($actionName)) + ->setAttribute('src', $imageSrc); + + // Inject the element to the first position to improve chances that + // it ends up on top in the output + } else { + $it = $this->form->getIterator(); + $it->rewind(); + $image = $this->form->insertBefore( + new HTML_QuickForm2_Controller_DefaultAction( + $this->getButtonName($actionName), array('src' => $imageSrc) + ), + $it->current() + ); + } + return $image; + } + + /** + * Wrapper around populateForm() ensuring that it is only called once + */ + final public function populateFormOnce() + { + if (!$this->_formPopulated) { + if (!empty($this->controller) && $this->controller->propagateId()) { + $this->form->addElement( + 'hidden', HTML_QuickForm2_Controller::KEY_ID, + array('id' => HTML_QuickForm2_Controller::KEY_ID) + )->setValue($this->controller->getId()); + } + $this->populateForm(); + $this->_formPopulated = true; + } + } + + /** + * Populates the form with the elements + * + * The implementation of this method in your subclass of + * HTML_QuickForm2_Controller_Page should contain all the necessary + * addElement(), addRule() etc. calls. The method will only be called if + * needed to prevent wasting resources on the forms that aren't going to + * be seen by the user. + */ + abstract protected function populateForm(); + + /** + * Stores the form values (and validation status) is session container + * + * @param bool Whether to store validation status + */ + public function storeValues($validate = true) + { + $this->populateFormOnce(); + $container = $this->getController()->getSessionContainer(); + $id = $this->form->getId(); + + $container->storeValues($id, (array)$this->form->getValue()); + if ($validate) { + $container->storeValidationStatus($id, $this->form->validate()); + } + return $container->getValidationStatus($id); + } +} +?>
\ No newline at end of file diff --git a/libs/HTML/QuickForm2/Controller/SessionContainer.php b/libs/HTML/QuickForm2/Controller/SessionContainer.php new file mode 100644 index 0000000000..14b8674b1a --- /dev/null +++ b/libs/HTML/QuickForm2/Controller/SessionContainer.php @@ -0,0 +1,195 @@ +<?php +/** + * Object wrapping around session variable used to store controller data + * + * PHP version 5 + * + * LICENSE: + * + * Copyright (c) 2006-2010, Alexey Borzov <avb@php.net>, + * Bertrand Mansion <golgote@mamasam.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * The names of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version SVN: $Id: SessionContainer.php 293868 2010-01-23 18:37:16Z avb $ + * @link http://pear.php.net/package/HTML_QuickForm2 + */ + +/** + * Object wrapping around session variable used to store controller data + * + * Unlike old HTML_QuickForm_Controller, this does not extend HTML_QuickForm2 + * but accepts an instance of that in the constructor. You need to create a + * subclass of this class and implement its populateForm() method. + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @version Release: @package_version@ + */ +class HTML_QuickForm2_Controller_SessionContainer +{ + /** + * A reference to a key in $_SESSION superglobal array + * @var array + */ + protected $data; + + /** + * Class constructor + * + * Initializes a variable in $_SESSION array, its name is based upon the + * name of the Controller passed here + * + * @param HTML_QuickForm2_Controller + */ + public function __construct(HTML_QuickForm2_Controller $controller) + { + $name = sprintf(HTML_QuickForm2_Controller::KEY_CONTAINER, + $controller->getId()); + if (empty($_SESSION[$name])) { + $_SESSION[$name] = array( + 'datasources' => array(), + 'values' => array(), + 'valid' => array() + ); + } + $this->data =& $_SESSION[$name]; + } + + /** + * Stores the page submit values + * + * @param string Page ID + * @param array Page submit values + */ + public function storeValues($pageId, array $values) + { + $this->data['values'][$pageId] = $values; + } + + /** + * Returns the page values kept in session + * + * @param string Page ID + * @return array + */ + public function getValues($pageId) + { + return array_key_exists($pageId, $this->data['values']) + ? $this->data['values'][$pageId]: array(); + } + + /** + * Stores the page validation status + * + * @param string Page ID + * @param bool Whether the page is valid + */ + public function storeValidationStatus($pageId, $status) + { + $this->data['valid'][$pageId] = (bool)$status; + } + + /** + * Returns the page validation status kept in session + * + * @param string Page ID + * @return bool + */ + public function getValidationStatus($pageId) + { + return array_key_exists($pageId, $this->data['valid']) + ? $this->data['valid'][$pageId]: null; + + } + + /** + * Stores the controller data sources + * + * @param array A new data source list + * @throws HTML_QuickForm2_InvalidArgumentException if given array + * contains something that is not a valid data source + */ + public function storeDatasources(array $datasources) + { + foreach ($datasources as $ds) { + if (!$ds instanceof HTML_QuickForm2_DataSource) { + throw new HTML_QuickForm2_InvalidArgumentException( + 'Array should contain only DataSource instances' + ); + } + } + $this->data['datasources'] = $datasources; + } + + /** + * Returns the controller data sources + * + * @return array + */ + public function getDatasources() + { + return $this->data['datasources']; + } + + /** + * Stores some user-supplied parameter alongside controller data + * + * It is sometimes useful to pass some additional user data between pages + * of the form, thus this method. It will be removed with all the other + * data by {@link HTML_QuickForm2_Controller::destroySessionContainer()} + * + * @param string Parameter name + * @param string Parameter value + */ + public function storeOpaque($name, $value) + { + if (!array_key_exists('opaque', $this->data)) { + $this->data['opaque'] = array(); + } + $this->data['opaque'][$name] = $value; + } + + /** + * Returns a user-supplied parameter + * + * @param string Parameter name + * @return mixed + */ + public function getOpaque($name) + { + return (array_key_exists('opaque', $this->data) + && array_key_exists($name, $this->data['opaque'])) + ? $this->data['opaque'][$name]: null; + } +}
\ No newline at end of file diff --git a/libs/HTML/QuickForm2/DataSource.php b/libs/HTML/QuickForm2/DataSource.php new file mode 100644 index 0000000000..9bd3a4a004 --- /dev/null +++ b/libs/HTML/QuickForm2/DataSource.php @@ -0,0 +1,67 @@ +<?php +/** + * Interface for data sources used by HTML_QuickForm2 objects + * + * PHP version 5 + * + * LICENSE: + * + * Copyright (c) 2006-2010, Alexey Borzov <avb@php.net>, + * Bertrand Mansion <golgote@mamasam.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * The names of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version SVN: $Id: DataSource.php 300722 2010-06-24 10:15:52Z mansion $ + * @link http://pear.php.net/package/HTML_QuickForm2 + */ + +/** + * Interface for data sources used by HTML_QuickForm2 objects + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @version Release: @package_version@ + */ +interface HTML_QuickForm2_DataSource +{ + /** + * Returns value for the element with the given name + * + * If data source doesn't have a requested value it should return null + * + * @param string Element's name + * @return mixed Element's value + */ + public function getValue($name); +} +?> diff --git a/libs/HTML/QuickForm2/DataSource/Array.php b/libs/HTML/QuickForm2/DataSource/Array.php new file mode 100644 index 0000000000..8bb2a2959e --- /dev/null +++ b/libs/HTML/QuickForm2/DataSource/Array.php @@ -0,0 +1,101 @@ +<?php +/** + * Array-based data source for HTML_QuickForm2 objects + * + * PHP version 5 + * + * LICENSE: + * + * Copyright (c) 2006-2010, Alexey Borzov <avb@php.net>, + * Bertrand Mansion <golgote@mamasam.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * The names of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version SVN: $Id: Array.php 294057 2010-01-26 21:10:28Z avb $ + * @link http://pear.php.net/package/HTML_QuickForm2 + */ + +/** + * Interface for data sources used by HTML_QuickForm2 objects + */ +require_once 'HTML/QuickForm2/DataSource.php'; + +/** + * Array-based data source for HTML_QuickForm2 objects + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @version Release: @package_version@ + */ +class HTML_QuickForm2_DataSource_Array implements HTML_QuickForm2_DataSource +{ + /** + * Array containing elements' values + * @var array + */ + protected $values; + + /** + * Class constructor, initializes the values array + * + * @param array Array containing the elements' values + */ + public function __construct($values = array()) + { + $this->values = $values; + } + + public function getValue($name) + { + if (empty($this->values)) { + return null; + } + if (strpos($name, '[')) { + $tokens = explode('[', str_replace(']', '', $name)); + $value = $this->values; + do { + $token = array_shift($tokens); + if (!isset($value[$token])) { + return null; + } + $value = $value[$token]; + } while (!empty($tokens)); + return $value; + } elseif (isset($this->values[$name])) { + return $this->values[$name]; + } else { + return null; + } + } +} +?> diff --git a/libs/HTML/QuickForm2/DataSource/Session.php b/libs/HTML/QuickForm2/DataSource/Session.php new file mode 100644 index 0000000000..e4634557af --- /dev/null +++ b/libs/HTML/QuickForm2/DataSource/Session.php @@ -0,0 +1,78 @@ +<?php +/** + * Class presenting the values stored in session by Controller as submitted ones + * + * PHP version 5 + * + * LICENSE: + * + * Copyright (c) 2006-2010, Alexey Borzov <avb@php.net>, + * Bertrand Mansion <golgote@mamasam.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * The names of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version SVN: $Id: Session.php 293411 2010-01-11 16:51:32Z avb $ + * @link http://pear.php.net/package/HTML_QuickForm2 + */ + +/** Interface for data sources containing submitted values */ +require_once 'HTML/QuickForm2/DataSource/Submit.php'; + +/** Array-based data source for HTML_QuickForm2 objects */ +require_once 'HTML/QuickForm2/DataSource/Array.php'; + +/** + * Class presenting the values stored in session by Controller as submitted ones + * + * This is a less hackish implementation of loadValues() method in old + * HTML_QuickForm_Controller. The values need to be presented as submitted so + * that elements like checkboxes and multiselects do not try to use default + * values from subsequent datasources. + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @version Release: @package_version@ + */ +class HTML_QuickForm2_DataSource_Session + extends HTML_QuickForm2_DataSource_Array + implements HTML_QuickForm2_DataSource_Submit +{ + /** + * File upload data is not stored in the session + */ + public function getUpload($name) + { + return null; + } +} +?> diff --git a/libs/HTML/QuickForm2/DataSource/Submit.php b/libs/HTML/QuickForm2/DataSource/Submit.php new file mode 100644 index 0000000000..fa9f6d3648 --- /dev/null +++ b/libs/HTML/QuickForm2/DataSource/Submit.php @@ -0,0 +1,76 @@ +<?php +/** + * Interface for data sources containing submitted values + * + * PHP version 5 + * + * LICENSE: + * + * Copyright (c) 2006-2010, Alexey Borzov <avb@php.net>, + * Bertrand Mansion <golgote@mamasam.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * The names of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version SVN: $Id: Submit.php 300722 2010-06-24 10:15:52Z mansion $ + * @link http://pear.php.net/package/HTML_QuickForm2 + */ + +/** + * Interface for data sources used by HTML_QuickForm2 objects + */ +require_once 'HTML/QuickForm2/DataSource.php'; + +/** + * Interface for data sources containing submitted values + * + * This interface provides method for getting information on uploaded files. + * Additionally some elements will only consider getting their values from data + * sources implementing this interface. + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @version Release: @package_version@ + */ +interface HTML_QuickForm2_DataSource_Submit extends HTML_QuickForm2_DataSource +{ + /** + * Returns the information about uploaded file + * + * If data source doesn't such information it should return null + * + * @param string Name of file upload field + * @return array|null Information on uploaded file, from $_FILES array + */ + public function getUpload($name); +} +?> diff --git a/libs/HTML/QuickForm2/DataSource/SuperGlobal.php b/libs/HTML/QuickForm2/DataSource/SuperGlobal.php new file mode 100644 index 0000000000..38fd7906d7 --- /dev/null +++ b/libs/HTML/QuickForm2/DataSource/SuperGlobal.php @@ -0,0 +1,170 @@ +<?php +/** + * Data source for HTML_QuickForm2 objects based on superglobal arrays + * + * PHP version 5 + * + * LICENSE: + * + * Copyright (c) 2006-2010, Alexey Borzov <avb@php.net>, + * Bertrand Mansion <golgote@mamasam.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * The names of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version SVN: $Id: SuperGlobal.php 294057 2010-01-26 21:10:28Z avb $ + * @link http://pear.php.net/package/HTML_QuickForm2 + */ + +/** + * Interface for data sources containing submitted values + */ +require_once 'HTML/QuickForm2/DataSource/Submit.php'; + +/** + * Array-based data source for HTML_QuickForm2 objects + */ +require_once 'HTML/QuickForm2/DataSource/Array.php'; + +/** + * Data source for HTML_QuickForm2 objects based on superglobal arrays + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @version Release: @package_version@ + */ +class HTML_QuickForm2_DataSource_SuperGlobal + extends HTML_QuickForm2_DataSource_Array + implements HTML_QuickForm2_DataSource_Submit +{ + /** + * Information on file uploads (from $_FILES) + * @var array + */ + protected $files = array(); + + /** + * Keys present in the $_FILES array + * @var array + */ + private static $_fileKeys = array('name', 'type', 'size', 'tmp_name', 'error'); + + /** + * Class constructor, intializes the internal arrays from superglobals + * + * @param string Request method (GET or POST) + * @param bool Whether magic_quotes_gpc directive is on + */ + public function __construct($requestMethod = 'POST', $magicQuotesGPC = false) + { + if (!$magicQuotesGPC) { + if ('GET' == strtoupper($requestMethod)) { + $this->values = $_GET; + } else { + $this->values = $_POST; + $this->files = $_FILES; + } + } else { + if ('GET' == strtoupper($requestMethod)) { + $this->values = $this->arrayMapRecursive('stripslashes', $_GET); + } else { + $this->values = $this->arrayMapRecursive('stripslashes', $_POST); + foreach ($_FILES as $key1 => $val1) { + foreach ($val1 as $key2 => $val2) { + if ('name' == $key2) { + $this->files[$key1][$key2] = $this->arrayMapRecursive( + 'stripslashes', $val2 + ); + } else { + $this->files[$key1][$key2] = $val2; + } + } + } + } + } + } + + /** + * A recursive version of array_map() function + * + * @param callback Callback function to apply + * @param mixed Input array + * @return array with callback applied + */ + protected function arrayMapRecursive($callback, $arr) + { + if (!is_array($arr)) { + return call_user_func($callback, $arr); + } + $mapped = array(); + foreach ($arr as $k => $v) { + $mapped[$k] = is_array($v)? + $this->arrayMapRecursive($callback, $v): + call_user_func($callback, $v); + } + return $mapped; + } + + public function getUpload($name) + { + if (empty($this->files)) { + return null; + } + if (false !== ($pos = strpos($name, '['))) { + $tokens = explode('[', str_replace(']', '', $name)); + $base = array_shift($tokens); + $value = array(); + if (!isset($this->files[$base]['name'])) { + return null; + } + foreach (self::$_fileKeys as $key) { + $value[$key] = $this->files[$base][$key]; + } + + do { + $token = array_shift($tokens); + if (!isset($value['name'][$token])) { + return null; + } + foreach (self::$_fileKeys as $key) { + $value[$key] = $value[$key][$token]; + } + } while (!empty($tokens)); + return $value; + } elseif(isset($this->files[$name])) { + return $this->files[$name]; + } else { + return null; + } + } +} +?> diff --git a/libs/HTML/QuickForm2/Element.php b/libs/HTML/QuickForm2/Element.php new file mode 100644 index 0000000000..b89e6b8b6f --- /dev/null +++ b/libs/HTML/QuickForm2/Element.php @@ -0,0 +1,133 @@ +<?php +/** + * Base class for simple HTML_QuickForm2 elements (not Containers) + * + * PHP version 5 + * + * LICENSE: + * + * Copyright (c) 2006-2010, Alexey Borzov <avb@php.net>, + * Bertrand Mansion <golgote@mamasam.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * The names of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version SVN: $Id: Element.php 299706 2010-05-24 18:32:37Z avb $ + * @link http://pear.php.net/package/HTML_QuickForm2 + */ + +/** + * Base class for all HTML_QuickForm2 elements + */ +require_once 'HTML/QuickForm2/Node.php'; + +/** + * Abstract base class for simple QuickForm2 elements (not Containers) + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @version Release: @package_version@ + */ +abstract class HTML_QuickForm2_Element extends HTML_QuickForm2_Node +{ + public function setName($name) + { + $this->attributes['name'] = (string)$name; + $this->updateValue(); + return $this; + } + + /** + * Generates hidden form field containing the element's value + * + * This is used to pass the frozen element's value if 'persistent freeze' + * feature is on + * + * @return string + */ + protected function getPersistentContent() + { + if (!$this->persistent || null === ($value = $this->getValue())) { + return ''; + } + return '<input type="hidden"' . self::getAttributesString(array( + 'name' => $this->getName(), + 'value' => $value, + 'id' => $this->getId() + )) . ' />'; + } + + /** + * Called when the element needs to update its value from form's data sources + * + * The default behaviour is to go through the complete list of the data + * sources until the non-null value is found. + */ + protected function updateValue() + { + $name = $this->getName(); + foreach ($this->getDataSources() as $ds) { + if (null !== ($value = $ds->getValue($name))) { + $this->setValue($value); + return; + } + } + } + + /** + * Renders the element using the given renderer + * + * @param HTML_QuickForm2_Renderer Renderer instance + * @return HTML_QuickForm2_Renderer + */ + public function render(HTML_QuickForm2_Renderer $renderer) + { + foreach ($this->rules as $rule) { + if ($rule[1] & HTML_QuickForm2_Rule::RUNAT_CLIENT) { + $renderer->getJavascriptBuilder()->addRule($rule[0]); + } + } + $renderer->renderElement($this); + return $renderer; + } + + /** + * Returns Javascript code for getting the element's value + * + * @return string + */ + public function getJavascriptValue() + { + return "qf.form.getValue(document.getElementById('" . $this->getId() . "'))"; + } +} +?> diff --git a/libs/HTML/QuickForm2/Element/Button.php b/libs/HTML/QuickForm2/Element/Button.php new file mode 100644 index 0000000000..8fb87b1f1b --- /dev/null +++ b/libs/HTML/QuickForm2/Element/Button.php @@ -0,0 +1,161 @@ +<?php +/** + * Class for <button> elements + * + * PHP version 5 + * + * LICENSE: + * + * Copyright (c) 2006-2010, Alexey Borzov <avb@php.net>, + * Bertrand Mansion <golgote@mamasam.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * The names of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version SVN: $Id: Button.php 300722 2010-06-24 10:15:52Z mansion $ + * @link http://pear.php.net/package/HTML_QuickForm2 + */ + +/** + * Base class for simple HTML_QuickForm2 elements + */ +require_once 'HTML/QuickForm2/Element.php'; + +/** + * Class for <button> elements + * + * Note that this element was named 'xbutton' in previous version of QuickForm, + * the name 'button' being used for current 'inputbutton' element. + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @version Release: @package_version@ + */ +class HTML_QuickForm2_Element_Button extends HTML_QuickForm2_Element +{ + /** + * Contains options and data used for the element creation + * - content: Content to be displayed between <button></button> tags + * @var array + */ + protected $data = array('content' => ''); + + /** + * Element's submit value + * @var string + */ + protected $submitValue = null; + + + public function getType() + { + return 'button'; + } + + /** + * Buttons can not be frozen + * + * @param bool Whether element should be frozen or editable. This + * parameter is ignored in case of buttons + * @return bool Always returns false + */ + public function toggleFrozen($freeze = null) + { + return false; + } + + /** + * Sets the contents of the button element + * + * @param string Button content (HTML to add between <button></button> tags) + * @return HTML_QuickForm2_Element_Button + */ + function setContent($content) + { + $this->data['content'] = $content; + return $this; + } + + /** + * Button's value cannot be set via this method + * + * @param mixed Element's value, this parameter is ignored + * @return HTML_QuickForm2_Element_Button + */ + public function setValue($value) + { + return $this; + } + + /** + * Returns the element's value + * + * The value is only returned if the following is true + * - button has 'type' attribute set to 'submit' (or no 'type' attribute) + * - the form was submitted by clicking on this button + * + * This method returns the actual value submitted by the browser. Note that + * different browsers submit different values! + * + * @return string|null + */ + public function getValue() + { + if ((empty($this->attributes['type']) || 'submit' == $this->attributes['type']) && + !$this->getAttribute('disabled')) + { + return $this->applyFilters($this->submitValue); + } else { + return null; + } + } + + public function __toString() + { + return $this->getIndent() . '<button' . $this->getAttributes(true) . + '>' . $this->data['content'] . '</button>'; + } + + protected function updateValue() + { + foreach ($this->getDataSources() as $ds) { + if ($ds instanceof HTML_QuickForm2_DataSource_Submit && + null !== ($value = $ds->getValue($this->getName()))) + { + $this->submitValue = $value; + return; + } + } + $this->submitValue = null; + } +} +?> diff --git a/libs/HTML/QuickForm2/Element/Date.php b/libs/HTML/QuickForm2/Element/Date.php new file mode 100644 index 0000000000..4b98a8a457 --- /dev/null +++ b/libs/HTML/QuickForm2/Element/Date.php @@ -0,0 +1,503 @@ +<?php +/** + * Date element + * + * PHP version 5 + * + * LICENSE: + * + * Copyright (c) 2006-2009, Alexey Borzov <avb@php.net>, + * Bertrand Mansion <golgote@mamasam.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * The names of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version SVN: $Id: Date.php 297453 2010-04-04 10:22:39Z mansion $ + * @link http://pear.php.net/package/HTML_QuickForm2 + */ + +/** + * Base class for HTML_QuickForm2 group of elements + */ +require_once 'HTML/QuickForm2/Container/Group.php'; +/** + * Base class for HTML_QuickForm2 select element + */ +require_once 'HTML/QuickForm2/Element/Select.php'; + +/** + * Class for a group of elements used to input dates (and times). + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @version Release: @package_version@ + */ +class HTML_QuickForm2_Element_Date extends HTML_QuickForm2_Container_Group +{ + public function getType() + { + return 'date'; + } + + /** + * Various options to control the element's display. + * @var array + */ + protected $data = array( + 'language' => 'en', + 'format' => 'dMY', + 'minYear' => 2001, + 'maxYear' => 2010, + 'addEmptyOption' => false, + 'emptyOptionValue' => '', + 'emptyOptionText' => ' ', + 'optionIncrement' => array('i' => 1, 's' => 1) + ); + + /** + * Class constructor + * + * The following keys may appear in $data array: + * - 'language': date language + * - 'format': Format of the date, based on PHP's date() function. + * The following characters are currently recognised in format string: + * <pre> + * D => Short names of days + * l => Long names of days + * d => Day numbers + * M => Short names of months + * F => Long names of months + * m => Month numbers + * Y => Four digit year + * y => Two digit year + * h => 12 hour format + * H => 23 hour format + * i => Minutes + * s => Seconds + * a => am/pm + * A => AM/PM + * </pre> + * - 'minYear': Minimum year in year select + * - 'maxYear': Maximum year in year select + * - 'addEmptyOption': Should an empty option be added to the top of + * each select box? + * - 'emptyOptionValue': The value passed by the empty option. + * - 'emptyOptionText': The text displayed for the empty option. + * - 'optionIncrement': Step to increase the option values by (works for 'i' and 's') + * + * @param string Element name + * @param mixed Attributes (either a string or an array) + * @param array Element data (label, options and data used for element creation) + */ + public function __construct($name = null, $attributes = null, $data = null) + { + parent::__construct($name, $attributes, $data); + + $locale =& $this->locale[$this->data['language']]; + $backslash = false; + $separators = array(); + $separator = ''; + + for ($i = 0, $length = strlen($this->data['format']); $i < $length; $i++) { + $sign = $this->data['format']{$i}; + if ($backslash) { + $backslash = false; + $separator .= $sign; + } else { + $loadSelect = true; + switch ($sign) { + case 'D': + // Sunday is 0 like with 'w' in date() + $options = $locale['weekdays_short']; + break; + case 'l': + $options = $locale['weekdays_long']; + break; + case 'd': + $options = $this->createOptionList(1, 31); + break; + case 'M': + $options = $locale['months_short']; + array_unshift($options , ''); + unset($options[0]); + break; + case 'm': + $options = $this->createOptionList(1, 12); + break; + case 'F': + $options = $locale['months_long']; + array_unshift($options , ''); + unset($options[0]); + break; + case 'Y': + $options = $this->createOptionList( + $this->data['minYear'], + $this->data['maxYear'], + $this->data['minYear'] > $this->data['maxYear']? -1: 1 + ); + break; + case 'y': + $options = $this->createOptionList( + $this->data['minYear'], + $this->data['maxYear'], + $this->data['minYear'] > $this->data['maxYear']? -1: 1 + ); + array_walk($options, create_function('&$v,$k','$v = substr($v,-2);')); + break; + case 'h': + $options = $this->createOptionList(1, 12); + break; + case 'g': + $options = $this->createOptionList(1, 12); + array_walk($options, create_function('&$v,$k', '$v = intval($v);')); + break; + case 'H': + $options = $this->createOptionList(0, 23); + break; + case 'i': + $options = $this->createOptionList(0, 59, $this->data['optionIncrement']['i']); + break; + case 's': + $options = $this->createOptionList(0, 59, $this->data['optionIncrement']['s']); + break; + case 'a': + $options = array('am' => 'am', 'pm' => 'pm'); + break; + case 'A': + $options = array('AM' => 'AM', 'PM' => 'PM'); + break; + case 'W': + $options = $this->createOptionList(1, 53); + break; + case '\\': + $backslash = true; + $loadSelect = false; + break; + default: + $separator .= (' ' == $sign? ' ': $sign); + $loadSelect = false; + } + + if ($loadSelect) { + if (0 < count($this)) { + $separators[] = $separator; + } + $separator = ''; + // Should we add an empty option to the top of the select? + if (!is_array($this->data['addEmptyOption']) && $this->data['addEmptyOption'] || + is_array($this->data['addEmptyOption']) && !empty($this->data['addEmptyOption'][$sign])) { + + // Using '+' array operator to preserve the keys + if (is_array($this->data['emptyOptionText']) && !empty($this->data['emptyOptionText'][$sign])) { + $options = array($this->data['emptyOptionValue'] => $this->data['emptyOptionText'][$sign]) + $options; + } else { + $options = array($this->data['emptyOptionValue'] => $this->data['emptyOptionText']) + $options; + } + } + $this->addSelect($sign, $this->getAttributes())->loadOptions($options); + } + } + } + $separators[] = $separator . ($backslash? '\\': ''); + $this->setSeparator($separators); + } + + /** + * Creates an option list containing the numbers from the start number to the end, inclusive + * + * @param int The start number + * @param int The end number + * @param int Increment by this value + * @return array An array of numeric options. + */ + protected function createOptionList($start, $end, $step = 1) + { + for ($i = $start, $options = array(); $start > $end? $i >= $end: $i <= $end; $i += $step) { + $options[$i] = sprintf('%02d', $i); + } + return $options; + } + + /** + * Trims leading zeros from the (numeric) string + * + * @param string A numeric string, possibly with leading zeros + * @return string String with leading zeros removed + */ + protected function trimLeadingZeros($str) + { + if (0 == strcmp($str, $this->data['emptyOptionValue'])) { + return $str; + } + $trimmed = ltrim($str, '0'); + return strlen($trimmed)? $trimmed: '0'; + } + + + /** + * Tries to convert the given value to a usable date before setting the + * element value + * @param int|string|array A timestamp, a string compatible with strtotime() + * or an array that fits the element names + */ + public function setValue($value) + { + if (empty($value)) { + $value = array(); + } elseif (is_scalar($value)) { + if (!is_numeric($value)) { + $value = strtotime($value); + } + // might be a unix epoch, then we fill all possible values + $arr = explode('-', date('w-j-n-Y-g-G-i-s-a-A-W', (int)$value)); + $value = array( + 'D' => $arr[0], + 'l' => $arr[0], + 'd' => $arr[1], + 'M' => $arr[2], + 'm' => $arr[2], + 'F' => $arr[2], + 'Y' => $arr[3], + 'y' => $arr[3], + 'h' => $arr[4], + 'g' => $arr[4], + 'H' => $arr[5], + 'i' => $this->trimLeadingZeros($arr[6]), + 's' => $this->trimLeadingZeros($arr[7]), + 'a' => $arr[8], + 'A' => $arr[9], + 'W' => $this->trimLeadingZeros($arr[10]) + ); + } else { + $value = array_map(array($this, 'trimLeadingZeros'), $value); + } + return parent::setValue($value); + } + + /** + * Called when the element needs to update its value from form's data sources + * + * Since the date element also accepts a timestamp as value, the default + * group behavior is changed. + */ + protected function updateValue() + { + $name = $this->getName(); + foreach ($this->getDataSources() as $ds) { + if (null !== ($value = $ds->getValue($name))) { + $this->setValue($value); + return; + } + } + parent::updateValue(); + } + + /** + * Options in different languages + * + * Note to potential translators: to avoid encoding problems please send + * your translations with "weird" letters encoded as HTML Unicode entities + * + * @var array + */ + protected $locale = array( + 'en' => array ( + 'weekdays_short'=> array ('Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'), + 'weekdays_long' => array ('Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'), + 'months_short' => array ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'months_long' => array ('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December') + ), + 'de' => array ( + 'weekdays_short'=> array ('So', 'Mon', 'Di', 'Mi', 'Do', 'Fr', 'Sa'), + 'weekdays_long' => array ('Sonntag', 'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag'), + 'months_short' => array ('Jan', 'Feb', 'März', 'April', 'Mai', 'Juni', 'Juli', 'Aug', 'Sept', 'Okt', 'Nov', 'Dez'), + 'months_long' => array ('Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember') + ), + 'fr' => array ( + 'weekdays_short'=> array ('Dim', 'Lun', 'Mar', 'Mer', 'Jeu', 'Ven', 'Sam'), + 'weekdays_long' => array ('Dimanche', 'Lundi', 'Mardi', 'Mercredi', 'Jeudi', 'Vendredi', 'Samedi'), + 'months_short' => array ('Jan', 'Fév', 'Mar', 'Avr', 'Mai', 'Juin', 'Juil', 'Août', 'Sep', 'Oct', 'Nov', 'Déc'), + 'months_long' => array ('Janvier', 'Février', 'Mars', 'Avril', 'Mai', 'Juin', 'Juillet', 'Août', 'Septembre', 'Octobre', 'Novembre', 'Décembre') + ), + 'hu' => array ( + 'weekdays_short'=> array ('V', 'H', 'K', 'Sze', 'Cs', 'P', 'Szo'), + 'weekdays_long' => array ('vasárnap', 'hétfő', 'kedd', 'szerda', 'csütörtök', 'péntek', 'szombat'), + 'months_short' => array ('jan', 'feb', 'márc', 'ápr', 'máj', 'jún', 'júl', 'aug', 'szept', 'okt', 'nov', 'dec'), + 'months_long' => array ('január', 'február', 'március', 'április', 'május', 'június', 'július', 'augusztus', 'szeptember', 'október', 'november', 'december') + ), + 'pl' => array ( + 'weekdays_short'=> array ('Nie', 'Pn', 'Wt', 'Śr', 'Czw', 'Pt', 'Sob'), + 'weekdays_long' => array ('Niedziela', 'Poniedziałek', 'Wtorek', 'Środa', 'Czwartek', 'Piątek', 'Sobota'), + 'months_short' => array ('Sty', 'Lut', 'Mar', 'Kwi', 'Maj', 'Cze', 'Lip', 'Sie', 'Wrz', 'Paź', 'Lis', 'Gru'), + 'months_long' => array ('Styczeń', 'Luty', 'Marzec', 'Kwiecień', 'Maj', 'Czerwiec', 'Lipiec', 'Sierpień', 'Wrzesień', 'Październik', 'Listopad', 'Grudzień') + ), + 'sl' => array ( + 'weekdays_short'=> array ('Ned', 'Pon', 'Tor', 'Sre', 'Cet', 'Pet', 'Sob'), + 'weekdays_long' => array ('Nedelja', 'Ponedeljek', 'Torek', 'Sreda', 'Cetrtek', 'Petek', 'Sobota'), + 'months_short' => array ('Jan', 'Feb', 'Mar', 'Apr', 'Maj', 'Jun', 'Jul', 'Avg', 'Sep', 'Okt', 'Nov', 'Dec'), + 'months_long' => array ('Januar', 'Februar', 'Marec', 'April', 'Maj', 'Junij', 'Julij', 'Avgust', 'September', 'Oktober', 'November', 'December') + ), + 'ru' => array ( + 'weekdays_short'=> array ('Вс', 'Пн', 'Вт', 'Ср', 'Чт', 'Пт', 'Сб'), + 'weekdays_long' => array ('Воскресенье', 'Понедельник', 'Вторник', 'Среда', 'Четверг', 'Пятница', 'Суббота'), + 'months_short' => array ('Янв', 'Фев', 'Мар', 'Апр', 'Май', 'Июн', 'Июл', 'Авг', 'Сен', 'Окт', 'Ноя', 'Дек'), + 'months_long' => array ('Январь', 'Февраль', 'Март', 'Апрель', 'Май', 'Июнь', 'Июль', 'Август', 'Сентябрь', 'Октябрь', 'Ноябрь', 'Декабрь') + ), + 'es' => array ( + 'weekdays_short'=> array ('Dom', 'Lun', 'Mar', 'Mié', 'Jue', 'Vie', 'Sáb'), + 'weekdays_long' => array ('Domingo', 'Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado'), + 'months_short' => array ('Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', 'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic'), + 'months_long' => array ('Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre') + ), + 'da' => array ( + 'weekdays_short'=> array ('Søn', 'Man', 'Tir', 'Ons', 'Tor', 'Fre', 'Lør'), + 'weekdays_long' => array ('Søndag', 'Mandag', 'Tirsdag', 'Onsdag', 'Torsdag', 'Fredag', 'Lørdag'), + 'months_short' => array ('Jan', 'Feb', 'Mar', 'Apr', 'Maj', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dec'), + 'months_long' => array ('Januar', 'Februar', 'Marts', 'April', 'Maj', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'December') + ), + 'is' => array ( + 'weekdays_short'=> array ('Sun', 'Mán', 'Þri', 'Mið', 'Fim', 'Fös', 'Lau'), + 'weekdays_long' => array ('Sunnudagur', 'Mánudagur', 'Þriðjudagur', 'Miðvikudagur', 'Fimmtudagur', 'Föstudagur', 'Laugardagur'), + 'months_short' => array ('Jan', 'Feb', 'Mar', 'Apr', 'Maí', 'Jún', 'Júl', 'Ágú', 'Sep', 'Okt', 'Nóv', 'Des'), + 'months_long' => array ('Janúar', 'Febrúar', 'Mars', 'Apríl', 'Maí', 'Júní', 'Júlí', 'Ágúst', 'September', 'Október', 'Nóvember', 'Desember') + ), + 'it' => array ( + 'weekdays_short'=> array ('Dom', 'Lun', 'Mar', 'Mer', 'Gio', 'Ven', 'Sab'), + 'weekdays_long' => array ('Domenica', 'Lunedì', 'Martedì', 'Mercoledì', 'Giovedì', 'Venerdì', 'Sabato'), + 'months_short' => array ('Gen', 'Feb', 'Mar', 'Apr', 'Mag', 'Giu', 'Lug', 'Ago', 'Set', 'Ott', 'Nov', 'Dic'), + 'months_long' => array ('Gennaio', 'Febbraio', 'Marzo', 'Aprile', 'Maggio', 'Giugno', 'Luglio', 'Agosto', 'Settembre', 'Ottobre', 'Novembre', 'Dicembre') + ), + 'sk' => array ( + 'weekdays_short'=> array ('Ned', 'Pon', 'Uto', 'Str', 'Štv', 'Pia', 'Sob'), + 'weekdays_long' => array ('Nedeža', 'Pondelok', 'Utorok', 'Streda', 'Štvrtok', 'Piatok', 'Sobota'), + 'months_short' => array ('Jan', 'Feb', 'Mar', 'Apr', 'Máj', 'Jún', 'Júl', 'Aug', 'Sep', 'Okt', 'Nov', 'Dec'), + 'months_long' => array ('Január', 'Február', 'Marec', 'Apríl', 'Máj', 'Jún', 'Júl', 'August', 'September', 'Október', 'November', 'December') + ), + 'cs' => array ( + 'weekdays_short'=> array ('Ne', 'Po', 'Út', 'St', 'Čt', 'Pá', 'So'), + 'weekdays_long' => array ('Neděle', 'Pondělí', 'Úterý', 'Středa', 'Čtvrtek', 'Pátek', 'Sobota'), + 'months_short' => array ('Led', 'Úno', 'Bře', 'Dub', 'Kvě', 'Čen', 'Čec', 'Srp', 'Zář', 'Říj', 'Lis', 'Pro'), + 'months_long' => array ('Leden', 'Únor', 'Březen', 'Duben', 'Květen', 'Červen', 'Červenec', 'Srpen', 'Září', 'Říjen', 'Listopad', 'Prosinec') + ), + 'hy' => array ( + 'weekdays_short'=> array ('Կրկ', 'Երկ', 'Երք', 'Չրք', 'Հնգ', 'Ուր', 'Շբթ'), + 'weekdays_long' => array ('Կիրակի', 'Երկուշաբթի', 'Երեքշաբթի', 'Չորեքշաբթի', 'Հինգշաբթի', 'Ուրբաթ', 'Շաբաթ'), + 'months_short' => array ('Հնվ', 'Փտր', 'Մրտ', 'Ապր', 'Մյս', 'Հնս', 'Հլս', 'Օգս', 'Սպտ', 'Հկտ', 'Նյմ', 'Դկտ'), + 'months_long' => array ('Հունվար', 'Փետրվար', 'Մարտ', 'Ապրիլ', 'Մայիս', 'Հունիս', 'Հուլիս', 'Օգոստոս', 'Սեպտեմբեր', 'Հոկտեմբեր', 'Նոյեմբեր', 'Դեկտեմբեր') + ), + 'nl' => array ( + 'weekdays_short'=> array ('Zo', 'Ma', 'Di', 'Wo', 'Do', 'Vr', 'Za'), + 'weekdays_long' => array ('Zondag', 'Maandag', 'Dinsdag', 'Woensdag', 'Donderdag', 'Vrijdag', 'Zaterdag'), + 'months_short' => array ('Jan', 'Feb', 'Mar', 'Apr', 'Mei', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dec'), + 'months_long' => array ('Januari', 'Februari', 'Maart', 'April', 'Mei', 'Juni', 'Juli', 'Augustus', 'September', 'Oktober', 'November', 'December') + ), + 'et' => array ( + 'weekdays_short'=> array ('P', 'E', 'T', 'K', 'N', 'R', 'L'), + 'weekdays_long' => array ('Pühapäev', 'Esmaspäev', 'Teisipäev', 'Kolmapäev', 'Neljapäev', 'Reede', 'Laupäev'), + 'months_short' => array ('Jaan', 'Veebr', 'Märts', 'Aprill', 'Mai', 'Juuni', 'Juuli', 'Aug', 'Sept', 'Okt', 'Nov', 'Dets'), + 'months_long' => array ('Jaanuar', 'Veebruar', 'Märts', 'Aprill', 'Mai', 'Juuni', 'Juuli', 'August', 'September', 'Oktoober', 'November', 'Detsember') + ), + 'tr' => array ( + 'weekdays_short'=> array ('Paz', 'Pzt', 'Sal', 'Çar', 'Per', 'Cum', 'Cts'), + 'weekdays_long' => array ('Pazar', 'Pazartesi', 'Salı', 'Çarşamba', 'Perşembe', 'Cuma', 'Cumartesi'), + 'months_short' => array ('Ock', 'Şbt', 'Mrt', 'Nsn', 'Mys', 'Hzrn', 'Tmmz', 'Ağst', 'Eyl', 'Ekm', 'Ksm', 'Arlk'), + 'months_long' => array ('Ocak', 'Şubat', 'Mart', 'Nisan', 'Mayıs', 'Haziran', 'Temmuz', 'Ağustos', 'Eylül', 'Ekim', 'Kasım', 'Aralık') + ), + 'no' => array ( + 'weekdays_short'=> array ('Søn', 'Man', 'Tir', 'Ons', 'Tor', 'Fre', 'Lør'), + 'weekdays_long' => array ('Søndag', 'Mandag', 'Tirsdag', 'Onsdag', 'Torsdag', 'Fredag', 'Lørdag'), + 'months_short' => array ('Jan', 'Feb', 'Mar', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Des'), + 'months_long' => array ('Januar', 'Februar', 'Mars', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Desember') + ), + 'eo' => array ( + 'weekdays_short'=> array ('Dim', 'Lun', 'Mar', 'Mer', 'Ĵaŭ', 'Ven', 'Sab'), + 'weekdays_long' => array ('Dimanĉo', 'Lundo', 'Mardo', 'Merkredo', 'Ĵaŭdo', 'Vendredo', 'Sabato'), + 'months_short' => array ('Jan', 'Feb', 'Mar', 'Apr', 'Maj', 'Jun', 'Jul', 'Aŭg', 'Sep', 'Okt', 'Nov', 'Dec'), + 'months_long' => array ('Januaro', 'Februaro', 'Marto', 'Aprilo', 'Majo', 'Junio', 'Julio', 'Aŭgusto', 'Septembro', 'Oktobro', 'Novembro', 'Decembro') + ), + 'ua' => array ( + 'weekdays_short'=> array ('Ндл', 'Пнд', 'Втр', 'Срд', 'Чтв', 'Птн', 'Сбт'), + 'weekdays_long' => array ('Неділя', 'Понеділок', 'Вівторок', 'Середа', 'Четвер', 'П\'ятниця', 'Субота'), + 'months_short' => array ('Січ', 'Лют', 'Бер', 'Кві', 'Тра', 'Чер', 'Лип', 'Сер', 'Вер', 'Жов', 'Лис', 'Гру'), + 'months_long' => array ('Січень', 'Лютий', 'Березень', 'Квітень', 'Травень', 'Червень', 'Липень', 'Серпень', 'Вересень', 'Жовтень', 'Листопад', 'Грудень') + ), + 'ro' => array ( + 'weekdays_short'=> array ('Dum', 'Lun', 'Mar', 'Mie', 'Joi', 'Vin', 'Sam'), + 'weekdays_long' => array ('Duminica', 'Luni', 'Marti', 'Miercuri', 'Joi', 'Vineri', 'Sambata'), + 'months_short' => array ('Ian', 'Feb', 'Mar', 'Apr', 'Mai', 'Iun', 'Iul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'months_long' => array ('Ianuarie', 'Februarie', 'Martie', 'Aprilie', 'Mai', 'Iunie', 'Iulie', 'August', 'Septembrie', 'Octombrie', 'Noiembrie', 'Decembrie') + ), + 'he' => array ( + 'weekdays_short'=> array ('ראשון', 'שני', 'שלישי', 'רביעי', 'חמישי', 'שישי', 'שבת'), + 'weekdays_long' => array ('יום ראשון', 'יום שני', 'יום שלישי', 'יום רביעי', 'יום חמישי', 'יום שישי', 'שבת'), + 'months_short' => array ('ינואר', 'פברואר', 'מרץ', 'אפריל', 'מאי', 'יוני', 'יולי', 'אוגוסט', 'ספטמבר', 'אוקטובר', 'נובמבר', 'דצמבר'), + 'months_long' => array ('ינואר', 'פברואר', 'מרץ', 'אפריל', 'מאי', 'יוני', 'יולי', 'אוגוסט', 'ספטמבר', 'אוקטובר', 'נובמבר', 'דצמבר') + ), + 'sv' => array ( + 'weekdays_short'=> array ('Sön', 'Mån', 'Tis', 'Ons', 'Tor', 'Fre', 'Lör'), + 'weekdays_long' => array ('Söndag', 'Måndag', 'Tisdag', 'Onsdag', 'Torsdag', 'Fredag', 'Lördag'), + 'months_short' => array ('Jan', 'Feb', 'Mar', 'Apr', 'Maj', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dec'), + 'months_long' => array ('Januari', 'Februari', 'Mars', 'April', 'Maj', 'Juni', 'Juli', 'Augusti', 'September', 'Oktober', 'November', 'December') + ), + 'pt' => array ( + 'weekdays_short'=> array ('Dom', 'Seg', 'Ter', 'Qua', 'Qui', 'Sex', 'Sáb'), + 'weekdays_long' => array ('Domingo', 'Segunda-feira', 'Terça-feira', 'Quarta-feira', 'Quinta-feira', 'Sexta-feira', 'Sábado'), + 'months_short' => array ('Jan', 'Fev', 'Mar', 'Abr', 'Mai', 'Jun', 'Jul', 'Ago', 'Set', 'Out', 'Nov', 'Dez'), + 'months_long' => array ('Janeiro', 'Fevereiro', 'Março', 'Abril', 'Maio', 'Junho', 'Julho', 'Agosto', 'Setembro', 'Outubro', 'Novembro', 'Dezembro') + ), + 'tw' => array ( + 'weekdays_short'=> array ('週日','週一', '週二','週三', '週四','週五', '週六'), + 'weekdays_long' => array ('星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'), + 'months_short' => array ('一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'), + 'months_long' => array ('一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月') + ), + 'pt-br' => array ( + 'weekdays_short'=> array ('Dom', 'Seg', 'Ter', 'Qua', 'Qui', 'Sex', 'Sáb'), + 'weekdays_long' => array ('Domingo', 'Segunda', 'Terça', 'Quarta', 'Quinta', 'Sexta', 'Sábado'), + 'months_short' => array ('Jan', 'Fev', 'Mar', 'Abr', 'Mai', 'Jun', 'Jul', 'Ago', 'Set', 'Out', 'Nov', 'Dez'), + 'months_long' => array ('Janeiro', 'Fevereiro', 'Março', 'Abril', 'Maio', 'Junho', 'Julho', 'Agosto', 'Setembro', 'Outubro', 'Novembro', 'Dezembro') + ), + 'sr' => array ( + 'weekdays_short'=> array ('Нед', 'Пон', 'Уто', 'Сре', 'Чет', 'Пет', 'Суб'), + 'weekdays_long' => array ('Недеља', 'Понедељак', 'Уторак', 'Среда', 'Четвртак', 'Петак', 'Субота'), + 'months_short' => array ('Јан', 'Феб', 'Мар', 'Апр', 'Мај', 'Јун', 'Јул', 'Авг', 'Сеп', 'Окт', 'Нов', 'Дец'), + 'months_long' => array ('Јануар', 'Фебруар', 'Март', 'Април', 'Мај', 'Јун', 'Јул', 'Август', 'Септембар', 'Октобар', 'Новембар', 'Децембар') + ), + 'el' => array ( + 'weekdays_short'=> array ('Δευ', 'Τρί', 'Τετ', 'Πέμ', 'Παρ', 'Σάβ', 'Κυρ'), + 'weekdays_long' => array ('Δευτέρα', 'Τρίτη', 'Τετάρτη', 'Πέμπτη', 'Παρασκευή', 'Σάββατο', 'Κυριακή'), + 'months_short' => array ('Ιαν', 'Φεβ', 'Μάρ', 'Απρ', 'Μάϊ', 'Ioύν', 'Ιούλ', 'Αύγ', 'Σεπ', 'Οκτ', 'Νοέ', 'Δεκ'), + 'months_long' => array ('Ιανουάριος', 'Φεβρουάριος', 'Μάρτιος', 'Απρίλιος', 'Μάϊος', 'Ιούνιος', 'Ioύλιος', 'Αύγουστος', 'Σεπτέμβριος', 'Οκτώβριος', 'Νοέμβριος', 'Δεκέμβριος') + ) + ); +} +?>
\ No newline at end of file diff --git a/libs/HTML/QuickForm2/Element/Input.php b/libs/HTML/QuickForm2/Element/Input.php new file mode 100644 index 0000000000..65024a05fd --- /dev/null +++ b/libs/HTML/QuickForm2/Element/Input.php @@ -0,0 +1,114 @@ +<?php +/** + * Base class for <input> elements + * + * PHP version 5 + * + * LICENSE: + * + * Copyright (c) 2006-2010, Alexey Borzov <avb@php.net>, + * Bertrand Mansion <golgote@mamasam.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * The names of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version SVN: $Id: Input.php 300722 2010-06-24 10:15:52Z mansion $ + * @link http://pear.php.net/package/HTML_QuickForm2 + */ + +/** + * Base class for simple HTML_QuickForm2 elements (not Containers) + */ +require_once 'HTML/QuickForm2/Element.php'; + +/** + * Base class for <input> elements + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @version Release: @package_version@ + */ +class HTML_QuickForm2_Element_Input extends HTML_QuickForm2_Element +{ + /** + * 'type' attribute should not be changeable + * @var array + */ + protected $watchedAttributes = array('id', 'name', 'type'); + + protected function onAttributeChange($name, $value = null) + { + if ('type' == $name) { + throw new HTML_QuickForm2_InvalidArgumentException( + "Attribute 'type' is read-only" + ); + } + parent::onAttributeChange($name, $value); + } + + public function getType() + { + return $this->attributes['type']; + } + + public function setValue($value) + { + $this->setAttribute('value', $value); + return $this; + } + + public function getValue() + { + return $this->getAttribute('disabled')? null: $this->applyFilters($this->getAttribute('value')); + } + + public function __toString() + { + if ($this->frozen) { + return $this->getFrozenHtml(); + } else { + return '<input' . $this->getAttributes(true) . ' />'; + } + } + + /** + * Returns the field's value without HTML tags + * @return string + */ + protected function getFrozenHtml() + { + $value = $this->getAttribute('value'); + return (('' != $value)? htmlspecialchars($value, ENT_QUOTES, self::getOption('charset')): ' ') . + $this->getPersistentContent(); + } +} +?>
\ No newline at end of file diff --git a/libs/HTML/QuickForm2/Element/InputButton.php b/libs/HTML/QuickForm2/Element/InputButton.php new file mode 100644 index 0000000000..b3a2ef7cf9 --- /dev/null +++ b/libs/HTML/QuickForm2/Element/InputButton.php @@ -0,0 +1,99 @@ +<?php +/** + * Class for <input type="button" /> elements + * + * PHP version 5 + * + * LICENSE: + * + * Copyright (c) 2006-2010, Alexey Borzov <avb@php.net>, + * Bertrand Mansion <golgote@mamasam.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * The names of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version SVN: $Id: InputButton.php 294057 2010-01-26 21:10:28Z avb $ + * @link http://pear.php.net/package/HTML_QuickForm2 + */ + +/** + * Base class for <input> elements + */ +require_once 'HTML/QuickForm2/Element/Input.php'; + +/** + * Class for <input type="button" /> elements + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @version Release: @package_version@ + */ +class HTML_QuickForm2_Element_InputButton extends HTML_QuickForm2_Element_Input +{ + protected $attributes = array('type' => 'button'); + + /** + * Buttons can not be frozen + * + * @param bool Whether element should be frozen or editable. This + * parameter is ignored in case of buttons + * @return bool Always returns false + */ + public function toggleFrozen($freeze = null) + { + return false; + } + + /** + * Button elements cannot have any submit values + * + * @param mixed Element's value, this parameter is ignored + * @return HTML_QuickForm2_Element_InputButton + */ + public function setValue($value) + { + return $this; + } + + /** + * Button elements cannot have any submit values + * + * This method always returns null + * + * return string|null + */ + public function getValue() + { + return null; + } +} +?> diff --git a/libs/HTML/QuickForm2/Element/InputCheckable.php b/libs/HTML/QuickForm2/Element/InputCheckable.php new file mode 100644 index 0000000000..5d9b30dff2 --- /dev/null +++ b/libs/HTML/QuickForm2/Element/InputCheckable.php @@ -0,0 +1,172 @@ +<?php +/** + * Base class for checkboxes and radios + * + * PHP version 5 + * + * LICENSE: + * + * Copyright (c) 2006-2010, Alexey Borzov <avb@php.net>, + * Bertrand Mansion <golgote@mamasam.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * The names of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version SVN: $Id: InputCheckable.php 300722 2010-06-24 10:15:52Z mansion $ + * @link http://pear.php.net/package/HTML_QuickForm2 + */ + +/** + * Base class for <input> elements + */ +require_once 'HTML/QuickForm2/Element/Input.php'; + +/** + * Base class for <input> elements having 'checked' attribute (checkboxes and radios) + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @version Release: @package_version@ + */ +class HTML_QuickForm2_Element_InputCheckable extends HTML_QuickForm2_Element_Input +{ + protected $persistent = true; + + /** + * HTML to represent the element in "frozen" state + * + * Array index "checked" contains HTML for element's "checked" state, + * "unchecked" for not checked + * @var array + */ + protected $frozenHtml = array( + 'checked' => 'On', + 'unchecked' => 'Off' + ); + + /** + * Contains options and data used for the element creation + * - content: Label "glued" to a checkbox or radio + * @var array + */ + protected $data = array('content' => ''); + + public function __construct($name = null, $attributes = null, $data = null) + { + parent::__construct($name, $attributes, $data); + // "checked" attribute should be updated on changes to "value" attribute + // see bug #15708 + $this->watchedAttributes[] = 'value'; + } + + protected function onAttributeChange($name, $value = null) + { + if ('value' != $name) { + return parent::onAttributeChange($name, $value); + } + if (null === $value) { + unset($this->attributes['value'], $this->attributes['checked']); + } else { + $this->attributes['value'] = $value; + $this->updateValue(); + } + } + + + /** + * Sets the label to be rendered glued to the element + * + * This label is returned by {@link __toString()} method with the element's + * HTML. It is automatically wrapped into the <label> tag. + * + * @param string + * @return HTML_QuickForm2_Element_InputCheckable + */ + public function setContent($content) + { + $this->data['content'] = $content; + return $this; + } + + /** + * Returns the label that will be "glued" to element's HTML + * + * @return string + */ + public function getContent() + { + return $this->data['content']; + } + + + public function setValue($value) + { + if ((string)$value == $this->getAttribute('value')) { + return $this->setAttribute('checked'); + } else { + return $this->removeAttribute('checked'); + } + } + + public function getValue() + { + if (!empty($this->attributes['checked']) && empty($this->attributes['disabled'])) { + return $this->applyFilters($this->getAttribute('value')); + } else { + return null; + } + } + + public function __toString() + { + if (0 == strlen($this->data['content'])) { + $label = ''; + } elseif ($this->frozen) { + $label = $this->data['content']; + } else { + $label = '<label for="' . htmlspecialchars( + $this->getId(), ENT_QUOTES, self::getOption('charset') + ) . '">' . $this->data['content'] . '</label>'; + } + return parent::__toString() . $label; + } + + public function getFrozenHtml() + { + if ($this->getAttribute('checked')) { + return $this->frozenHtml['checked'] . $this->getPersistentContent(); + } else { + return $this->frozenHtml['unchecked']; + } + } +} +?> diff --git a/libs/HTML/QuickForm2/Element/InputCheckbox.php b/libs/HTML/QuickForm2/Element/InputCheckbox.php new file mode 100644 index 0000000000..7e2ab8e065 --- /dev/null +++ b/libs/HTML/QuickForm2/Element/InputCheckbox.php @@ -0,0 +1,99 @@ +<?php +/** + * Class for <input type="checkbox" /> elements + * + * PHP version 5 + * + * LICENSE: + * + * Copyright (c) 2006-2010, Alexey Borzov <avb@php.net>, + * Bertrand Mansion <golgote@mamasam.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * The names of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version SVN: $Id: InputCheckbox.php 294057 2010-01-26 21:10:28Z avb $ + * @link http://pear.php.net/package/HTML_QuickForm2 + */ + +/** + * Base class for checkboxes and radios + */ +require_once 'HTML/QuickForm2/Element/InputCheckable.php'; + +/** + * Class for <input type="checkbox" /> elements + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @version Release: @package_version@ + */ +class HTML_QuickForm2_Element_InputCheckbox extends HTML_QuickForm2_Element_InputCheckable +{ + protected $attributes = array('type' => 'checkbox'); + + protected $frozenHtml = array( + 'checked' => '<tt>[x]</tt>', + 'unchecked' => '<tt>[ ]</tt>' + ); + + public function __construct($name = null, $attributes = null, array $data = array()) + { + parent::__construct($name, $attributes, $data); + if (!$this->getAttribute('value')) { + $this->setAttribute('value', 1); + } + } + + protected function updateValue() + { + $name = $this->getName(); + if ('[]' == substr($name, -2)) { + $name = substr($name, 0, -2); + } + foreach ($this->getDataSources() as $ds) { + if (null !== ($value = $ds->getValue($name)) + || $ds instanceof HTML_QuickForm2_DataSource_Submit + ) { + if (!is_array($value)) { + $this->setValue($value); + } elseif (in_array($this->getAttribute('value'), array_map('strval', $value), true)) { + $this->setAttribute('checked'); + } else { + $this->removeAttribute('checked'); + } + return; + } + } + } +} +?> diff --git a/libs/HTML/QuickForm2/Element/InputFile.php b/libs/HTML/QuickForm2/Element/InputFile.php new file mode 100644 index 0000000000..8fdf99aa55 --- /dev/null +++ b/libs/HTML/QuickForm2/Element/InputFile.php @@ -0,0 +1,268 @@ +<?php +/** + * Class for <input type="file" /> elements + * + * PHP version 5 + * + * LICENSE: + * + * Copyright (c) 2006-2010, Alexey Borzov <avb@php.net>, + * Bertrand Mansion <golgote@mamasam.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * The names of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version SVN: $Id: InputFile.php 300722 2010-06-24 10:15:52Z mansion $ + * @link http://pear.php.net/package/HTML_QuickForm2 + */ + +/** + * Base class for <input> elements + */ +require_once 'HTML/QuickForm2/Element/Input.php'; + +/** + * Class for <input type="file" /> elements + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @version Release: @package_version@ + */ +class HTML_QuickForm2_Element_InputFile extends HTML_QuickForm2_Element_Input +{ + /** + * Default language for error messages + */ + const DEFAULT_LANGUAGE = 'en'; + + /** + * Localized error messages for PHP's file upload errors + * @var array + */ + protected $errorMessages = array( + 'en' => array( + UPLOAD_ERR_INI_SIZE => 'The uploaded file exceeds size permitted by PHP configuration (%d bytes)', + UPLOAD_ERR_FORM_SIZE => 'The uploaded file exceeds the MAX_FILE_SIZE directive in HTML form (%d bytes)', + UPLOAD_ERR_PARTIAL => 'The file was only partially uploaded', + UPLOAD_ERR_NO_TMP_DIR => 'Server error: temporary directory is missing', + UPLOAD_ERR_CANT_WRITE => 'Server error: failed to write the file to disk', + UPLOAD_ERR_EXTENSION => 'File upload was stopped by extension' + ), + 'fr' => array( + UPLOAD_ERR_INI_SIZE => 'Le fichier envoyé excède la taille autorisée par la configuration de PHP (%d octets)', + UPLOAD_ERR_FORM_SIZE => 'Le fichier envoyé excède la taille de MAX_FILE_SIZE spécifiée dans le formulaire HTML (%d octets)', + UPLOAD_ERR_PARTIAL => 'Le fichier n\'a été que partiellement téléchargé', + UPLOAD_ERR_NO_TMP_DIR => 'Erreur serveur: le répertoire temporaire est manquant', + UPLOAD_ERR_CANT_WRITE => 'Erreur serveur: échec de l\'écriture du fichier sur le disque', + UPLOAD_ERR_EXTENSION => 'L\'envoi de fichier est arrêté par l\'extension' + ), + 'ru' => array( + UPLOAD_ERR_INI_SIZE => 'Размер загруженного файла превосходит максимально разрешённый настройками PHP (%d байт)', + UPLOAD_ERR_FORM_SIZE => 'Размер загруженного файла превосходит директиву MAX_FILE_SIZE, указанную в форме (%d байт)', + UPLOAD_ERR_PARTIAL => 'Файл был загружен не полностью', + UPLOAD_ERR_NO_TMP_DIR => 'Ошибка на сервере: отсутствует каталог для временных файлов', + UPLOAD_ERR_CANT_WRITE => 'Ошибка на сервере: не удалось записать файл на диск', + UPLOAD_ERR_EXTENSION => 'Загрузка файла была остановлена расширением' + ) + ); + + /** + * Language to display error messages in + * @var string + */ + protected $language; + + /** + * Information on uploaded file, from submit data source + * @var array + */ + protected $value = null; + + protected $attributes = array('type' => 'file'); + + + /** + * Class constructor + * + * Possible keys in $data array are: + * - 'language': language to display error messages in, it should either be + * already available in the class or provided in 'errorMessages' + * - 'errorMessages': an array of error messages with the following format + * <pre> + * 'language code 1' => array( + * UPLOAD_ERR_... => 'message', + * ... + * UPLOAD_ERR_... => 'message' + * ), + * ... + * 'language code N' => array( + * ... + * ) + * </pre> + * Note that error messages for UPLOAD_ERR_INI_SIZE and UPLOAD_ERR_FORM_SIZE + * may contain '%d' placeholders that will be automatically replaced by the + * appropriate size limits. Note also that you don't need to provide messages + * for every possible error code in the arrays, you may e.g. override just + * one error message for a particular language. + * + * @param string Element name + * @param mixed Attributes (either a string or an array) + * @param array Data used to set up error messages for PHP's file + * upload errors. + */ + public function __construct($name = null, $attributes = null, array $data = array()) + { + if (isset($data['errorMessages'])) { + // neither array_merge() nor array_merge_recursive will do + foreach ($data['errorMessages'] as $lang => $ary) { + foreach ($ary as $code => $message) { + $this->errorMessages[$lang][$code] = $message; + } + } + unset($data['errorMessages']); + } + if (!isset($data['language'])) { + $this->language = self::DEFAULT_LANGUAGE; + } else { + $this->language = isset($this->errorMessages[$data['language']])? + $data['language']: self::DEFAULT_LANGUAGE; + unset($data['language']); + } + parent::__construct($name, $attributes, $data); + } + + + /** + * File upload elements cannot be frozen + * + * To properly "freeze" a file upload element one has to store the uploaded + * file somewhere and store the file info in session. This is way outside + * the scope of this class. + * + * @param bool Whether element should be frozen or editable. This + * parameter is ignored in case of file uploads + * @return bool Always returns false + */ + public function toggleFrozen($freeze = null) + { + return false; + } + + /** + * Returns the information on uploaded file + * + * @return array|null + */ + public function getValue() + { + return $this->value; + } + + /** + * File upload's value cannot be set here + * + * @param mixed Value for file element, this parameter is ignored + * @return HTML_QuickForm2_Element_InputFile + */ + public function setValue($value) + { + return $this; + } + + protected function updateValue() + { + foreach ($this->getDataSources() as $ds) { + if ($ds instanceof HTML_QuickForm2_DataSource_Submit) { + $value = $ds->getUpload($this->getName()); + if (null !== $value) { + $this->value = $value; + return; + } + } + } + $this->value = null; + } + + /** + * Performs the server-side validation + * + * Before the Rules added to the element kick in, the element checks the + * error code added to the $_FILES array by PHP. If the code isn't + * UPLOAD_ERR_OK or UPLOAD_ERR_NO_FILE then a built-in error message will be + * displayed and no further validation will take place. + * + * @return boolean Whether the element is valid + */ + protected function validate() + { + if (strlen($this->error)) { + return false; + } + if (isset($this->value['error']) && + !in_array($this->value['error'], array(UPLOAD_ERR_OK, UPLOAD_ERR_NO_FILE))) + { + if (isset($this->errorMessages[$this->language][$this->value['error']])) { + $errorMessage = $this->errorMessages[$this->language][$this->value['error']]; + } else { + $errorMessage = $this->errorMessages[self::DEFAULT_LANGUAGE][$this->value['error']]; + } + if (UPLOAD_ERR_INI_SIZE == $this->value['error']) { + $iniSize = ini_get('upload_max_filesize'); + $size = intval($iniSize); + switch (strtoupper(substr($iniSize, -1))) { + case 'G': $size *= 1024; + case 'M': $size *= 1024; + case 'K': $size *= 1024; + } + + } elseif (UPLOAD_ERR_FORM_SIZE == $this->value['error']) { + foreach ($this->getDataSources() as $ds) { + if ($ds instanceof HTML_QuickForm2_DataSource_Submit) { + $size = intval($ds->getValue('MAX_FILE_SIZE')); + break; + } + } + } + $this->error = isset($size)? sprintf($errorMessage, $size): $errorMessage; + return false; + } + return parent::validate(); + } + + public function addFilter($callback, array $options = null, $recursive = true) + { + throw new HTML_QuickForm2_Exception( + 'InputFile elements do not support filters' + ); + } +} +?> diff --git a/libs/HTML/QuickForm2/Element/InputHidden.php b/libs/HTML/QuickForm2/Element/InputHidden.php new file mode 100644 index 0000000000..578af01fa3 --- /dev/null +++ b/libs/HTML/QuickForm2/Element/InputHidden.php @@ -0,0 +1,82 @@ +<?php +/** + * Class for <input type="hidden" /> elements + * + * PHP version 5 + * + * LICENSE: + * + * Copyright (c) 2006-2010, Alexey Borzov <avb@php.net>, + * Bertrand Mansion <golgote@mamasam.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * The names of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version SVN: $Id: InputHidden.php 294057 2010-01-26 21:10:28Z avb $ + * @link http://pear.php.net/package/HTML_QuickForm2 + */ + +/** + * Base class for <input> elements + */ +require_once 'HTML/QuickForm2/Element/Input.php'; + +/** + * Class for <input type="hidden" /> elements + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @version Release: @package_version@ + */ +class HTML_QuickForm2_Element_InputHidden extends HTML_QuickForm2_Element_Input +{ + protected $attributes = array('type' => 'hidden'); + + /** + * Hidden elements can not be frozen + * + * @param bool Whether element should be frozen or editable. This + * parameter is ignored in case of hidden elements + * @return bool Always returns false + */ + public function toggleFrozen($freeze = null) + { + return false; + } + + public function render(HTML_QuickForm2_Renderer $renderer) + { + $renderer->renderHidden($this); + return $renderer; + } +} +?> diff --git a/libs/HTML/QuickForm2/Element/InputImage.php b/libs/HTML/QuickForm2/Element/InputImage.php new file mode 100644 index 0000000000..369bd49ee4 --- /dev/null +++ b/libs/HTML/QuickForm2/Element/InputImage.php @@ -0,0 +1,162 @@ +<?php +/** + * Class for <input type="image" /> elements + * + * PHP version 5 + * + * LICENSE: + * + * Copyright (c) 2006-2010, Alexey Borzov <avb@php.net>, + * Bertrand Mansion <golgote@mamasam.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * The names of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version SVN: $Id: InputImage.php 300722 2010-06-24 10:15:52Z mansion $ + * @link http://pear.php.net/package/HTML_QuickForm2 + */ + +/** + * Base class for <input> elements + */ +require_once 'HTML/QuickForm2/Element/Input.php'; + +/** + * Class for <input type="image" /> elements + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @version Release: @package_version@ + */ +class HTML_QuickForm2_Element_InputImage extends HTML_QuickForm2_Element_Input +{ + protected $attributes = array('type' => 'image'); + + /** + * Coordinates of user click within the image, array contains keys 'x' and 'y' + * @var array + */ + protected $coordinates = null; + + /** + * Image buttons can not be frozen + * + * @param bool Whether element should be frozen or editable. This + * parameter is ignored in case of image elements + * @return bool Always returns false + */ + public function toggleFrozen($freeze = null) + { + return false; + } + + /** + * Image button's value cannot be set via this method + * + * @param mixed Element's value, this parameter is ignored + * @return HTML_QuickForm2_Element_InputImage + */ + public function setValue($value) + { + return $this; + } + + /** + * Returns the element's value + * + * The value is only returned if the form was actually submitted and this + * image button was clicked. Returns null in all other cases. + * + * @return array|null An array with keys 'x' and 'y' containing the + * coordinates of user click if the image was clicked, + * null otherwise + */ + public function getValue() + { + return $this->getAttribute('disabled')? null: $this->applyFilters($this->coordinates); + } + + /** + * Returns the HTML representation of the element + * + * The method changes the element's name to foo[bar][] if it was foo[bar] + * originally. If it is not done, then one of the click coordinates will be + * lost, see {@link http://bugs.php.net/bug.php?id=745} + * + * @return string + */ + public function __toString() + { + if (false === strpos($this->attributes['name'], '[') || + '[]' == substr($this->attributes['name'], -2)) + { + return parent::__toString(); + } else { + $this->attributes['name'] .= '[]'; + $html = parent::__toString(); + $this->attributes['name'] = substr($this->attributes['name'], 0, -2); + return $html; + } + } + + protected function updateValue() + { + foreach ($this->getDataSources() as $ds) { + if ($ds instanceof HTML_QuickForm2_DataSource_Submit) { + $name = $this->getName(); + if (false === strpos($name, '[') && + null !== ($value = $ds->getValue($name . '_x'))) + { + $this->coordinates = array( + 'x' => $value, + 'y' => $ds->getValue($name . '_y') + ); + return; + + } elseif (false !== strpos($name, '[')) { + if ('[]' == substr($name, -2)) { + $name = substr($name, 0, -2); + } + if (null !== ($value = $ds->getValue($name))) { + $this->coordinates = array( + 'x' => $value[0], + 'y' => $value[1] + ); + return; + } + } + } + } + $this->coordinates = null; + } +} +?> diff --git a/libs/HTML/QuickForm2/Element/InputPassword.php b/libs/HTML/QuickForm2/Element/InputPassword.php new file mode 100644 index 0000000000..12a975f240 --- /dev/null +++ b/libs/HTML/QuickForm2/Element/InputPassword.php @@ -0,0 +1,71 @@ +<?php +/** + * Class for <input type="password" /> elements + * + * PHP version 5 + * + * LICENSE: + * + * Copyright (c) 2006-2010, Alexey Borzov <avb@php.net>, + * Bertrand Mansion <golgote@mamasam.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * The names of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version SVN: $Id: InputPassword.php 294057 2010-01-26 21:10:28Z avb $ + * @link http://pear.php.net/package/HTML_QuickForm2 + */ + +/** + * Base class for <input> elements + */ +require_once 'HTML/QuickForm2/Element/Input.php'; + +/** + * Class for <input type="password" /> elements + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @version Release: @package_version@ + */ +class HTML_QuickForm2_Element_InputPassword extends HTML_QuickForm2_Element_Input +{ + protected $attributes = array('type' => 'password'); + + protected function getFrozenHtml() + { + $value = $this->getValue(); + return (('' != $value)? '********': ' ') . + $this->getPersistentContent(); + } +} +?>
\ No newline at end of file diff --git a/libs/HTML/QuickForm2/Element/InputRadio.php b/libs/HTML/QuickForm2/Element/InputRadio.php new file mode 100644 index 0000000000..a005c71513 --- /dev/null +++ b/libs/HTML/QuickForm2/Element/InputRadio.php @@ -0,0 +1,69 @@ +<?php +/** + * Class for <input type="radio" /> elements + * + * PHP version 5 + * + * LICENSE: + * + * Copyright (c) 2006-2010, Alexey Borzov <avb@php.net>, + * Bertrand Mansion <golgote@mamasam.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * The names of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version SVN: $Id: InputRadio.php 294057 2010-01-26 21:10:28Z avb $ + * @link http://pear.php.net/package/HTML_QuickForm2 + */ + +/** + * Base class for checkboxes and radios + */ +require_once 'HTML/QuickForm2/Element/InputCheckable.php'; + +/** + * Class for <input type="radio" /> elements + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @version Release: @package_version@ + */ +class HTML_QuickForm2_Element_InputRadio extends HTML_QuickForm2_Element_InputCheckable +{ + protected $attributes = array('type' => 'radio'); + + protected $frozenHtml = array( + 'checked' => '<tt>(x)</tt>', + 'unchecked' => '<tt>( )</tt>' + ); +} +?> diff --git a/libs/HTML/QuickForm2/Element/InputReset.php b/libs/HTML/QuickForm2/Element/InputReset.php new file mode 100644 index 0000000000..b6dd914582 --- /dev/null +++ b/libs/HTML/QuickForm2/Element/InputReset.php @@ -0,0 +1,99 @@ +<?php +/** + * Class for <input type="reset" /> elements + * + * PHP version 5 + * + * LICENSE: + * + * Copyright (c) 2006-2010, Alexey Borzov <avb@php.net>, + * Bertrand Mansion <golgote@mamasam.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * The names of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version SVN: $Id: InputReset.php 294057 2010-01-26 21:10:28Z avb $ + * @link http://pear.php.net/package/HTML_QuickForm2 + */ + +/** + * Base class for <input> elements + */ +require_once 'HTML/QuickForm2/Element/Input.php'; + +/** + * Class for <input type="reset" /> elements + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @version Release: @package_version@ + */ +class HTML_QuickForm2_Element_InputReset extends HTML_QuickForm2_Element_Input +{ + protected $attributes = array('type' => 'reset'); + + /** + * Reset buttons can not be frozen + * + * @param bool Whether element should be frozen or editable. This + * parameter is ignored in case of reset buttons + * @return bool Always returns false + */ + public function toggleFrozen($freeze = null) + { + return false; + } + + /** + * Reset elements cannot have any submit values + * + * @param mixed Element's value, this parameter is ignored + * @return HTML_QuickForm2_Element_InputReset + */ + public function setValue($value) + { + return $this; + } + + /** + * Reset elements cannot have any submit values + * + * This method always returns null + * + * @return string|null + */ + public function getValue() + { + return null; + } +} +?>
\ No newline at end of file diff --git a/libs/HTML/QuickForm2/Element/InputSubmit.php b/libs/HTML/QuickForm2/Element/InputSubmit.php new file mode 100644 index 0000000000..c538ad0a68 --- /dev/null +++ b/libs/HTML/QuickForm2/Element/InputSubmit.php @@ -0,0 +1,120 @@ +<?php +/** + * Class for <input type="submit" /> elements + * + * PHP version 5 + * + * LICENSE: + * + * Copyright (c) 2006-2010, Alexey Borzov <avb@php.net>, + * Bertrand Mansion <golgote@mamasam.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * The names of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version SVN: $Id: InputSubmit.php 300722 2010-06-24 10:15:52Z mansion $ + * @link http://pear.php.net/package/HTML_QuickForm2 + */ + +/** + * Base class for <input> elements + */ +require_once 'HTML/QuickForm2/Element/Input.php'; + +/** + * Class for <input type="submit" /> elements + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @version Release: @package_version@ + */ +class HTML_QuickForm2_Element_InputSubmit extends HTML_QuickForm2_Element_Input +{ + protected $attributes = array('type' => 'submit'); + + /** + * Element's submit value + * @var string + */ + protected $submitValue = null; + + + /** + * Submit buttons can not be frozen + * + * @param bool Whether element should be frozen or editable. This + * parameter is ignored in case of submit elements + * @return bool Always returns false + */ + public function toggleFrozen($freeze = null) + { + return false; + } + + /** + * Submit's value cannot be set via this method + * + * @param mixed Element's value, this parameter is ignored + * @return HTML_QuickForm2_Element_InputSubmit + */ + public function setValue($value) + { + return $this; + } + + /** + * Returns the element's value + * + * The value is only returned if the form was actually submitted and this + * submit button was clicked. Returns null in all other cases + * + * @return string|null + */ + public function getValue() + { + return $this->getAttribute('disabled')? null: $this->applyFilters($this->submitValue); + } + + protected function updateValue() + { + foreach ($this->getDataSources() as $ds) { + if ($ds instanceof HTML_QuickForm2_DataSource_Submit && + null !== ($value = $ds->getValue($this->getName()))) + { + $this->submitValue = $value; + return; + } + } + $this->submitValue = null; + } +} +?> diff --git a/libs/HTML/QuickForm2/Element/InputText.php b/libs/HTML/QuickForm2/Element/InputText.php new file mode 100644 index 0000000000..5b9e62ebf9 --- /dev/null +++ b/libs/HTML/QuickForm2/Element/InputText.php @@ -0,0 +1,64 @@ +<?php +/** + * Class for <input type="text" /> elements + * + * PHP version 5 + * + * LICENSE: + * + * Copyright (c) 2006-2010, Alexey Borzov <avb@php.net>, + * Bertrand Mansion <golgote@mamasam.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * The names of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version SVN: $Id: InputText.php 294057 2010-01-26 21:10:28Z avb $ + * @link http://pear.php.net/package/HTML_QuickForm2 + */ + +/** + * Base class for <input> elements + */ +require_once 'HTML/QuickForm2/Element/Input.php'; + +/** + * Class for <input type="text" /> elements + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @version Release: @package_version@ + */ +class HTML_QuickForm2_Element_InputText extends HTML_QuickForm2_Element_Input +{ + protected $attributes = array('type' => 'text'); +} +?> diff --git a/libs/HTML/QuickForm2/Element/Select.php b/libs/HTML/QuickForm2/Element/Select.php new file mode 100644 index 0000000000..ec7d596194 --- /dev/null +++ b/libs/HTML/QuickForm2/Element/Select.php @@ -0,0 +1,575 @@ +<?php +/** + * Classes for <select> elements + * + * PHP version 5 + * + * LICENSE: + * + * Copyright (c) 2006-2010, Alexey Borzov <avb@php.net>, + * Bertrand Mansion <golgote@mamasam.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * The names of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version SVN: $Id: Select.php 300722 2010-06-24 10:15:52Z mansion $ + * @link http://pear.php.net/package/HTML_QuickForm2 + */ + +/** + * Base class for simple HTML_QuickForm2 elements + */ +require_once 'HTML/QuickForm2/Element.php'; + + +/** + * Collection of <option>s and <optgroup>s + * + * This class handles the output of <option> tags. The class is not intended to + * be used directly. + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @version Release: @package_version@ + */ +class HTML_QuickForm2_Element_Select_OptionContainer extends HTML_Common2 + implements IteratorAggregate, Countable +{ + /** + * List of options and optgroups in this container + * + * Options are stored as arrays (for performance reasons), optgroups as + * instances of Optgroup class. + * + * @var array + */ + protected $options = array(); + + /** + * Reference to parent <select>'s values + * @var array + */ + protected $values; + + /** + * Reference to parent <select>'s possible values + * @var array + */ + protected $possibleValues; + + + /** + * Class constructor + * + * @param array Reference to values of parent <select> element + * @param array Reference to possible values of parent <select> element + */ + public function __construct(&$values, &$possibleValues) + { + $this->values =& $values; + $this->possibleValues =& $possibleValues; + } + + /** + * Adds a new option + * + * Please note that if you pass 'selected' attribute in the $attributes + * parameter then this option's value will be added to <select>'s values. + * + * @param string Option text + * @param string 'value' attribute for <option> tag + * @param mixed Additional attributes for <option> tag (either as a + * string or as an associative array) + */ + public function addOption($text, $value, $attributes = null) + { + if (null === $attributes) { + $attributes = array('value' => (string)$value); + } else { + $attributes = self::prepareAttributes($attributes); + if (isset($attributes['selected'])) { + // the 'selected' attribute will be set in __toString() + unset($attributes['selected']); + if (!in_array($value, $this->values)) { + $this->values[] = $value; + } + } + $attributes['value'] = (string)$value; + } + if (!isset($attributes['disabled'])) { + $this->possibleValues[(string)$value] = true; + } + $this->options[] = array('text' => $text, 'attr' => $attributes); + } + + /** + * Adds a new optgroup + * + * @param string 'label' attribute for optgroup tag + * @param mixed Additional attributes for <optgroup> tag (either as a + * string or as an associative array) + * @return HTML_QuickForm2_Element_Select_Optgroup + */ + public function addOptgroup($label, $attributes = null) + { + $optgroup = new HTML_QuickForm2_Element_Select_Optgroup( + $this->values, $this->possibleValues, + $label, $attributes + ); + $this->options[] = $optgroup; + return $optgroup; + } + + /** + * Returns an array of contained options + * + * @return array + */ + public function getOptions() + { + return $this->options; + } + + public function __toString() + { + $indentLvl = $this->getIndentLevel(); + $indent = $this->getIndent() . self::getOption('indent'); + $linebreak = self::getOption('linebreak'); + $html = ''; + $strValues = array_map('strval', $this->values); + foreach ($this->options as $option) { + if (is_array($option)) { + if (in_array($option['attr']['value'], $strValues, true)) { + $option['attr']['selected'] = 'selected'; + } + $html .= $indent . '<option' . + self::getAttributesString($option['attr']) . + '>' . $option['text'] . '</option>' . $linebreak; + } elseif ($option instanceof HTML_QuickForm2_Element_Select_OptionContainer) { + $option->setIndentLevel($indentLvl + 1); + $html .= $option->__toString(); + } + } + return $html; + } + + /** + * Returns an iterator over contained elements + * + * @return HTML_QuickForm2_Element_Select_OptionIterator + */ + public function getIterator() + { + return new HTML_QuickForm2_Element_Select_OptionIterator($this->options); + } + + /** + * Returns a recursive iterator over contained elements + * + * @return RecursiveIteratorIterator + */ + public function getRecursiveIterator() + { + return new RecursiveIteratorIterator( + new HTML_QuickForm2_Element_Select_OptionIterator($this->options), + RecursiveIteratorIterator::SELF_FIRST + ); + } + + /** + * Returns the number of options in the container + * + * @return int + */ + public function count() + { + return count($this->options); + } +} + + +/** + * Class representing an <optgroup> tag + * + * Do not instantiate this class yourself, use + * {@link HTML_QuickForm2_Element_Select::addOptgroup()} method + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @version Release: @package_version@ + */ +class HTML_QuickForm2_Element_Select_Optgroup + extends HTML_QuickForm2_Element_Select_OptionContainer +{ + /** + * Class constructor + * + * @param array Reference to values of parent <select> element + * @param array Reference to possible values of parent <select> element + * @param string 'label' attribute for optgroup tag + * @param mixed Additional attributes for <optgroup> tag (either as a + * string or as an associative array) + */ + public function __construct(&$values, &$possibleValues, $label, $attributes = null) + { + parent::__construct($values, $possibleValues); + $this->setAttributes($attributes); + $this->attributes['label'] = (string)$label; + } + + public function __toString() + { + $indent = $this->getIndent(); + $linebreak = self::getOption('linebreak'); + return $indent . '<optgroup' . $this->getAttributes(true) . '>' . + $linebreak . parent::__toString() . $indent . '</optgroup>' . $linebreak; + } +} + +/** + * Implements a recursive iterator for options arrays + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @version Release: @package_version@ + */ +class HTML_QuickForm2_Element_Select_OptionIterator extends RecursiveArrayIterator + implements RecursiveIterator +{ + public function hasChildren() + { + return $this->current() instanceof HTML_QuickForm2_Element_Select_OptionContainer; + } + + public function getChildren() + { + return new HTML_QuickForm2_Element_Select_OptionIterator( + $this->current()->getOptions() + ); + } +} + + +/** + * Class representing a <select> element + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @version Release: @package_version@ + */ +class HTML_QuickForm2_Element_Select extends HTML_QuickForm2_Element +{ + protected $persistent = true; + + /** + * Values for the select element (i.e. values of the selected options) + * @var array + */ + protected $values = array(); + + /** + * Possible values for select elements + * + * A value is considered possible if it is present as a value attribute of + * some option and that option is not disabled. + * @var array + */ + protected $possibleValues = array(); + + + /** + * Object containing options for the <select> element + * @var HTML_QuickForm2_Element_Select_OptionContainer + */ + protected $optionContainer; + + /** + * Enable intrinsic validation by default + * @var array + */ + protected $data = array('intrinsic_validation' => true); + + /** + * Class constructor + * + * Select element can understand the following keys in $data parameter: + * - 'options': data to populate element's options with. Passed to + * {@link loadOptions()} method. + * - 'intrinsic_validation': setting this to false will disable + * that validation, {@link getValue()} will then return all submit + * values, not just those corresponding to options present in the + * element. May be useful in AJAX scenarios. + * + * @param string Element name + * @param mixed Attributes (either a string or an array) + * @param array Additional element data + * @throws HTML_QuickForm2_InvalidArgumentException if junk is given in $options + */ + public function __construct($name = null, $attributes = null, array $data = array()) + { + $options = isset($data['options'])? $data['options']: array(); + unset($data['options']); + parent::__construct($name, $attributes, $data); + $this->loadOptions($options); + } + + public function getType() + { + return 'select'; + } + + public function __toString() + { + if ($this->frozen) { + return $this->getFrozenHtml(); + } else { + if (empty($this->attributes['multiple'])) { + $attrString = $this->getAttributes(true); + } else { + $this->attributes['name'] .= '[]'; + $attrString = $this->getAttributes(true); + $this->attributes['name'] = substr($this->attributes['name'], 0, -2); + } + $indent = $this->getIndent(); + return $indent . '<select' . $attrString . '>' . + self::getOption('linebreak') . + $this->optionContainer->__toString() . + $indent . '</select>'; + } + } + + protected function getFrozenHtml() + { + if (null === ($value = $this->getValue())) { + return ' '; + } + $valueHash = is_array($value)? array_flip($value): array($value => true); + $options = array(); + foreach ($this->optionContainer->getRecursiveIterator() as $child) { + if (is_array($child) && isset($valueHash[$child['attr']['value']]) && + empty($child['attr']['disabled'])) + { + $options[] = $child['text']; + } + } + + $html = implode('<br />', $options); + if ($this->persistent) { + $name = $this->attributes['name'] . + (empty($this->attributes['multiple'])? '': '[]'); + // Only use id attribute if doing single hidden input + $idAttr = (1 == count($valueHash))? array('id' => $this->getId()): array(); + foreach ($valueHash as $key => $item) { + $html .= '<input type="hidden"' . self::getAttributesString(array( + 'name' => $name, + 'value' => $key + ) + $idAttr) . ' />'; + } + } + return $html; + } + + /** + * Returns the value of the <select> element + * + * Please note that the returned value may not necessarily be equal to that + * passed to {@link setValue()}. It passes "intrinsic validation" confirming + * that such value could possibly be submitted by this <select> element. + * Specifically, this method will return null if the elements "disabled" + * attribute is set, it will not return values if there are no options having + * such a "value" attribute or if such options' "disabled" attribute is set. + * It will also only return a scalar value for single selects, mimicking + * the common browsers' behaviour. + * + * @return mixed "value" attribute of selected option in case of single + * select, array of selected options' "value" attributes in + * case of multiple selects, null if no options selected + */ + public function getValue() + { + if (!empty($this->attributes['disabled']) || 0 == count($this->values) + || ($this->data['intrinsic_validation'] + && (0 == count($this->optionContainer) || 0 == count($this->possibleValues))) + ) { + return null; + } + + $values = array(); + foreach ($this->values as $value) { + if (!$this->data['intrinsic_validation'] || !empty($this->possibleValues[$value])) { + $values[] = $value; + } + } + if (0 == count($values)) { + return null; + } elseif (!empty($this->attributes['multiple'])) { + return $this->applyFilters($values); + } elseif (1 == count($values)) { + return $this->applyFilters($values[0]); + } else { + // The <select> is not multiple, but several options are to be + // selected. At least IE and Mozilla select the last selected + // option in this case, we should do the same + foreach ($this->optionContainer->getRecursiveIterator() as $child) { + if (is_array($child) && in_array($child['attr']['value'], $values)) { + $lastValue = $child['attr']['value']; + } + } + return $this->applyFilters($lastValue); + } + } + + public function setValue($value) + { + if (is_array($value)) { + $this->values = array_values($value); + } else { + $this->values = array($value); + } + return $this; + } + + /** + * Loads <option>s (and <optgroup>s) for select element + * + * The method expects a array of options and optgroups: + * <pre> + * array( + * 'option value 1' => 'option text 1', + * ... + * 'option value N' => 'option text N', + * 'optgroup label 1' => array( + * 'option value' => 'option text', + * ... + * ), + * ... + * ) + * </pre> + * If value is a scalar, then array key is treated as "value" attribute of + * <option> and value as this <option>'s text. If value is an array, then + * key is treated as a "label" attribute of <optgroup> and value as an + * array of <option>s for this <optgroup>. + * + * If you need to specify additional attributes for <option> and <optgroup> + * tags, then you need to use {@link addOption()} and {@link addOptgroup()} + * methods instead of this one. + * + * @param array + * @throws HTML_QuickForm2_InvalidArgumentException if junk is given in $options + * @return HTML_QuickForm2_Element_Select + */ + public function loadOptions(array $options) + { + $this->possibleValues = array(); + $this->optionContainer = new HTML_QuickForm2_Element_Select_OptionContainer( + $this->values, $this->possibleValues + ); + $this->loadOptionsFromArray($this->optionContainer, $options); + return $this; + } + + + /** + * Adds options from given array into given container + * + * @param HTML_QuickForm2_Element_Select_OptionContainer options will be + * added to this container + * @param array options array + */ + protected function loadOptionsFromArray( + HTML_QuickForm2_Element_Select_OptionContainer $container, $options + ) + { + foreach ($options as $key => $value) { + if (is_array($value)) { + $optgroup = $container->addOptgroup($key); + $this->loadOptionsFromArray($optgroup, $value); + } else { + $container->addOption($value, $key); + } + } + } + + + /** + * Adds a new option + * + * Please note that if you pass 'selected' attribute in the $attributes + * parameter then this option's value will be added to <select>'s values. + * + * @param string Option text + * @param string 'value' attribute for <option> tag + * @param mixed Additional attributes for <option> tag (either as a + * string or as an associative array) + */ + public function addOption($text, $value, $attributes = null) + { + return $this->optionContainer->addOption($text, $value, $attributes); + } + + /** + * Adds a new optgroup + * + * @param string 'label' attribute for optgroup tag + * @param mixed Additional attributes for <optgroup> tag (either as a + * string or as an associative array) + * @return HTML_QuickForm2_Element_Select_Optgroup + */ + public function addOptgroup($label, $attributes = null) + { + return $this->optionContainer->addOptgroup($label, $attributes); + } + + protected function updateValue() + { + if (!$this->getAttribute('multiple')) { + parent::updateValue(); + } else { + $name = $this->getName(); + foreach ($this->getDataSources() as $ds) { + if (null !== ($value = $ds->getValue($name)) || + $ds instanceof HTML_QuickForm2_DataSource_Submit) + { + $this->setValue(null === $value? array(): $value); + return; + } + } + } + } +} +?> diff --git a/libs/HTML/QuickForm2/Element/Static.php b/libs/HTML/QuickForm2/Element/Static.php new file mode 100644 index 0000000000..bfee75e130 --- /dev/null +++ b/libs/HTML/QuickForm2/Element/Static.php @@ -0,0 +1,153 @@ +<?php +/** + * Class for static elements that only contain text or markup + * + * PHP version 5 + * + * LICENSE: + * + * Copyright (c) 2006-2010, Alexey Borzov <avb@php.net>, + * Bertrand Mansion <golgote@mamasam.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * The names of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version SVN: $Id: Static.php 299206 2010-05-10 10:21:10Z mansion $ + * @link http://pear.php.net/package/HTML_QuickForm2 + */ + +/** + * Base class for simple HTML_QuickForm2 elements (not Containers) + */ +require_once 'HTML/QuickForm2/Element.php'; + +/** + * Class for static elements that only contain text or markup + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @version Release: @package_version@ + */ +class HTML_QuickForm2_Element_Static extends HTML_QuickForm2_Element +{ + + /** + * Contains options and data used for the element creation + * - content: Content of the static element + * @var array + */ + protected $data = array('content' => ''); + + public function getType() + { + return 'static'; + } + + /** + * Static element can not be frozen + * + * @param bool Whether element should be frozen or editable. This + * parameter is ignored in case of static elements + * @return bool Always returns false + */ + public function toggleFrozen($freeze = null) + { + return false; + } + + /** + * Sets the contents of the static element + * + * @param string Static content + * @return HTML_QuickForm2_Element_Static + */ + function setContent($content) + { + $this->data['content'] = $content; + return $this; + } + + /** + * Returns the contents of the static element + * + * @return string + */ + function getContent() + { + return $this->data['content']; + } + + /** + * Static element's content can also be set via this method + * + * @param mixed Element's value, this parameter is ignored + * @return HTML_QuickForm2_Element_Static + */ + public function setValue($value) + { + $this->setContent($value); + return $this; + } + + /** + * Static elements have no value + * + * @return null + */ + public function getValue() + { + return null; + } + + public function __toString() + { + return $this->getIndent() . $this->data['content']; + } + + /** + * Called when the element needs to update its value from form's data sources + * + * Static elements content can be updated with default form values. + */ + protected function updateValue() + { + foreach ($this->getDataSources() as $ds) { + if (!$ds instanceof HTML_QuickForm2_DataSource_Submit && + null !== ($value = $ds->getValue($this->getName()))) + { + $this->setContent($value); + return; + } + } + } +} +?>
\ No newline at end of file diff --git a/libs/HTML/QuickForm2/Element/Textarea.php b/libs/HTML/QuickForm2/Element/Textarea.php new file mode 100644 index 0000000000..ff6892d35c --- /dev/null +++ b/libs/HTML/QuickForm2/Element/Textarea.php @@ -0,0 +1,110 @@ +<?php +/** + * Class for <textarea> elements + * + * PHP version 5 + * + * LICENSE: + * + * Copyright (c) 2006-2010, Alexey Borzov <avb@php.net>, + * Bertrand Mansion <golgote@mamasam.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * The names of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version SVN: $Id: Textarea.php 300722 2010-06-24 10:15:52Z mansion $ + * @link http://pear.php.net/package/HTML_QuickForm2 + */ + +/** + * Base class for simple HTML_QuickForm2 elements + */ +require_once 'HTML/QuickForm2/Element.php'; + +/** + * Class for <textarea> elements + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @version Release: @package_version@ + */ +class HTML_QuickForm2_Element_Textarea extends HTML_QuickForm2_Element +{ + protected $persistent = true; + + /** + * Value for textarea field + * @var string + */ + protected $value = null; + + public function getType() + { + return 'textarea'; + } + + public function setValue($value) + { + $this->value = $value; + return $this; + } + + public function getValue() + { + return empty($this->attributes['disabled'])? $this->applyFilters($this->value): null; + } + + public function __toString() + { + if ($this->frozen) { + return $this->getFrozenHtml(); + } else { + return $this->getIndent() . '<textarea' . $this->getAttributes(true) . + '>' . preg_replace("/(\r\n|\n|\r)/", '
', htmlspecialchars( + $this->value, ENT_QUOTES, self::getOption('charset') + )) . '</textarea>'; + } + } + + public function getFrozenHtml() + { + $value = htmlspecialchars($this->value, ENT_QUOTES, self::getOption('charset')); + if ('off' == $this->getAttribute('wrap')) { + $html = $this->getIndent() . '<pre>' . $value . + '</pre>' . self::getOption('linebreak'); + } else { + $html = nl2br($value) . self::getOption('linbebreak'); + } + return $html . $this->getPersistentContent(); + } +} +?> diff --git a/libs/HTML/QuickForm2/Exception.php b/libs/HTML/QuickForm2/Exception.php new file mode 100644 index 0000000000..29e7a7f206 --- /dev/null +++ b/libs/HTML/QuickForm2/Exception.php @@ -0,0 +1,109 @@ +<?php +/** + * Exception classes for HTML_QuickForm2 + * + * PHP version 5 + * + * LICENSE: + * + * Copyright (c) 2006-2010, Alexey Borzov <avb@php.net>, + * Bertrand Mansion <golgote@mamasam.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * The names of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version SVN: $Id: Exception.php 294057 2010-01-26 21:10:28Z avb $ + * @link http://pear.php.net/package/HTML_QuickForm2 + */ + +/** + * Base class for exceptions in PEAR + */ +require_once 'PEAR/Exception.php'; + +/** + * Base class for exceptions in HTML_QuickForm2 package + * + * Such a base class is required by the Exception RFC: + * http://pear.php.net/pepr/pepr-proposal-show.php?id=132 + * It will rarely be thrown directly, its specialized subclasses will be + * thrown most of the time. + * + * @category HTML + * @package HTML_QuickForm2 + * @version Release: @package_version@ + */ +class HTML_QuickForm2_Exception extends PEAR_Exception +{ +} + +/** + * Exception that denotes some resource was not found + * + * One example is trying to instantiate a nonexistent class in Factory + * <code> + * try { + * HTML_QuickForm2_Factory::registerElement('missing', 'NonExistent'); + * $el = HTML_QuickForm2_Factory::createElement('missing'); + * } catch (HTML_QuickForm2_NotFoundException $e) { + * echo $e->getMessage(); + * } + * </code> + * This code fill output "Class 'NonExistent' does not exist and no file to load" + * + * @category HTML + * @package HTML_QuickForm2 + * @version Release: @package_version@ + */ +class HTML_QuickForm2_NotFoundException extends HTML_QuickForm2_Exception +{ +} + +/** + * Exception that denotes invalid arguments were passed + * + * One example is trying to create an element of type which is unknown to Factory + * <code> + * try { + * $el = HTML_QuickForm2_Factory::createElement('unknown'); + * } catch (HTML_QuickForm2_InvalidArgumentException $e) { + * echo $e->getMessage(); + * } + * </code> + * This code will output "Element type 'unknown' is not known" + * + * @category HTML + * @package HTML_QuickForm2 + * @version Release: @package_version@ + */ +class HTML_QuickForm2_InvalidArgumentException extends HTML_QuickForm2_Exception +{ +} +?> diff --git a/libs/HTML/QuickForm2/Factory.php b/libs/HTML/QuickForm2/Factory.php new file mode 100644 index 0000000000..5f3028edbe --- /dev/null +++ b/libs/HTML/QuickForm2/Factory.php @@ -0,0 +1,229 @@ +<?php +/** + * Static Factory class for HTML_QuickForm2 package + * + * PHP version 5 + * + * LICENSE: + * + * Copyright (c) 2006-2010, Alexey Borzov <avb@php.net>, + * Bertrand Mansion <golgote@mamasam.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * The names of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version SVN: $Id: Factory.php 299305 2010-05-12 20:15:28Z avb $ + * @link http://pear.php.net/package/HTML_QuickForm2 + */ + +/** + * Class with static methods for loading classes and files + */ +require_once 'HTML/QuickForm2/Loader.php'; + +/** + * Static factory class + * + * The class handles instantiation of Element and Rule objects as well as + * registering of new Element and Rule classes. + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @version Release: @package_version@ + */ +class HTML_QuickForm2_Factory +{ + /** + * List of element types known to Factory + * @var array + */ + protected static $elementTypes = array( + 'button' => array('HTML_QuickForm2_Element_Button', null), + 'checkbox' => array('HTML_QuickForm2_Element_InputCheckbox', null), + 'date' => array('HTML_QuickForm2_Element_Date', null), + 'fieldset' => array('HTML_QuickForm2_Container_Fieldset', null), + 'group' => array('HTML_QuickForm2_Container_Group', null), + 'file' => array('HTML_QuickForm2_Element_InputFile', null), + 'hidden' => array('HTML_QuickForm2_Element_InputHidden', null), + 'image' => array('HTML_QuickForm2_Element_InputImage', null), + 'inputbutton' => array('HTML_QuickForm2_Element_InputButton', null), + 'password' => array('HTML_QuickForm2_Element_InputPassword', null), + 'radio' => array('HTML_QuickForm2_Element_InputRadio', null), + 'reset' => array('HTML_QuickForm2_Element_InputReset', null), + 'select' => array('HTML_QuickForm2_Element_Select', null), + 'submit' => array('HTML_QuickForm2_Element_InputSubmit', null), + 'text' => array('HTML_QuickForm2_Element_InputText', null), + 'textarea' => array('HTML_QuickForm2_Element_Textarea', null) + ); + + /** + * List of registered rules + * @var array + */ + protected static $registeredRules = array( + 'nonempty' => array('HTML_QuickForm2_Rule_Nonempty', null), + 'empty' => array('HTML_QuickForm2_Rule_Empty', null), + 'required' => array('HTML_QuickForm2_Rule_Required', null), + 'compare' => array('HTML_QuickForm2_Rule_Compare', null), + 'eq' => array('HTML_QuickForm2_Rule_Compare', null, + array('operator' => '===')), + 'neq' => array('HTML_QuickForm2_Rule_Compare', null, + array('operator' => '!==')), + 'lt' => array('HTML_QuickForm2_Rule_Compare', null, + array('operator' => '<')), + 'lte' => array('HTML_QuickForm2_Rule_Compare', null, + array('operator' => '<=')), + 'gt' => array('HTML_QuickForm2_Rule_Compare', null, + array('operator' => '>')), + 'gte' => array('HTML_QuickForm2_Rule_Compare', null, + array('operator' => '>=')), + 'regex' => array('HTML_QuickForm2_Rule_Regex', null), + 'callback' => array('HTML_QuickForm2_Rule_Callback', null), + 'length' => array('HTML_QuickForm2_Rule_Length', null), + 'minlength' => array('HTML_QuickForm2_Rule_Length', null, + array('max' => 0)), + 'maxlength' => array('HTML_QuickForm2_Rule_Length', null, + array('min' => 0)), + 'maxfilesize' => array('HTML_QuickForm2_Rule_MaxFileSize', null), + 'mimetype' => array('HTML_QuickForm2_Rule_MimeType', null), + 'each' => array('HTML_QuickForm2_Rule_Each', null), + 'notcallback' => array('HTML_QuickForm2_Rule_NotCallback', null), + 'notregex' => array('HTML_QuickForm2_Rule_NotRegex', null) + ); + + + /** + * Registers a new element type + * + * @param string Type name (treated case-insensitively) + * @param string Class name + * @param string File containing the class, leave empty if class already loaded + */ + public static function registerElement($type, $className, $includeFile = null) + { + self::$elementTypes[strtolower($type)] = array($className, $includeFile); + } + + + /** + * Checks whether an element type is known to factory + * + * @param string Type name (treated case-insensitively) + * @return bool + */ + public static function isElementRegistered($type) + { + return isset(self::$elementTypes[strtolower($type)]); + } + + + /** + * Creates a new element object of the given type + * + * @param string Type name (treated case-insensitively) + * @param mixed Element name (passed to element's constructor) + * @param mixed Element attributes (passed to element's constructor) + * @param array Element-specific data (passed to element's constructor) + * @return HTML_QuickForm2_Node A created element + * @throws HTML_QuickForm2_InvalidArgumentException If type name is unknown + * @throws HTML_QuickForm2_NotFoundException If class for the element can + * not be found and/or loaded from file + */ + public static function createElement($type, $name = null, $attributes = null, + array $data = array()) + { + $type = strtolower($type); + if (!isset(self::$elementTypes[$type])) { + throw new HTML_QuickForm2_InvalidArgumentException("Element type '$type' is not known"); + } + list($className, $includeFile) = self::$elementTypes[$type]; + HTML_QuickForm2_Loader::loadClass($className, $includeFile); + return new $className($name, $attributes, $data); + } + + + /** + * Registers a new rule type + * + * @param string Rule type name (treated case-insensitively) + * @param string Class name + * @param string File containing the class, leave empty if class already loaded + * @param mixed Configuration data for rules of the given type + */ + public static function registerRule($type, $className, $includeFile = null, + $config = null) + { + self::$registeredRules[strtolower($type)] = array($className, $includeFile, $config); + } + + + /** + * Checks whether a rule type is known to Factory + * + * @param string Rule type name (treated case-insensitively) + * @return bool + */ + public static function isRuleRegistered($type) + { + return isset(self::$registeredRules[strtolower($type)]); + } + + + /** + * Creates a new Rule of the given type + * + * @param string Rule type name (treated case-insensitively) + * @param HTML_QuickForm2_Node Element to validate by the rule + * @param string Message to display if validation fails + * @param mixed Configuration data for the rule + * @return HTML_QuickForm2_Rule A created Rule + * @throws HTML_QuickForm2_InvalidArgumentException If rule type is unknown + * @throws HTML_QuickForm2_NotFoundException If class for the rule + * can't be found and/or loaded from file + */ + public static function createRule($type, HTML_QuickForm2_Node $owner, + $message = '', $config = null) + { + $type = strtolower($type); + if (!isset(self::$registeredRules[$type])) { + throw new HTML_QuickForm2_InvalidArgumentException("Rule '$type' is not known"); + } + list($className, $includeFile) = self::$registeredRules[$type]; + HTML_QuickForm2_Loader::loadClass($className, $includeFile); + if (isset(self::$registeredRules[$type][2])) { + $config = call_user_func(array($className, 'mergeConfig'), $config, + self::$registeredRules[$type][2]); + } + return new $className($owner, $message, $config); + } +} +?> diff --git a/libs/HTML/QuickForm2/JavascriptBuilder.php b/libs/HTML/QuickForm2/JavascriptBuilder.php new file mode 100644 index 0000000000..8723d05905 --- /dev/null +++ b/libs/HTML/QuickForm2/JavascriptBuilder.php @@ -0,0 +1,120 @@ +<?php +/** + * Javascript aggregator and builder class + * + * PHP version 5 + * + * LICENSE: + * + * Copyright (c) 2006-2010, Alexey Borzov <avb@php.net>, + * Bertrand Mansion <golgote@mamasam.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * The names of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version SVN: $Id: JavascriptBuilder.php 299480 2010-05-19 06:55:03Z avb $ + * @link http://pear.php.net/package/HTML_QuickForm2 + */ + +/** + * Exception classes for HTML_QuickForm2 + */ +require_once 'HTML/QuickForm2/Exception.php'; + +/** + * Javascript aggregator and builder class + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @version Release: @package_version@ + */ +class HTML_QuickForm2_JavascriptBuilder +{ + /** + * Client-side rules + * @var array + */ + protected $rules = array(); + + /** + * Current form ID + * @var string + */ + protected $formId = null; + + /** + * Sets the form currently being processed + * + * @param HTML_QuickForm2 + */ + public function startForm(HTML_QuickForm2 $form) + { + $this->formId = $form->getId(); + $this->rules[$this->formId] = array(); + } + + /** + * Adds the Rule javascript to the list of current form Rules + * + * @param HTML_QuickForm2_Rule + */ + public function addRule(HTML_QuickForm2_Rule $rule) + { + $this->rules[$this->formId][] = $rule->getJavascript(); + } + + /** + * Returns client-side validation code + * + * @todo This shouldn't probably be __toString() as we can't throw exceptions from that + * @todo Of course we shouldn't put library files into each page, need some means to include them via <script> tags + */ + public function __toString() + { + $js = ''; + foreach ($this->rules as $formId => $rules) { + if (!empty($rules)) { + $js .= "new qf.validator(document.getElementById('{$formId}'), [\n" . + implode(",\n", $rules) . + "\n]);"; + } + } + if ('' != $js) { + $js = "<script type=\"text/javascript\">\n//<![CDATA[\n" . + file_get_contents('@data_dir@/HTML_QuickForm2/quickform.js') . + "qf.events.contentReady(function() {\n{$js}\n});\n" . + "//]]>\n</script>"; + } + return $js; + } +} +?> diff --git a/libs/HTML/QuickForm2/Loader.php b/libs/HTML/QuickForm2/Loader.php new file mode 100644 index 0000000000..f058d45dd5 --- /dev/null +++ b/libs/HTML/QuickForm2/Loader.php @@ -0,0 +1,140 @@ +<?php +/** + * Class with static methods for loading classes and files + * + * PHP version 5 + * + * LICENSE: + * + * Copyright (c) 2006-2010, Alexey Borzov <avb@php.net>, + * Bertrand Mansion <golgote@mamasam.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * The names of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version SVN: $Id: Loader.php 294057 2010-01-26 21:10:28Z avb $ + * @link http://pear.php.net/package/HTML_QuickForm2 + */ + +/** + * Exception classes for HTML_QuickForm2 + */ +require_once 'HTML/QuickForm2/Exception.php'; + +/** + * Class with static methods for loading classes and files + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @version Release: @package_version@ + */ +class HTML_QuickForm2_Loader +{ + /** + * Tries to load a given class + * + * If no $includeFile was provided, $className will be used with underscores + * replaced with path separators and '.php' extension appended + * + * @param string Class name to load + * @param string Name of the file (supposedly) containing the given class + * @throws HTML_QuickForm2_NotFoundException If the file either can't be + * loaded or doesn't contain the given class + */ + public static function loadClass($className, $includeFile = null) + { + if (class_exists($className, false) || interface_exists($className, false)) { + return true; + } + + if (empty($includeFile)) { + $includeFile = str_replace('_', DIRECTORY_SEPARATOR, $className) . '.php'; + } + // Do not silence the errors with @, parse errors will not be seen + include $includeFile; + + // Still no class? + if (!class_exists($className, false) && !interface_exists($className, false)) { + if (!self::fileExists($includeFile)) { + throw new HTML_QuickForm2_NotFoundException( + "File '$includeFile' was not found" + ); + } else { + throw new HTML_QuickForm2_NotFoundException( + "Class '$className' was not found within file '$includeFile'" + ); + } + } + } + + /** + * Checks whether the file exists in the include path + * + * @param string file name + * @return bool + */ + public static function fileExists($fileName) + { + $fp = @fopen($fileName, 'r', true); + if (is_resource($fp)) { + fclose($fp); + return true; + } + return false; + } + + /** + * Loading of HTML_QuickForm2_* classes suitable for SPL autoload mechanism + * + * This method will only try to load a class if its name starts with + * HTML_QuickForm2. Register with the following: + * <code> + * spl_autoload_register(array('HTML_QuickForm2_Loader', 'autoload')); + * </code> + * + * @param string Class name + * @return bool Whether class loaded successfully + */ + public static function autoload($class) + { + if (0 !== strpos($class, 'HTML_QuickForm2')) { + return false; + } + try { + @self::loadClass($class); + return true; + } catch (Exception $e) { + return false; + } + } +} +?> diff --git a/libs/HTML/QuickForm2/Node.php b/libs/HTML/QuickForm2/Node.php new file mode 100644 index 0000000000..ae770561ba --- /dev/null +++ b/libs/HTML/QuickForm2/Node.php @@ -0,0 +1,692 @@ +<?php +/** + * Base class for all HTML_QuickForm2 elements + * + * PHP version 5 + * + * LICENSE: + * + * Copyright (c) 2006-2010, Alexey Borzov <avb@php.net>, + * Bertrand Mansion <golgote@mamasam.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * The names of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version SVN: $Id: Node.php 300747 2010-06-25 16:16:50Z mansion $ + * @link http://pear.php.net/package/HTML_QuickForm2 + */ + +/** + * HTML_Common2 - base class for HTML elements + */ +require_once 'HTML/Common2.php'; + +// By default, we generate element IDs with numeric indexes appended even for +// elements with unique names. If you want IDs to be equal to the element +// names by default, set this configuration option to false. +if (null === HTML_Common2::getOption('id_force_append_index')) { + HTML_Common2::setOption('id_force_append_index', true); +} + +/** + * Exception classes for HTML_QuickForm2 + */ +require_once 'HTML/QuickForm2/Exception.php'; + +/** + * Static factory class for QuickForm2 elements + */ +require_once 'HTML/QuickForm2/Factory.php'; + +/** + * Base class for HTML_QuickForm2 rules + */ +require_once 'HTML/QuickForm2/Rule.php'; + + +/** + * Abstract base class for all QuickForm2 Elements and Containers + * + * This class is mostly here to define the interface that should be implemented + * by the subclasses. It also contains static methods handling generation + * of unique ids for elements which do not have ids explicitly set. + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @version Release: @package_version@ + */ +abstract class HTML_QuickForm2_Node extends HTML_Common2 +{ + /** + * Array containing the parts of element ids + * @var array + */ + protected static $ids = array(); + + /** + * Element's "frozen" status + * @var boolean + */ + protected $frozen = false; + + /** + * Whether element's value should persist when element is frozen + * @var boolean + */ + protected $persistent = false; + + /** + * Element containing current + * @var HTML_QuickForm2_Container + */ + protected $container = null; + + /** + * Contains options and data used for the element creation + * @var array + */ + protected $data = array(); + + /** + * Validation rules for element + * @var array + */ + protected $rules = array(); + + /** + * An array of callback filters for element + * @var array + */ + protected $filters = array(); + + /** + * Error message (usually set via Rule if validation fails) + * @var string + */ + protected $error = null; + + /** + * Changing 'name' and 'id' attributes requires some special handling + * @var array + */ + protected $watchedAttributes = array('id', 'name'); + + /** + * Intercepts setting 'name' and 'id' attributes + * + * These attributes should always be present and thus trying to remove them + * will result in an exception. Changing their values is delegated to + * setName() and setId() methods, respectively + * + * @param string Attribute name + * @param string Attribute value, null if attribute is being removed + * @throws HTML_QuickForm2_InvalidArgumentException if trying to + * remove a required attribute + */ + protected function onAttributeChange($name, $value = null) + { + if ('name' == $name) { + if (null === $value) { + throw new HTML_QuickForm2_InvalidArgumentException( + "Required attribute 'name' can not be removed" + ); + } else { + $this->setName($value); + } + } elseif ('id' == $name) { + if (null === $value) { + throw new HTML_QuickForm2_InvalidArgumentException( + "Required attribute 'id' can not be removed" + ); + } else { + $this->setId($value); + } + } + } + + /** + * Class constructor + * + * @param string Element name + * @param mixed Attributes (either a string or an array) + * @param array Element data (label, options and data used for element creation) + */ + public function __construct($name = null, $attributes = null, $data = null) + { + parent::__construct($attributes); + $this->setName($name); + // Autogenerating the id if not set on previous steps + if ('' == $this->getId()) { + $this->setId(); + } + if (!empty($data)) { + $this->data = array_merge($this->data, $data); + } + } + + + /** + * Generates an id for the element + * + * Called when an element is created without explicitly given id + * + * @param string Element name + * @return string The generated element id + */ + protected static function generateId($elementName) + { + $stop = !self::getOption('id_force_append_index'); + $tokens = strlen($elementName) + ? explode('[', str_replace(']', '', $elementName)) + : ($stop? array('qfauto', ''): array('qfauto')); + $container =& self::$ids; + $id = ''; + + do { + $token = array_shift($tokens); + // Handle the 'array[]' names + if ('' === $token) { + if (empty($container)) { + $token = 0; + } else { + $keys = array_keys($container); + $token = end($keys); + while (isset($container[$token])) { + $token++; + } + } + } + $id .= '-' . $token; + if (!isset($container[$token])) { + $container[$token] = array(); + // Handle duplicate names when not having mandatory indexes + } elseif (empty($tokens) && $stop) { + $tokens[] = ''; + } + // Handle mandatory indexes + if (empty($tokens) && !$stop) { + $tokens[] = ''; + $stop = true; + } + $container =& $container[$token]; + } while (!empty($tokens)); + + return substr($id, 1); + } + + + /** + * Stores the explicitly given id to prevent duplicate id generation + * + * @param string Element id + */ + protected static function storeId($id) + { + $tokens = explode('-', $id); + $container =& self::$ids; + + do { + $token = array_shift($tokens); + if (!isset($container[$token])) { + $container[$token] = array(); + } + $container =& $container[$token]; + } while (!empty($tokens)); + } + + + /** + * Returns the element options + * + * @return array + */ + public function getData() + { + return $this->data; + } + + + /** + * Returns the element's type + * + * @return string + */ + abstract public function getType(); + + + /** + * Returns the element's name + * + * @return string + */ + public function getName() + { + return isset($this->attributes['name'])? $this->attributes['name']: null; + } + + + /** + * Sets the element's name + * + * @param string + * @return HTML_QuickForm2_Node + */ + abstract public function setName($name); + + + /** + * Returns the element's id + * + * @return string + */ + public function getId() + { + return isset($this->attributes['id'])? $this->attributes['id']: null; + } + + + /** + * Sets the elements id + * + * Please note that elements should always have an id in QuickForm2 and + * therefore it will not be possible to remove the element's id or set it to + * an empty value. If id is not explicitly given, it will be autogenerated. + * + * @param string Element's id, will be autogenerated if not given + * @return HTML_QuickForm2_Node + */ + public function setId($id = null) + { + if (is_null($id)) { + $id = self::generateId($this->getName()); + } else { + self::storeId($id); + } + $this->attributes['id'] = (string)$id; + return $this; + } + + + /** + * Returns the element's value + * + * @return mixed + */ + abstract public function getValue(); + + + /** + * Sets the element's value + * + * @param mixed + * @return HTML_QuickForm2_Node + */ + abstract public function setValue($value); + + + /** + * Returns the element's label(s) + * + * @return string|array + */ + public function getLabel() + { + if (isset($this->data['label'])) { + return $this->data['label']; + } + return null; + } + + + /** + * Sets the element's label(s) + * + * @param string|array Label for the element (may be an array of labels) + * @return HTML_QuickForm2_Node + */ + public function setLabel($label) + { + $this->data['label'] = $label; + return $this; + } + + + /** + * Changes the element's frozen status + * + * @param bool Whether the element should be frozen or editable. If + * omitted, the method will not change the frozen status, + * just return its current value + * @return bool Old value of element's frozen status + */ + public function toggleFrozen($freeze = null) + { + $old = $this->frozen; + if (null !== $freeze) { + $this->frozen = (bool)$freeze; + } + return $old; + } + + + /** + * Changes the element's persistent freeze behaviour + * + * If persistent freeze is on, the element's value will be kept (and + * submitted) in a hidden field when the element is frozen. + * + * @param bool New value for "persistent freeze". If omitted, the + * method will not set anything, just return the current + * value of the flag. + * @return bool Old value of "persistent freeze" flag + */ + public function persistentFreeze($persistent = null) + { + $old = $this->persistent; + if (null !== $persistent) { + $this->persistent = (bool)$persistent; + } + return $old; + } + + + /** + * Adds the link to the element containing current + * + * @param HTML_QuickForm2_Container Element containing the current one, + * null if the link should really be + * removed (if removing from container) + * @throws HTML_QuickForm2_InvalidArgumentException If trying to set a + * child of an element as its container + */ + protected function setContainer(HTML_QuickForm2_Container $container = null) + { + if (null !== $container) { + $check = $container; + do { + if ($this === $check) { + throw new HTML_QuickForm2_InvalidArgumentException( + 'Cannot set an element or its child as its own container' + ); + } + } while ($check = $check->getContainer()); + if (null !== $this->container && $container !== $this->container) { + $this->container->removeChild($this); + } + } + $this->container = $container; + if (null !== $container) { + $this->updateValue(); + } + } + + + /** + * Returns the element containing current + * + * @return HTML_QuickForm2_Container|null + */ + public function getContainer() + { + return $this->container; + } + + /** + * Returns the data sources for this element + * + * @return array + */ + protected function getDataSources() + { + if (empty($this->container)) { + return array(); + } else { + return $this->container->getDataSources(); + } + } + + /** + * Called when the element needs to update its value from form's data sources + */ + abstract protected function updateValue(); + + /** + * Adds a validation rule + * + * @param HTML_QuickForm2_Rule|string Validation rule or rule type + * @param string|int If first parameter is rule type, then + * message to display if validation fails, otherwise constant showing + * whether to perfom validation client-side and/or server-side + * @param mixed Additional data for the rule + * @param int Whether to perfom validation server-side + * and/or client side. Combination of HTML_QuickForm2_Rule::RUNAT_* constants + * @return HTML_QuickForm2_Rule The added rule + * @throws HTML_QuickForm2_InvalidArgumentException if $rule is of a + * wrong type or rule name isn't registered with Factory + * @throws HTML_QuickForm2_NotFoundException if class for a given rule + * name cannot be found + * @todo Need some means to mark the Rules for running client-side + */ + public function addRule($rule, $messageOrRunAt = '', $options = null, + $runAt = HTML_QuickForm2_Rule::RUNAT_SERVER) + { + if ($rule instanceof HTML_QuickForm2_Rule) { + $rule->setOwner($this); + $runAt = '' == $messageOrRunAt? HTML_QuickForm2_Rule::RUNAT_SERVER: $messageOrRunAt; + } elseif (is_string($rule)) { + $rule = HTML_QuickForm2_Factory::createRule($rule, $this, $messageOrRunAt, $options); + } else { + throw new HTML_QuickForm2_InvalidArgumentException( + 'addRule() expects either a rule type or ' . + 'a HTML_QuickForm2_Rule instance' + ); + } + + $this->rules[] = array($rule, $runAt); + return $rule; + } + + /** + * Removes a validation rule + * + * The method will *not* throw an Exception if the rule wasn't added to the + * element. + * + * @param HTML_QuickForm2_Rule Validation rule to remove + * @return HTML_QuickForm2_Rule Removed rule + */ + public function removeRule(HTML_QuickForm2_Rule $rule) + { + foreach ($this->rules as $i => $r) { + if ($r[0] === $rule) { + unset($this->rules[$i]); + break; + } + } + return $rule; + } + + /** + * Creates a validation rule + * + * This method is mostly useful when when chaining several rules together + * via {@link HTML_QuickForm2_Rule::and_()} and {@link HTML_QuickForm2_Rule::or_()} + * methods: + * <code> + * $first->addRule('nonempty', 'Fill in either first or second field') + * ->or_($second->createRule('nonempty')); + * </code> + * + * @param string Rule type + * @param string Message to display if validation fails + * @param mixed Additional data for the rule + * @return HTML_QuickForm2_Rule The created rule + * @throws HTML_QuickForm2_InvalidArgumentException If rule type is unknown + * @throws HTML_QuickForm2_NotFoundException If class for the rule + * can't be found and/or loaded from file + */ + public function createRule($type, $message = '', $options = null) + { + return HTML_QuickForm2_Factory::createRule($type, $this, $message, $options); + } + + + /** + * Checks whether an element is required + * + * @return boolean + */ + public function isRequired() + { + foreach ($this->rules as $rule) { + if ($rule[0] instanceof HTML_QuickForm2_Rule_Required) { + return true; + } + } + return false; + } + + + /** + * Performs the server-side validation + * + * @return boolean Whether the element is valid + */ + protected function validate() + { + foreach ($this->rules as $rule) { + if (strlen($this->error)) { + break; + } + if ($rule[1] & HTML_QuickForm2_Rule::RUNAT_SERVER) { + $rule[0]->validate(); + } + } + return !strlen($this->error); + } + + /** + * Sets the error message to the element + * + * @param string + * @return HTML_QuickForm2_Node + */ + public function setError($error = null) + { + $this->error = (string)$error; + return $this; + } + + /** + * Returns the error message for the element + * + * @return string + */ + public function getError() + { + return $this->error; + } + + /** + * Returns Javascript code for getting the element's value + * + * @return string + */ + abstract public function getJavascriptValue(); + + /** + * Adds a filter + * + * A filter is simply a PHP callback which will be applied to the element value + * when getValue() is called. A filter is by default applied recursively : + * if the value is an array, each elements it contains will + * also be filtered, unless the recursive flag is set to false. + * + * @param callback The PHP callback used for filter + * @param array Optional arguments for the callback. The first parameter + * will always be the element value, then these options will + * be used as parameters for the callback. + * @param bool Whether to apply the filter recursively to contained elements + * @return HTML_QuickForm2_Node The element + * @throws HTML_QuickForm2_InvalidArgumentException If callback is incorrect + */ + public function addFilter($callback, array $options = null, $recursive = true) + { + if (!is_callable($callback, false, $callbackName)) { + throw new HTML_QuickForm2_InvalidArgumentException( + 'Callback Filter requires a valid callback, \'' . $callbackName . + '\' was given' + ); + } + $this->filters[] = array($callback, $options, 'recursive' => $recursive); + return $this; + } + + /** + * Removes all element filters + */ + public function removeFilters() + { + $this->filters = array(); + } + + /** + * Applies element filters on element value + * @param mixed Element value + * @return mixed Filtered value + */ + protected function applyFilters($value) + { + foreach ($this->filters as $filter) { + if (is_array($value) && !empty($filter['recursive'])) { + array_walk_recursive(&$value, + array('HTML_QuickForm2_Node', 'applyFilter'), $filter); + } else { + self::applyFilter($value, null, $filter); + } + } + return $value; + } + + protected static function applyFilter(&$value, $key = null, $filter) + { + $callback = $filter[0]; + $options = $filter[1]; + if (!is_array($options)) { + $options = array(); + } + array_unshift($options, $value); + $value = call_user_func_array($callback, $options); + } + +} +?> diff --git a/libs/HTML/QuickForm2/Renderer.php b/libs/HTML/QuickForm2/Renderer.php new file mode 100644 index 0000000000..3b696a5c03 --- /dev/null +++ b/libs/HTML/QuickForm2/Renderer.php @@ -0,0 +1,360 @@ +<?php +/** + * Base class for HTML_QuickForm2 renderers + * + * PHP version 5 + * + * LICENSE: + * + * Copyright (c) 2006-2010, Alexey Borzov <avb@php.net>, + * Bertrand Mansion <golgote@mamasam.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * The names of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version SVN: $Id: Renderer.php 299706 2010-05-24 18:32:37Z avb $ + * @link http://pear.php.net/package/HTML_QuickForm2 + */ + +/** + * Class with static methods for loading classes and files + */ +require_once 'HTML/QuickForm2/Loader.php'; + +/** + * Abstract base class for QuickForm2 renderers + * + * This class serves two main purposes: + * <ul> + * <li>Defines the API all renderers should implement (render*() methods);</li> + * <li>Provides static methods for registering renderers and their plugins + * and {@link factory()} method for creating renderer instances.</li> + * </ul> + * + * Note that renderers should always be instantiated through factory(), in the + * other case it will not be possible to add plugins. + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @version Release: @package_version@ + */ +abstract class HTML_QuickForm2_Renderer +{ + /** + * List of registered renderer types + * @var array + */ + private static $_types = array( + 'default' => array('HTML_QuickForm2_Renderer_Default', null), + 'array' => array('HTML_QuickForm2_Renderer_Array', null) + ); + + /** + * List of registered renderer plugins + * @var array + */ + private static $_pluginClasses = array( + 'default' => array(), + 'array' => array() + ); + + /** + * Renderer options + * @var array + * @see setOption() + */ + protected $options = array( + 'group_hiddens' => true, + 'required_note' => '<em>*</em> denotes required fields.', + 'errors_prefix' => 'Invalid information entered:', + 'errors_suffix' => 'Please correct these fields.', + 'group_errors' => false + ); + + /** + * Javascript builder object + * @var HTML_QuickForm2_JavascriptBuilder + */ + protected $jsBuilder; + + /** + * Creates a new renderer instance of the given type + * + * A renderer is always wrapped by a Proxy, which handles calling its + * "published" methods and methods of its plugins. Registered plugins are + * added automagically to the existing renderer instances so that + * <code> + * $foo = HTML_QuickForm2_Renderer::factory('foo'); + * // Plugin implementing bar() method + * HTML_QuickForm2_Renderer::registerPlugin('foo', 'Plugin_Foo_Bar'); + * $foo->bar(); + * </code> + * will work. + * + * @param string Type name (treated case-insensitively) + * @return HTML_QuickForm2_Renderer_Proxy A renderer instance of the given + * type wrapped by a Proxy + * @throws HTML_QuickForm2_InvalidArgumentException If type name is unknown + * @throws HTML_QuickForm2_NotFoundException If class for the renderer can + * not be found and/or loaded from file + */ + final public static function factory($type) + { + $type = strtolower($type); + if (!isset(self::$_types[$type])) { + throw new HTML_QuickForm2_InvalidArgumentException( + "Renderer type '$type' is not known" + ); + } + + list ($className, $includeFile) = self::$_types[$type]; + HTML_QuickForm2_Loader::loadClass($className, $includeFile); + HTML_QuickForm2_Loader::loadClass('HTML_QuickForm2_Renderer_Proxy'); + return new HTML_QuickForm2_Renderer_Proxy(new $className, self::$_pluginClasses[$type]); + } + + /** + * Registers a new renderer type + * + * @param string Type name (treated case-insensitively) + * @param string Class name + * @param string File containing the class, leave empty if class already loaded + * @throws HTML_QuickForm2_InvalidArgumentException if type already registered + */ + final public static function register($type, $className, $includeFile = null) + { + $type = strtolower($type); + if (!empty(self::$_types[$type])) { + throw new HTML_QuickForm2_InvalidArgumentException( + "Renderer type '$type' is already registered" + ); + } + self::$_types[$type] = array($className, $includeFile); + if (empty(self::$_pluginClasses[$type])) { + self::$_pluginClasses[$type] = array(); + } + } + + /** + * Registers a plugin for a renderer type + * + * @param string Renderer type name (treated case-insensitively) + * @param string Plugin class name + * @param string File containing the plugin class, leave empty if class already loaded + * @throws HTML_QuickForm2_InvalidArgumentException if plugin is already registered + */ + final public static function registerPlugin($type, $className, $includeFile = null) + { + $type = strtolower($type); + // We don't check self::$_types, since a plugin may be registered + // before renderer itself if it goes with some custom element + if (empty(self::$_pluginClasses[$type])) { + self::$_pluginClasses[$type] = array(array($className, $includeFile)); + } else { + foreach (self::$_pluginClasses[$type] as $plugin) { + if (0 == strcasecmp($plugin[0], $className)) { + throw new HTML_QuickForm2_InvalidArgumentException( + "Plugin '$className' for renderer type '$type' is already registered" + ); + } + } + self::$_pluginClasses[$type][] = array($className, $includeFile); + } + } + + /** + * Constructor + * + * Renderer instances should not be created directly, use {@link factory()} + */ + protected function __construct() + { + } + + /** + * Returns an array of "published" method names that should be callable through proxy + * + * Methods defined in HTML_QuickForm2_Renderer are proxied automatically, + * only additional methods should be returned. + * + * @return array + */ + protected function exportMethods() + { + return array(); + } + + /** + * Sets the option(s) affecting renderer behaviour + * + * The following options are available: + * <ul> + * <li>'group_hiddens' - whether to group hidden elements together or + * render them where they were added (boolean)</li> + * <li>'group_errors' - whether to group error messages or render them + * alongside elements they apply to (boolean)</li> + * <li>'errors_prefix' - leading message for grouped errors (string)</li> + * <li>'errors_suffix' - trailing message for grouped errors (string)</li> + * <li>'required_note' - note displayed if the form contains required + * elements (string)</li> + * </ul> + * + * @param string|array option name or array ('option name' => 'option value') + * @param mixed parameter value if $nameOrConfig is not an array + * @return HTML_QuickForm2_Renderer + * @throws HTML_QuickForm2_NotFoundException in case of unknown option + */ + public function setOption($nameOrOptions, $value = null) + { + if (is_array($nameOrOptions)) { + foreach ($nameOrOptions as $name => $value) { + $this->setOption($name, $value); + } + + } else { + if (!array_key_exists($nameOrOptions, $this->options)) { + throw new HTML_QuickForm2_NotFoundException( + "Unknown option '{$nameOrOptions}'" + ); + } + $this->options[$nameOrOptions] = $value; + } + + return $this; + } + + /** + * Returns the value(s) of the renderer option(s) + * + * @param string parameter name + * @return mixed value of $name parameter, array of all configuration + * parameters if $name is not given + * @throws HTML_QuickForm2_NotFoundException in case of unknown option + */ + public function getOption($name = null) + { + if (null === $name) { + return $this->options; + } elseif (!array_key_exists($name, $this->options)) { + throw new HTML_QuickForm2_NotFoundException( + "Unknown option '{$name}'" + ); + } + return $this->options[$name]; + } + + /** + * Returns the javascript builder object + * + * @return HTML_QuickForm2_JavascriptBuilder + */ + public function getJavascriptBuilder() + { + if (empty($this->jsBuilder)) { + HTML_QuickForm2_Loader::loadClass('HTML_QuickForm2_JavascriptBuilder'); + $this->jsBuilder = new HTML_QuickForm2_JavascriptBuilder(); + } + return $this->jsBuilder; + } + + /** + * Sets the javascript builder object + * + * You may want to reuse the same builder object if outputting several + * forms on one page. + * + * @param HTML_QuickForm2_JavascriptBuilder + * @return HTML_QuickForm2_Renderer + */ + public function setJavascriptBuilder(HTML_QuickForm2_JavascriptBuilder $builder = null) + { + $this->jsBuilder = $builder; + return $this; + } + + /** + * Renders a generic element + * + * @param HTML_QuickForm2_Node Element being rendered + */ + abstract public function renderElement(HTML_QuickForm2_Node $element); + + /** + * Renders a hidden element + * + * @param HTML_QuickForm2_Node Hidden element being rendered + */ + abstract public function renderHidden(HTML_QuickForm2_Node $element); + + /** + * Starts rendering a form, called before processing contained elements + * + * @param HTML_QuickForm2_Node Form being rendered + */ + abstract public function startForm(HTML_QuickForm2_Node $form); + + /** + * Finishes rendering a form, called after processing contained elements + * + * @param HTML_QuickForm2_Node Form being rendered + */ + abstract public function finishForm(HTML_QuickForm2_Node $form); + + /** + * Starts rendering a generic container, called before processing contained elements + * + * @param HTML_QuickForm2_Node Container being rendered + */ + abstract public function startContainer(HTML_QuickForm2_Node $container); + + /** + * Finishes rendering a generic container, called after processing contained elements + * + * @param HTML_QuickForm2_Node Container being rendered + */ + abstract public function finishContainer(HTML_QuickForm2_Node $container); + + /** + * Starts rendering a group, called before processing grouped elements + * + * @param HTML_QuickForm2_Node Group being rendered + */ + abstract public function startGroup(HTML_QuickForm2_Node $group); + + /** + * Finishes rendering a group, called after processing grouped elements + * + * @param HTML_QuickForm2_Node Group being rendered + */ + abstract public function finishGroup(HTML_QuickForm2_Node $group); +} +?> diff --git a/libs/HTML/QuickForm2/Renderer/Array.php b/libs/HTML/QuickForm2/Renderer/Array.php new file mode 100644 index 0000000000..57f1dd7000 --- /dev/null +++ b/libs/HTML/QuickForm2/Renderer/Array.php @@ -0,0 +1,376 @@ +<?php +/** + * A renderer for HTML_QuickForm2 building an array of form elements + * + * PHP version 5 + * + * LICENSE: + * + * Copyright (c) 2006-2010, Alexey Borzov <avb@php.net>, + * Bertrand Mansion <golgote@mamasam.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * The names of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @author Thomas Schulz <ths@4bconsult.de> + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version SVN: $Id: Array.php 294052 2010-01-26 20:00:22Z avb $ + * @link http://pear.php.net/package/HTML_QuickForm2 + */ + +/** + * Abstract base class for QuickForm2 renderers + */ +require_once 'HTML/QuickForm2/Renderer.php'; + +/** + * A renderer for HTML_QuickForm2 building an array of form elements + * + * Based on Array renderer from HTML_QuickForm 3.x package + * + * The form array structure is the following: + * <pre> + * array( + * 'id' => form's "id" attribute (string), + * 'frozen' => whether the form is frozen (bool), + * 'attributes' => attributes for <form> tag (string), + * // if form contains required elements: + * 'required_note' => note about the required elements (string), + * // if 'group_hiddens' option is true: + * 'hidden' => array with html of hidden elements (array), + * // if 'group_errors' option is true: + * 'errors' => array( + * '1st element id' => 'Error for the 1st element', + * ... + * 'nth element id' => 'Error for the nth element' + * ), + * 'elements' => array( + * element_1, + * ... + * element_N + * ) + * ); + * </pre> + * Where element_i is an array of the form + * <pre> + * array( + * 'id' => element id (string), + * 'type' => type of the element (string), + * 'frozen' => whether element is frozen (bool), + * // if element has a label: + * 'label' => 'label for the element', + * // note that if 'static_labels' option is true and element's label is an + * // array then there will be several 'label_*' keys corresponding to + * // labels' array keys + * 'required' => whether element is required (bool), + * // if a validation error is present and 'group_errors' option is false: + * 'error' => error associated with the element (string), + * // if some style was associated with an element: + * 'style' => 'some information about element style (e.g. for Smarty)', + * + * // if element is not a Container + * 'value' => element value (mixed), + * 'html' => HTML for the element (string), + * + * // if element is a Container + * 'attributes' => container attributes (string) + * // only for groups, if separator is set: + * 'separator' => separator for group elements (mixed), + * 'elements' => array( + * element_1, + * ... + * element_N + * ) + * ); + * </pre> + * + * While almost everything in this class is defined as public, its properties + * and those methods that are not published (i.e. not in array returned by + * exportMethods()) will be available to renderer plugins only. + * + * The following methods are published: + * - {@link reset()} + * - {@link toArray()} + * - {@link setStyleForId()} + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @author Thomas Schulz <ths@4bconsult.de> + * @version Release: @package_version@ + */ +class HTML_QuickForm2_Renderer_Array extends HTML_QuickForm2_Renderer +{ + /** + * An array being generated + * @var array + */ + public $array = array(); + + /** + * Array with references to 'elements' fields of currently processed containers + * @var unknown_type + */ + public $containers = array(); + + /** + * Whether the form contains required elements + * @var bool + */ + public $hasRequired = false; + + /** + * Additional style information for elements + * @var array + */ + public $styles = array(); + + /** + * Constructor, adds a new 'static_labels' option + */ + protected function __construct() + { + $this->options['static_labels'] = false; + } + + protected function exportMethods() + { + return array( + 'reset', + 'toArray', + 'setStyleForId' + ); + } + + /** + * Resets the accumulated data + * + * This method is called automatically by startForm() method, but should + * be called manually before calling other rendering methods separately. + * + * @return HTML_QuickForm2_Renderer_Array + */ + public function reset() + { + $this->array = array(); + $this->containers = array(); + $this->hasRequired = false; + + return $this; + } + + /** + * Returns the resultant array + * + * @return array + */ + public function toArray() + { + return $this->array; + } + + /** + * Creates an array with fields that are common to all elements + * + * @param HTML_QuickForm2_Node Element being rendered + * @return array + */ + public function buildCommonFields(HTML_QuickForm2_Node $element) + { + $ary = array( + 'id' => $element->getId(), + 'frozen' => $element->toggleFrozen() + ); + if ($labels = $element->getLabel()) { + if (!is_array($labels) || !$this->options['static_labels']) { + $ary['label'] = $labels; + } else { + foreach ($labels as $key => $label) { + $key = is_int($key)? $key + 1: $key; + if (1 === $key) { + $ary['label'] = $label; + } else { + $ary['label_' . $key] = $label; + } + } + } + } + if (($error = $element->getError()) && $this->options['group_errors']) { + $this->array['errors'][$ary['id']] = $error; + } elseif ($error) { + $ary['error'] = $error; + } + if (isset($this->styles[$ary['id']])) { + $ary['style'] = $this->styles[$ary['id']]; + } + if (!$element instanceof HTML_QuickForm2_Container) { + $ary['html'] = $element->__toString(); + } else { + $ary['elements'] = array(); + $ary['attributes'] = $element->getAttributes(true); + } + return $ary; + } + + /** + * Stores an array representing "scalar" element in the form array + * + * @param array + */ + public function pushScalar(array $element) + { + if (!empty($element['required'])) { + $this->hasRequired = true; + } + if (empty($this->containers)) { + $this->array += $element; + } else { + $this->containers[count($this->containers) - 1][] = $element; + } + } + + /** + * Stores an array representing a Container in the form array + * + * @param array + */ + public function pushContainer(array $container) + { + if (!empty($container['required'])) { + $this->hasRequired = true; + } + if (empty($this->containers)) { + $this->array += $container; + $this->containers = array(&$this->array['elements']); + } else { + $cntIndex = count($this->containers) - 1; + $myIndex = count($this->containers[$cntIndex]); + $this->containers[$cntIndex][$myIndex] = $container; + $this->containers[$cntIndex + 1] =& $this->containers[$cntIndex][$myIndex]['elements']; + } + } + + /** + * Sets a style for element rendering + * + * "Style" is some information that is opaque to Array Renderer but may be + * of use to e.g. template engine that receives the resultant array. + * + * @param string|array Element id or array ('element id' => 'style') + * @param sting Element style if $idOrStyles is not an array + * @return HTML_QuickForm2_Renderer_Array + */ + public function setStyleForId($idOrStyles, $style = null) + { + if (is_array($idOrStyles)) { + $this->styles = array_merge($this->styles, $idOrStyles); + } else { + $this->styles[$idOrStyles] = $style; + } + return $this; + } + + /**#@+ + * Implementations of abstract methods from {@link HTML_QuickForm2_Renderer} + */ + public function renderElement(HTML_QuickForm2_Node $element) + { + $ary = $this->buildCommonFields($element) + array( + 'value' => $element->getValue(), + 'type' => $element->getType(), + 'required' => $element->isRequired(), + ); + $this->pushScalar($ary); + } + + public function renderHidden(HTML_QuickForm2_Node $element) + { + if ($this->options['group_hiddens']) { + $this->array['hidden'][] = $element->__toString(); + } else { + $this->renderElement($element); + } + } + + public function startForm(HTML_QuickForm2_Node $form) + { + $this->reset(); + + $this->array = $this->buildCommonFields($form); + if ($this->options['group_errors']) { + $this->array['errors'] = array(); + } + if ($this->options['group_hiddens']) { + $this->array['hidden'] = array(); + } + $this->containers = array(&$this->array['elements']); + } + + public function finishForm(HTML_QuickForm2_Node $form) + { + $this->finishContainer($form); + if ($this->hasRequired) { + $this->array['required_note'] = $this->options['required_note']; + } + } + + public function startContainer(HTML_QuickForm2_Node $container) + { + $ary = $this->buildCommonFields($container) + array( + 'required' => $container->isRequired(), + 'type' => $container->getType() + ); + $this->pushContainer($ary); + } + + public function finishContainer(HTML_QuickForm2_Node $container) + { + array_pop($this->containers); + } + + public function startGroup(HTML_QuickForm2_Node $group) + { + $ary = $this->buildCommonFields($group) + array( + 'required' => $group->isRequired(), + 'type' => $group->getType() + ); + if ($separator = $group->getSeparator()) { + $ary['separator'] = $separator; + } + $this->pushContainer($ary); + } + + public function finishGroup(HTML_QuickForm2_Node $group) + { + $this->finishContainer($group); + } + /**#@-*/ +} +?> diff --git a/libs/HTML/QuickForm2/Renderer/Default.php b/libs/HTML/QuickForm2/Renderer/Default.php new file mode 100644 index 0000000000..a58f011fbe --- /dev/null +++ b/libs/HTML/QuickForm2/Renderer/Default.php @@ -0,0 +1,598 @@ +<?php +/** + * Default renderer for HTML_QuickForm2 + * + * PHP version 5 + * + * LICENSE: + * + * Copyright (c) 2006-2010, Alexey Borzov <avb@php.net>, + * Bertrand Mansion <golgote@mamasam.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * The names of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version SVN: $Id: Default.php 299706 2010-05-24 18:32:37Z avb $ + * @link http://pear.php.net/package/HTML_QuickForm2 + */ + +/** + * Abstract base class for QuickForm2 renderers + */ +require_once 'HTML/QuickForm2/Renderer.php'; + +/** + * Default renderer for QuickForm2 + * + * Mostly a direct port of Default renderer from QuickForm 3.x package. + * + * While almost everything in this class is defined as public, its properties + * and those methods that are not published (i.e. not in array returned by + * exportMethods()) will be available to renderer plugins only. + * + * The following methods are published: + * - {@link reset()} + * - {@link setTemplateForClass()} + * - {@link setTemplateForId()} + * - {@link setErrorTemplate()} + * - {@link setElementTemplateForGroupClass()} + * - {@link setElementTemplateForGroupId()} + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @version Release: @package_version@ + */ +class HTML_QuickForm2_Renderer_Default extends HTML_QuickForm2_Renderer +{ + /** + * Whether the form contains required elements + * @var bool + */ + public $hasRequired = false; + + /** + * HTML generated for the form + * @var array + */ + public $html = array(array()); + + /** + * HTML for hidden elements if 'group_hiddens' option is on + * @var string + */ + public $hiddenHtml = ''; + + /** + * Array of validation errors if 'group_errors' option is on + * @var array + */ + public $errors = array(); + + /** + * Default templates for elements of the given class + * @var array + */ + public $templatesForClass = array( + 'html_quickform2_element_inputhidden' => '<div style="display: none;">{element}</div>', + 'html_quickform2' => '<div class="quickform">{errors}<form{attributes}>{hidden}{content}</form><qf:reqnote><div class="reqnote">{reqnote}</div></qf:reqnote></div>', + 'html_quickform2_container_fieldset' => '<fieldset{attributes}><qf:label><legend id="{id}-legend">{label}</legend></qf:label>{content}</fieldset>', + 'special:error' => array( + 'prefix' => '<div class="errors"><qf:message><p>{message}</p></qf:message><ul><li>', + 'separator' => '</li><li>', + 'suffix' => '</li></ul><qf:message><p>{message}</p></qf:message></div>' + ), + 'html_quickform2_element' => '<div class="row"><label for="{id}" class="element"><qf:required><span class="required">* </span></qf:required>{label}</label><div class="element<qf:error> error</qf:error>"><qf:error><span class="error">{error}</span><br /></qf:error>{element}</div></div>', + 'html_quickform2_container_group' => '<div class="row"><label class="element"><qf:required><span class="required">* </span></qf:required>{label}</label><div class="element group<qf:error> error</qf:error>"><qf:error><span class="error">{error}</span><br /></qf:error>{content}</div></div>' + ); + + /** + * Custom templates for elements with the given IDs + * @var array + */ + public $templatesForId = array(); + + /** + * Default templates for elements in groups of the given classes + * + * Array has the form ('group class' => ('element class' => 'template', ...), ...) + * + * @var array + */ + public $elementTemplatesForGroupClass = array( + 'html_quickform2_container' => array( + 'html_quickform2_element' => '{element}', + 'html_quickform2_container_fieldset' => '<fieldset{attributes}><qf:label><legend id="{id}-legend">{label}</legend></qf:label>{content}</fieldset>' + ) + ); + + /** + * Custom templates for grouped elements in the given group IDs + * + * Array has the form ('group id' => ('element class' => 'template', ...), ...) + * + * @var array + */ + public $elementTemplatesForGroupId = array(); + + /** + * Array containing IDs of the groups being rendered + * @var array + */ + public $groupId = array(); + + protected function exportMethods() + { + return array( + 'reset', + 'setTemplateForClass', + 'setTemplateForId', + 'setErrorTemplate', + 'setGroupedTemplateForClass', + 'setElementTemplateForGroupClass', + 'setElementTemplateForGroupId' + ); + } + + /** + * Sets template for form elements that are instances of the given class + * + * When searching for a template to use, renderer will check for templates + * set for element's class and its parent classes, until found. Thus a more + * specific template will override a more generic one. + * + * @param string Class name + * @param mixed Template to use for elements of that class + * @return HTML_QuickForm2_Renderer_Default + */ + public function setTemplateForClass($className, $template) + { + $this->templatesForClass[strtolower($className)] = $template; + return $this; + } + + /** + * Sets template for form element with the given id + * + * If a template is set for an element via this method, it will be used. + * In the other case a generic template set by {@link setTemplateForClass()} + * or {@link setGroupedTemplateForClass()} will be used. + * + * @param string Element's id + * @param mixed Template to use for rendering of that element + * @return HTML_QuickForm2_Renderer_Default + */ + public function setTemplateForId($id, $template) + { + $this->templatesForId[$id] = $template; + return $this; + } + + /** + * Sets template for rendering validation errors + * + * This template will be used if 'group_errors' option is set to true. + * The template array should contain 'prefix', 'suffix' and 'separator' + * keys. + * + * @param array Template for validation errors + * @return HTML_QuickForm2_Renderer_Default + */ + public function setErrorTemplate(array $template) + { + return $this->setTemplateForClass('special:error', $template); + } + + /** + * Sets grouped elements templates using group class + * + * Templates set via {@link setTemplateForClass()} will not be used for + * grouped form elements. When searching for a template to use, the renderer + * will first consider template set for a specific group id, then the + * group templates set by group class. + * + * @param string Group class name + * @param string Element class name + * @param mixed Template + * @return HTML_QuickForm2_Renderer_Default + */ + public function setElementTemplateForGroupClass($groupClass, $elementClass, $template) + { + $this->elementTemplatesForGroupClass[strtolower($groupClass)][strtolower($elementClass)] = $template; + return $this; + } + + /** + * Sets grouped elements templates using group id + * + * Templates set via {@link setTemplateForClass()} will not be used for + * grouped form elements. When searching for a template to use, the renderer + * will first consider template set for a specific group id, then the + * group templates set by group class. + * + * @param string Group id + * @param string Element class name + * @param mixed Template + * @return HTML_QuickForm2_Renderer_Default + */ + public function setElementTemplateForGroupId($groupId, $elementClass, $template) + { + $this->elementTemplatesForGroupId[$groupId][strtolower($elementClass)] = $template; + return $this; + } + + /** + * Resets the accumulated data + * + * This method is called automatically by startForm() method, but should + * be called manually before calling other rendering methods separately. + * + * @return HTML_QuickForm2_Renderer_Default + */ + public function reset() + { + $this->html = array(array()); + $this->hiddenHtml = ''; + $this->errors = array(); + $this->hasRequired = false; + $this->groupId = array(); + + return $this; + } + + /** + * Returns generated HTML + * + * @return string + */ + public function __toString() + { + return (isset($this->html[0][0])? $this->html[0][0]: '') . + $this->hiddenHtml; + } + + /** + * Renders a generic element + * + * @param HTML_QuickForm2_Node Element being rendered + */ + public function renderElement(HTML_QuickForm2_Node $element) + { + $elTpl = $this->prepareTemplate($this->findTemplate($element), $element); + $this->html[count($this->html) - 1][] = str_replace(array('{element}', '{id}'), + array($element, $element->getId()), $elTpl); + } + + /** + * Renders a hidden element + * + * @param HTML_QuickForm2_Node Hidden element being rendered + */ + public function renderHidden(HTML_QuickForm2_Node $element) + { + if ($this->options['group_hiddens']) { + $this->hiddenHtml .= $element->__toString(); + } else { + $this->html[count($this->html) - 1][] = str_replace('{element}', $element, + $this->findTemplate($element)); + } + } + + /** + * Starts rendering a generic container, called before processing contained elements + * + * @param HTML_QuickForm2_Node Container being rendered + */ + public function startContainer(HTML_QuickForm2_Node $container) + { + $this->html[] = array(); + $this->groupId[] = false; + } + + /** + * Finishes rendering a generic container, called after processing contained elements + * + * @param HTML_QuickForm2_Node Container being rendered + */ + public function finishContainer(HTML_QuickForm2_Node $container) + { + array_pop($this->groupId); + + $cTpl = str_replace( + array('{attributes}', '{id}'), + array($container->getAttributes(true), $container->getId()), + $this->prepareTemplate($this->findTemplate($container, '{content}'), $container) + ); + $cHtml = array_pop($this->html); + $break = HTML_Common2::getOption('linebreak'); + $indent = str_repeat(HTML_Common2::getOption('indent'), count($this->html)); + $this->html[count($this->html) - 1][] = str_replace( + '{content}', $break . $indent . implode($break . $indent, $cHtml), $cTpl + ); + } + + /** + * Starts rendering a group, called before processing grouped elements + * + * @param HTML_QuickForm2_Node Group being rendered + */ + public function startGroup(HTML_QuickForm2_Node $group) + { + $this->html[] = array(); + $this->groupId[] = $group->getId(); + } + + /** + * Finishes rendering a group, called after processing grouped elements + * + * @param HTML_QuickForm2_Node Group being rendered + */ + public function finishGroup(HTML_QuickForm2_Node $group) + { + $gTpl = str_replace( + array('{attributes}', '{id}'), + array($group->getAttributes(true), array_pop($this->groupId)), + $this->prepareTemplate($this->findTemplate($group, '{content}'), $group) + ); + + $separator = $group->getSeparator(); + $elements = array_pop($this->html); + if (!is_array($separator)) { + $content = implode((string)$separator, $elements); + } else { + $content = ''; + $cSeparator = count($separator); + for ($i = 0, $count = count($elements); $i < $count; $i++) { + $content .= (0 == $i? '': $separator[($i - 1) % $cSeparator]) . + $elements[$i]; + } + } + + $this->html[count($this->html) - 1][] = str_replace('{content}', $content, $gTpl); + } + + /** + * Starts rendering a form, called before processing contained elements + * + * @param HTML_QuickForm2_Node Form being rendered + */ + public function startForm(HTML_QuickForm2_Node $form) + { + $this->reset(); + } + + /** + * Finishes rendering a form, called after processing contained elements + * + * @param HTML_QuickForm2_Node Form being rendered + */ + public function finishForm(HTML_QuickForm2_Node $form) + { + $formTpl = str_replace( + array('{attributes}', '{hidden}', '{errors}'), + array($form->getAttributes(true), $this->hiddenHtml, + $this->outputGroupedErrors()), + $this->findTemplate($form, '{content}') + ); + $this->hiddenHtml = ''; + + // required note + if (!$this->hasRequired || $form->toggleFrozen() || + empty($this->options['required_note'])) + { + $formTpl = preg_replace('!<qf:reqnote>.*</qf:reqnote>!isU', '', $formTpl); + } else { + $formTpl = str_replace( + array('<qf:reqnote>', '</qf:reqnote>', '{reqnote}'), + array('', '', $this->options['required_note']), + $formTpl + ); + } + + $break = HTML_Common2::getOption('linebreak'); + $script = $this->getJavascriptBuilder()->__toString(); + $this->html[0] = array((empty($script)? '': $script . $break) . str_replace( + '{content}', $break . implode($break, $this->html[0]), $formTpl + )); + } + + /** + * Creates a error list if 'group_errors' option is true + * + * @return string HTML with a list of all validation errors + */ + public function outputGroupedErrors() + { + if (empty($this->errors)) { + return ''; + } + if (!empty($this->options['errors_prefix'])) { + $errorHtml = str_replace(array('<qf:message>', '</qf:message>', '{message}'), + array('', '', $this->options['errors_prefix']), + $this->templatesForClass['special:error']['prefix']); + } else { + $errorHtml = preg_replace('!<qf:message>.*</qf:message>!isU', '', + $this->templatesForClass['special:error']['prefix']); + } + $errorHtml .= implode($this->templatesForClass['special:error']['separator'], $this->errors); + if (!empty($this->options['errors_suffix'])) { + $errorHtml .= str_replace(array('<qf:message>', '</qf:message>', '{message}'), + array('', '', $this->options['errors_suffix']), + $this->templatesForClass['special:error']['suffix']); + } else { + $errorHtml .= preg_replace('!<qf:message>.*</qf:message>!isU', '', + $this->templatesForClass['special:error']['suffix']); + } + return $errorHtml; + } + + /** + * Finds a proper template for the element + * + * Templates are scanned in a predefined order. First, if a template was + * set for a specific element by id, it is returned, no matter if the + * element belongs to a group. If the element does not belong to a group, + * we try to match a template using the element class. + * But, if the element belongs to a group, templates are first looked up + * using the containing group id, then using the containing group class. + * When no template is found, the provided default template is returned. + * + * @param HTML_QuickForm2_Node Element being rendered + * @param string Default template to use if not found + * @return string Template + */ + public function findTemplate(HTML_QuickForm2_Node $element, $default = '{element}') + { + if (!empty($this->templatesForId[$element->getId()])) { + return $this->templatesForId[$element->getId()]; + } + $class = strtolower(get_class($element)); + $groupId = end($this->groupId); + $elementClasses = array(); + do { + if (empty($groupId) && !empty($this->templatesForClass[$class])) { + return $this->templatesForClass[$class]; + } + $elementClasses[$class] = true; + } while ($class = strtolower(get_parent_class($class))); + + if (!empty($groupId)) { + if (!empty($this->elementTemplatesForGroupId[$groupId])) { + while (list($elClass) = each($elementClasses)) { + if (!empty($this->elementTemplatesForGroupId[$groupId][$elClass])) { + return $this->elementTemplatesForGroupId[$groupId][$elClass]; + } + } + } + + $group = $element->getContainer(); + $grClass = strtolower(get_class($group)); + do { + if (!empty($this->elementTemplatesForGroupClass[$grClass])) { + reset($elementClasses); + while (list($elClass) = each($elementClasses)) { + if (!empty($this->elementTemplatesForGroupClass[$grClass][$elClass])) { + return $this->elementTemplatesForGroupClass[$grClass][$elClass]; + } + } + } + } while ($grClass = strtolower(get_parent_class($grClass))); + } + return $default; + } + + /** + * Processes the element's template, adding label(s), required note and error message + * + * @param string Element template + * @param HTML_QuickForm2_Node Element being rendered + * @return string Template with some substitutions done + */ + public function prepareTemplate($elTpl, HTML_QuickForm2_Node $element) + { + // if element is required + $elTpl = $this->markRequired($elTpl, $element->isRequired()); + $elTpl = $this->outputError($elTpl, $element->getError()); + return $this->outputLabel($elTpl, $element->getLabel()); + } + + /** + * Marks element required or removes "required" block + * + * @param string Element template + * @param bool Whether element is required + * @return string Template with processed "required" block + */ + public function markRequired($elTpl, $required) + { + if ($required) { + $this->hasRequired = true; + $elTpl = str_replace(array('<qf:required>', '</qf:required>'), + array('', ''), $elTpl); + } else { + $elTpl = preg_replace('!<qf:required>.*</qf:required>!isU', '', $elTpl); + } + return $elTpl; + } + + /** + * Outputs element error, removes empty error blocks + * + * @param string Element template + * @param string Validation error for the element + * @return string Template with error substitutions done + */ + public function outputError($elTpl, $error) + { + if ($error && !$this->options['group_errors']) { + $elTpl = str_replace(array('<qf:error>', '</qf:error>', '{error}'), + array('', '', $error), $elTpl); + } else { + if ($error && $this->options['group_errors']) { + $this->errors[] = $error; + } + $elTpl = preg_replace('!<qf:error>.*</qf:error>!isU', '', $elTpl); + } + return $elTpl; + } + + /** + * Outputs element's label(s), removes empty label blocks + * + * @param string Element template + * @param mixed Element label(s) + * @return string Template with label substitutions done + */ + public function outputLabel($elTpl, $label) + { + $mainLabel = is_array($label)? array_shift($label): $label; + $elTpl = str_replace('{label}', $mainLabel, $elTpl); + if (false !== strpos($elTpl, '<qf:label>')) { + if ($mainLabel) { + $elTpl = str_replace(array('<qf:label>', '</qf:label>'), array('', ''), $elTpl); + } else { + $elTpl = preg_replace('!<qf:label>.*</qf:label>!isU', '', $elTpl); + } + } + if (is_array($label)) { + foreach($label as $key => $text) { + $key = is_int($key)? $key + 2: $key; + $elTpl = str_replace(array('<qf:label_' . $key . '>', '</qf:label_' . $key . '>', '{label_' . $key . '}'), + array('', '', $text), $elTpl); + } + } + if (strpos($elTpl, '{label_')) { + $elTpl = preg_replace('!<qf:label_([^>]+)>.*</qf:label_\1>!isU', '', $elTpl); + } + return $elTpl; + } +} +?>
\ No newline at end of file diff --git a/libs/HTML/QuickForm2/Renderer/Plugin.php b/libs/HTML/QuickForm2/Renderer/Plugin.php new file mode 100644 index 0000000000..eb0aa9114e --- /dev/null +++ b/libs/HTML/QuickForm2/Renderer/Plugin.php @@ -0,0 +1,69 @@ +<?php +/** + * Abstract base class for HTML_QuickForm2_Renderer plugin classes + * + * PHP version 5 + * + * LICENSE: + * + * Copyright (c) 2006-2010, Alexey Borzov <avb@php.net>, + * Bertrand Mansion <golgote@mamasam.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * The names of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version SVN: $Id: Plugin.php 294057 2010-01-26 21:10:28Z avb $ + * @link http://pear.php.net/package/HTML_QuickForm2 + */ + +/** + * Abstract base class for HTML_QuickForm2_Renderer plugin classes + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @version Release: @package_version@ + */ +abstract class HTML_QuickForm2_Renderer_Plugin +{ + protected $renderer; + + /** + * Sets the base renderer this plugin is enhancing + * + * @param HTML_QuickForm2_Renderer base renderer + */ + public function setRenderer(HTML_QuickForm2_Renderer $renderer) + { + $this->renderer = $renderer; + } +} +?> diff --git a/libs/HTML/QuickForm2/Renderer/Proxy.php b/libs/HTML/QuickForm2/Renderer/Proxy.php new file mode 100644 index 0000000000..5b424ea1c0 --- /dev/null +++ b/libs/HTML/QuickForm2/Renderer/Proxy.php @@ -0,0 +1,262 @@ +<?php +/** + * Proxy class for HTML_QuickForm2 renderers and their plugins + * + * PHP version 5 + * + * LICENSE: + * + * Copyright (c) 2006-2010, Alexey Borzov <avb@php.net>, + * Bertrand Mansion <golgote@mamasam.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * The names of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version SVN: $Id: Proxy.php 299706 2010-05-24 18:32:37Z avb $ + * @link http://pear.php.net/package/HTML_QuickForm2 + */ + +/** + * Abstract base class for QuickForm2 renderers + */ +require_once 'HTML/QuickForm2/Renderer.php'; + +/** + * Proxy class for HTML_QuickForm2 renderers and their plugins + * + * This class serves two purposes: + * <ol> + * <li>Aggregates renderer and its plugins. From user's point of view + * renderer plugins simply add new methods to renderer instances.</li> + * <li>Restricts access to renderer properties and methods. Those are defined + * as 'public' to allow easy access from plugins, but only methods + * with names explicitly returned by Renderer::exportMethods() are + * available to the outside world.</li> + * </ol> + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @version Release: @package_version@ + */ +class HTML_QuickForm2_Renderer_Proxy extends HTML_QuickForm2_Renderer +{ + /** + * Renderer instance + * @var HTML_QuickForm2_Renderer + */ + private $_renderer; + + /** + * Additional renderer methods to proxy via __call(), as returned by exportMethods() + * @var array + */ + private $_rendererMethods = array(); + + /** + * Reference to a list of registered renderer plugins for that renderer type + * @var array + */ + private $_pluginClasses; + + /** + * Plugins for this renderer + * @var array + */ + private $_plugins = array(); + + /** + * Plugin methods to call via __call() magic method + * + * Array has the form ('lowercase method name' => 'index in _plugins array') + * + * @var array + */ + private $_pluginMethods = array(); + + /** + * Constructor, sets proxied renderer and its plugins + * + * @param HTML_QuickForm2_Renderer Renderer instance to proxy + * @param array Plugins registered for that renderer type + */ + protected function __construct(HTML_QuickForm2_Renderer $renderer, array &$pluginClasses) + { + foreach ($renderer->exportMethods() as $method) { + $this->_rendererMethods[strtolower($method)] = true; + } + $this->_renderer = $renderer; + $this->_pluginClasses = &$pluginClasses; + } + + /** + * Magic function; call an imported method of a renderer or its plugin + * + * @param string method name + * @param array method arguments + * @return mixed + */ + public function __call($name, $arguments) + { + $lower = strtolower($name); + if (isset($this->_rendererMethods[$lower])) { + // support fluent interfaces + $ret = call_user_func_array(array($this->_renderer, $name), $arguments); + return $ret === $this->_renderer? $this: $ret; + } + // any additional plugins since last __call()? + for ($i = count($this->_plugins); $i < count($this->_pluginClasses); $i++) { + list($className, $includeFile) = $this->_pluginClasses[$i]; + HTML_QuickForm2_Loader::loadClass($className, $includeFile); + $this->addPlugin($i, new $className); + } + if (isset($this->_pluginMethods[$lower])) { + return call_user_func_array( + array($this->_plugins[$this->_pluginMethods[$lower]], $name), + $arguments + ); + } + trigger_error("Fatal error: Call to undefined method " . + get_class($this->_renderer) . "::" . $name . "()", E_USER_ERROR); + } + + /** + * Adds a plugin for the current renderer instance + * + * Plugin's methods are imported and can be later called as this object's own + * + * @param HTML_QuickForm2_Renderer_Plugin a plugin instance + * @throws HTML_QuickForm2_InvalidArgumentException if a plugin has already + * imported name + */ + protected function addPlugin($index, HTML_QuickForm2_Renderer_Plugin $plugin) + { + $methods = array(); + $reflection = new ReflectionObject($plugin); + foreach ($reflection->getMethods(ReflectionMethod::IS_PUBLIC) as $method) { + $lower = strtolower($method->getName()); + if ('HTML_QuickForm2_Renderer_Plugin' == $method->getDeclaringClass()->getName()) { + continue; + } elseif (isset($this->_rendererMethods[$lower]) + || isset($this->_pluginMethods[$lower]) + ) { + throw new HTML_QuickForm2_InvalidArgumentException( + 'Duplicate method name: name ' . $method->getName() . ' in plugin ' . + get_class($plugin) . ' already taken by ' . + (isset($this->_rendererMethods[$lower])? + get_class($this->_renderer): + get_class($this->_plugins[$this->_pluginMethods[$lower]]) + ) + ); + } + $methods[$lower] = $index; + } + $plugin->setRenderer($this->_renderer); + $this->_plugins[$index] = $plugin; + $this->_pluginMethods += $methods; + } + + /**#@+ + * Proxies for methods defined in {@link HTML_QuickForm2_Renderer} + */ + public function setOption($nameOrOptions, $value = null) + { + $this->_renderer->setOption($nameOrOptions, $value); + return $this; + } + + public function getOption($name = null) + { + return $this->_renderer->getOption($name); + } + + public function getJavascriptBuilder() + { + return $this->_renderer->getJavascriptBuilder(); + } + + public function setJavascriptBuilder(HTML_QuickForm2_JavascriptBuilder $builder = null) + { + $this->_renderer->setJavascriptBuilder($builder); + return $this; + } + + public function renderElement(HTML_QuickForm2_Node $element) + { + $this->_renderer->renderElement($element); + } + + public function renderHidden(HTML_QuickForm2_Node $element) + { + $this->_renderer->renderHidden($element); + } + + public function startForm(HTML_QuickForm2_Node $form) + { + $this->_renderer->startForm($form); + } + + public function finishForm(HTML_QuickForm2_Node $form) + { + $this->_renderer->finishForm($form); + } + + public function startContainer(HTML_QuickForm2_Node $container) + { + $this->_renderer->startContainer($container); + } + + public function finishContainer(HTML_QuickForm2_Node $container) + { + $this->_renderer->finishContainer($container); + } + + public function startGroup(HTML_QuickForm2_Node $group) + { + $this->_renderer->startGroup($group); + } + + public function finishGroup(HTML_QuickForm2_Node $group) + { + $this->_renderer->finishGroup($group); + } + /**#@-*/ + + public function __toString() + { + if (method_exists($this->_renderer, '__toString')) { + return $this->_renderer->__toString(); + } + trigger_error("Fatal error: Object of class " . get_class($this->_renderer) . + " could not be converted to string", E_USER_ERROR); + } +} +?>
\ No newline at end of file diff --git a/libs/HTML/QuickForm2/Rule.php b/libs/HTML/QuickForm2/Rule.php new file mode 100644 index 0000000000..dfb11868b0 --- /dev/null +++ b/libs/HTML/QuickForm2/Rule.php @@ -0,0 +1,333 @@ +<?php +/** + * Base class for HTML_QuickForm2 rules + * + * PHP version 5 + * + * LICENSE: + * + * Copyright (c) 2006-2010, Alexey Borzov <avb@php.net>, + * Bertrand Mansion <golgote@mamasam.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * The names of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version SVN: $Id: Rule.php 299706 2010-05-24 18:32:37Z avb $ + * @link http://pear.php.net/package/HTML_QuickForm2 + */ + +/** + * Abstract base class for HTML_QuickForm2 rules + * + * This class provides methods that allow chaining several rules together. + * Its validate() method executes the whole rule chain starting from this rule. + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @version Release: @package_version@ + */ +abstract class HTML_QuickForm2_Rule +{ + /** + * Constant showing that validation should be run server-side + * @see HTML_QuickForm2_Node::addRule() + */ + const RUNAT_SERVER = 1; + + /** + * Constant showing that validation should be run client-side + * @see HTML_QuickForm2_Node::addRule() + */ + const RUNAT_CLIENT = 2; + + /** + * An element whose value will be validated by this rule + * @var HTML_QuickForm2_Node + */ + protected $owner; + + /** + * An error message to display if validation fails + * @var string + */ + protected $message; + + /** + * Configuration data for the rule + * @var mixed + */ + protected $config; + + /** + * Rules chained to this via "and" and "or" operators + * + * The contents can be described as "disjunctive normal form", where an outer + * array represents a disjunction of conjunctive clauses represented by inner + * arrays. + * + * @var array + */ + protected $chainedRules = array(array()); + + + /** + * Class constructor + * + * @param HTML_QuickForm2_Node Element to validate + * @param string Error message to display if validation fails + * @param mixed Configuration data for the rule + */ + public function __construct(HTML_QuickForm2_Node $owner, $message = '', $config = null) + { + $this->setOwner($owner); + $this->setMessage($message); + $this->setConfig($config); + } + + /** + * Merges local configuration with that provided for registerRule() + * + * Default behaviour is for global config to override local one, different + * Rules may implement more complex merging behaviours. + * + * @param mixed Local configuration + * @param mixed Global configuration, usually provided to {@link HTML_QuickForm2_Factory::registerRule()} + * @return mixed Merged configuration + */ + public static function mergeConfig($localConfig, $globalConfig) + { + return is_null($globalConfig)? $localConfig: $globalConfig; + } + + /** + * Sets configuration data for the rule + * + * @param mixed Rule configuration data (specific for a Rule) + * @return HTML_QuickForm2_Rule + * @throws HTML_QuickForm2_InvalidArgumentException in case of invalid + * configuration data + */ + public function setConfig($config) + { + $this->config = $config; + return $this; + } + + /** + * Returns the rule's configuration data + * + * @return mixed Configuration data (specific for a Rule) + */ + public function getConfig() + { + return $this->config; + } + + /** + * Sets the error message output by the rule + * + * @param string Error message to display if validation fails + * @return HTML_QuickForm2_Rule + */ + public function setMessage($message) + { + $this->message = (string)$message; + return $this; + } + + /** + * Returns the error message output by the rule + * + * @return string Error message + */ + public function getMessage() + { + return $this->message; + } + + /** + * Sets the element that will be validated by this rule + * + * @param HTML_QuickForm2_Node Element to validate + */ + public function setOwner(HTML_QuickForm2_Node $owner) + { + if (null !== $this->owner) { + $this->owner->removeRule($this); + } + $this->owner = $owner; + } + + /** + * Adds a rule to the chain with an "and" operator + * + * Evaluation is short-circuited, next rule will not be evaluated if the + * previous one returns false. The method is named this way because "and" is + * a reserved word in PHP. + * + * @param HTML_QuickForm2_Rule + * @return HTML_QuickForm2_Rule first rule in the chain (i.e. $this) + * @throws HTML_QuickForm2_InvalidArgumentException when trying to add + * a "required" rule to the chain + */ + public function and_(HTML_QuickForm2_Rule $next) + { + if ($next instanceof HTML_QuickForm2_Rule_Required) { + throw new HTML_QuickForm2_InvalidArgumentException( + 'and_(): Cannot add a "required" rule' + ); + } + $this->chainedRules[count($this->chainedRules) - 1][] = $next; + return $this; + } + + /** + * Adds a rule to the chain with an "or" operator + * + * Evaluation is short-circuited, next rule will not be evaluated if the + * previous one returns true. The method is named this way because "or" is + * a reserved word in PHP. + * + * @param HTML_QuickForm2_Rule + * @return HTML_QuickForm2_Rule first rule in the chain (i.e. $this) + * @throws HTML_QuickForm2_InvalidArgumentException when trying to add + * a "required" rule to the chain + */ + public function or_(HTML_QuickForm2_Rule $next) + { + if ($next instanceof HTML_QuickForm2_Rule_Required) { + throw new HTML_QuickForm2_InvalidArgumentException( + 'or_(): Cannot add a "required" rule' + ); + } + $this->chainedRules[] = array($next); + return $this; + } + + /** + * Performs validation + * + * The whole rule chain is executed. Note that the side effect of this + * method is setting the error message on element if validation fails + * + * @return boolean Whether the element is valid + */ + public function validate() + { + $globalValid = false; + $localValid = $this->validateOwner(); + foreach ($this->chainedRules as $item) { + foreach ($item as $multiplier) { + if (!($localValid = $localValid && $multiplier->validate())) { + break; + } + } + if ($globalValid = $globalValid || $localValid) { + break; + } + $localValid = true; + } + $globalValid or $this->setOwnerError(); + return $globalValid; + } + + /** + * Validates the owner element + * + * @return bool Whether owner element is valid according to the rule + */ + abstract protected function validateOwner(); + + /** + * Sets the error message on the owner element + */ + protected function setOwnerError() + { + if (strlen($this->getMessage()) && !$this->owner->getError()) { + $this->owner->setError($this->getMessage()); + } + } + + /** + * Returns the client-side validation callback + * + * This essentially builds a Javascript version of validateOwner() method, + * with element ID and Rule configuration hardcoded. + * + * @return string Javascript function to validate the element's value + * @throws HTML_QuickForm2_Exception if Rule can only be run server-side + */ + protected function getJavascriptCallback() + { + throw new HTML_QuickForm2_Exception( + get_class($this) . ' does not implement javascript validation' + ); + } + + /** + * Returns the client-side representation of the Rule + * + * The Javascript object returned contains the following fields: + * - callback: {@see getJavascriptCallback()} + * - elementId: element ID to set error for if validation fails + * - errorMessage: error message to set if validation fails + * - chained: chained rules, array of arrays like in $chainedRules property + * + * @return string + * @throws HTML_QuickForm2_Exception if Rule or its chained Rules can only + * be run server-side + */ + public function getJavascript() + { + $js = "{\n\tcallback: " . $this->getJavascriptCallback() . ",\n" . + "\telementId: '" . $this->owner->getId() . "',\n" . + "\terrorMessage: '" . strtr($this->getMessage(), array( + "\r" => '\r', + "\n" => '\n', + "\t" => '\t', + "'" => "\\'", + '"' => '\"', + '\\' => '\\\\' + )) . "',\n\tchained: ["; + $chained = array(); + foreach ($this->chainedRules as $item) { + $multipliers = array(); + foreach ($item as $multiplier) { + $multipliers[] = $multiplier->getJavascript(); + } + $chained[] = '[' . implode(",\n", $multipliers) . ']'; + } + $js .= implode(",\n", $chained) . "]\n}"; + return $js; + } +} +?> diff --git a/libs/HTML/QuickForm2/Rule/Callback.php b/libs/HTML/QuickForm2/Rule/Callback.php new file mode 100644 index 0000000000..c013d6b033 --- /dev/null +++ b/libs/HTML/QuickForm2/Rule/Callback.php @@ -0,0 +1,172 @@ +<?php +/** + * Rule checking the value via a callback function (method) + * + * PHP version 5 + * + * LICENSE: + * + * Copyright (c) 2006-2010, Alexey Borzov <avb@php.net>, + * Bertrand Mansion <golgote@mamasam.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * The names of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version SVN: $Id: Callback.php 294057 2010-01-26 21:10:28Z avb $ + * @link http://pear.php.net/package/HTML_QuickForm2 + */ + +/** + * Base class for HTML_QuickForm2 rules + */ +require_once 'HTML/QuickForm2/Rule.php'; + +/** + * Rule checking the value via a callback function (method) + * + * The Rule needs a valid callback as a configuration parameter for its work, it + * may also be given additional arguments to pass to the callback alongside the + * element's value. See {@link mergeConfig()} for description of possible ways + * to pass configuration parameters. + * + * The callback will be called with element's value as the first argument, if + * additional arguments were provided they'll be passed as well. It is expected + * to return false if the value is invalid and true if it is valid. + * + * Checking that the value is not empty: + * <code> + * $str->addRule('callback', 'The field should not be empty', 'strlen'); + * </code> + * Checking that the value is in the given array: + * <code> + * $meta->addRule('callback', 'Unknown variable name', + * array('callback' => 'in_array', + * 'arguments' => array(array('foo', 'bar', 'baz')))); + * </code> + * The same, but with rule registering first: + * <code> + * HTML_QuickForm2_Factory::registerRule( + * 'in_array', 'HTML_QuickForm2_Rule_Callback', + * 'HTML/QuickForm2/Rule/Callback.php', 'in_array' + * ); + * $meta->addRule('in_array', 'Unknown variable name', array(array('foo', 'bar', 'baz'))); + * </code> + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @version Release: @package_version@ + */ +class HTML_QuickForm2_Rule_Callback extends HTML_QuickForm2_Rule +{ + /** + * Validates the owner element + * + * @return bool the value returned by a callback function + */ + protected function validateOwner() + { + $value = $this->owner->getValue(); + $config = $this->getConfig(); + return (bool)call_user_func_array( + $config['callback'], array_merge(array($value), $config['arguments']) + ); + } + + /** + * Merges local configuration with that provided for registerRule() + * + * "Global" configuration may be passed to + * {@link HTML_QuickForm2_Factory::registerRule()} in either of the + * following formats + * - callback + * - array(['callback' => callback, ]['arguments' => array(...)]) + * + * "Local" configuration may be passed to the constructor in either of + * the following formats + * - callback or arguments (interpretation depends on whether the global + * configuration already contains the callback) + * - array(['callback' => callback, ]['arguments' => array(...)]) + * + * As usual, global config overrides local one. It is a good idea to use the + * associative array format to prevent ambiguity. + * + * @param mixed Local configuration + * @param mixed Global configuration + * @return mixed Merged configuration + */ + public static function mergeConfig($localConfig, $globalConfig) + { + if (!isset($globalConfig)) { + $config = $localConfig; + + } else { + if (!is_array($globalConfig) || + !isset($globalConfig['callback']) && !isset($globalConfig['arguments']) + ) { + $config = array('callback' => $globalConfig); + } else { + $config = $globalConfig; + } + if (is_array($localConfig) && (isset($localConfig['callback']) + || isset($localConfig['arguments'])) + ) { + $config += $localConfig; + } elseif(isset($localConfig)) { + $config += array('callback' => $localConfig, 'arguments' => $localConfig); + } + } + return $config; + } + + /** + * Sets the callback to use for validation and its additional arguments + * + * @param callback|array Callback or array ('callback' => validation callback, + * 'arguments' => additional arguments) + * @return HTML_QuickForm2_Rule + * @throws HTML_QuickForm2_InvalidArgumentException if callback is missing or invalid + */ + public function setConfig($config) + { + if (!is_array($config) || !isset($config['callback'])) { + $config = array('callback' => $config); + } + if (!is_callable($config['callback'], false, $callbackName)) { + throw new HTML_QuickForm2_InvalidArgumentException( + 'Callback Rule requires a valid callback, \'' . $callbackName . + '\' was given' + ); + } + return parent::setConfig($config + array('arguments' => array())); + } +} +?> diff --git a/libs/HTML/QuickForm2/Rule/Compare.php b/libs/HTML/QuickForm2/Rule/Compare.php new file mode 100644 index 0000000000..b6e83e59df --- /dev/null +++ b/libs/HTML/QuickForm2/Rule/Compare.php @@ -0,0 +1,231 @@ +<?php +/** + * Rule comparing the value of the field with some other value + * + * PHP version 5 + * + * LICENSE: + * + * Copyright (c) 2006-2010, Alexey Borzov <avb@php.net>, + * Bertrand Mansion <golgote@mamasam.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * The names of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version SVN: $Id: Compare.php 299480 2010-05-19 06:55:03Z avb $ + * @link http://pear.php.net/package/HTML_QuickForm2 + */ + +/** + * Base class for HTML_QuickForm2 rules + */ +require_once 'HTML/QuickForm2/Rule.php'; + +/** + * Rule comparing the value of the field with some other value + * + * The Rule needs two configuration parameters for its work + * - comparison operator (defaults to equality) + * - operand to compare with; this can be either a constant or another form + * element (its value will be used) + * See {@link mergeConfig()} for description of possible ways to pass + * configuration parameters. + * + * Note that 'less than [or equal]' and 'greater than [or equal]' operators + * compare the operands numerically, since this is considered as more useful + * approach by the authors. + * + * For convenience, this Rule is already registered in the Factory with the + * names 'eq', 'neq', 'lt', 'gt', 'lte', 'gte' corresponding to the relevant + * operators: + * <code> + * $password->addRule('eq', 'Passwords do not match', $passwordRepeat); + * $orderQty->addRule('lte', 'Should not order more than 10 of these', 10); + * </code> + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @version Release: @package_version@ + */ +class HTML_QuickForm2_Rule_Compare extends HTML_QuickForm2_Rule +{ + /** + * Possible comparison operators + * @var array + */ + protected $operators = array('==', '!=', '===', '!==', '<', '<=', '>', '>='); + + + /** + * Validates the owner element + * + * @return bool whether (element_value operator operand) expression is true + */ + protected function validateOwner() + { + $value = $this->owner->getValue(); + $config = $this->getConfig(); + if (!in_array($config['operator'], array('===', '!=='))) { + $compareFn = create_function( + '$a, $b', 'return floatval($a) ' . $config['operator'] . ' floatval($b);' + ); + } else { + $compareFn = create_function( + '$a, $b', 'return strval($a) ' . $config['operator'] . ' strval($b);' + ); + } + return $compareFn($value, $config['operand'] instanceof HTML_QuickForm2_Node + ? $config['operand']->getValue(): $config['operand']); + } + + protected function getJavascriptCallback() + { + $config = $this->getConfig(); + $operand1 = $this->owner->getJavascriptValue(); + $operand2 = $config['operand'] instanceof HTML_QuickForm2_Node + ? $config['operand']->getJavascriptValue() + : "'" . strtr($config['operand'], array( + "\r" => '\r', + "\n" => '\n', + "\t" => '\t', + "'" => "\\'", + '"' => '\"', + '\\' => '\\\\' + )) . "'"; + + if (!in_array($config['operator'], array('===', '!=='))) { + $check = "Number({$operand1}) {$config['operator']} Number({$operand2})"; + } else { + $check = "String({$operand1}) {$config['operator']} String({$operand2})"; + } + + return "function () { return {$check}; }"; + } + + /** + * Merges local configuration with that provided for registerRule() + * + * "Global" configuration may be passed to + * {@link HTML_QuickForm2_Factory::registerRule()} in + * either of the following formats + * - operator + * - array(operator[, operand]) + * - array(['operator' => operator, ]['operand' => operand]) + + * "Local" configuration may be passed to the constructor in either of + * the following formats + * - operand + * - array([operator, ]operand) + * - array(['operator' => operator, ]['operand' => operand]) + * + * As usual, global configuration overrides local one. + * + * @param mixed Local configuration + * @param mixed Global configuration + * @return mixed Merged configuration + */ + public static function mergeConfig($localConfig, $globalConfig) + { + $config = null; + if (0 < count($globalConfig)) { + $config = self::toCanonicalForm($globalConfig, 'operator'); + } + if (0 < count($localConfig)) { + $config = (isset($config)? $config: array()) + + self::toCanonicalForm($localConfig); + } + return $config; + } + + /** + * Converts configuration data to a canonical associative array form + * + * @param mixed Configuration data + * @param string Array key to assign $config to if it is scalar + * @return array Associative array that may contain 'operand' and 'operator' keys + */ + protected static function toCanonicalForm($config, $key = 'operand') + { + if (!is_array($config)) { + return array($key => $config); + + } elseif (array_key_exists('operator', $config) + || array_key_exists('operand', $config) + ) { + return $config; + + } elseif (1 == count($config)) { + return array($key => end($config)); + + } else { + return array('operator' => reset($config), 'operand' => end($config)); + } + } + + /** + * Sets the comparison operator and operand to compare to + * + * $config can be either of the following + * - operand + * - array([operator, ]operand) + * - array(['operator' => operator, ]['operand' => operand]) + * If operator is missing it will default to '===' + * + * @param mixed Configuration data + * @return HTML_QuickForm2_Rule + * @throws HTML_QuickForm2_InvalidArgumentException if a bogus comparison + * operator is used for configuration, if an operand is missing + */ + public function setConfig($config) + { + if (0 == count($config)) { + throw new HTML_QuickForm2_InvalidArgumentException( + 'Compare Rule requires an argument to compare with' + ); + } + $config = self::toCanonicalForm($config); + + $config += array('operator' => '==='); + if (!in_array($config['operator'], $this->operators)) { + throw new HTML_QuickForm2_InvalidArgumentException( + 'Compare Rule requires a valid comparison operator, ' . + preg_replace('/\s+/', ' ', var_export($config['operator'], true)) . ' given' + ); + } + if (in_array($config['operator'], array('==', '!='))) { + $config['operator'] .= '='; + } + + return parent::setConfig($config); + } +} +?> diff --git a/libs/HTML/QuickForm2/Rule/Each.php b/libs/HTML/QuickForm2/Rule/Each.php new file mode 100644 index 0000000000..721c87950f --- /dev/null +++ b/libs/HTML/QuickForm2/Rule/Each.php @@ -0,0 +1,137 @@ +<?php +/** + * Validates all elements in a Container using a template Rule + * + * PHP version 5 + * + * LICENSE: + * + * Copyright (c) 2006-2010, Alexey Borzov <avb@php.net>, + * Bertrand Mansion <golgote@mamasam.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * The names of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version SVN: $Id: Each.php 294057 2010-01-26 21:10:28Z avb $ + * @link http://pear.php.net/package/HTML_QuickForm2 + */ + +/** + * Base class for HTML_QuickForm2 rules + */ +require_once 'HTML/QuickForm2/Rule.php'; + +/** + * Validates all elements in a Container using a template Rule + * + * This Rule needs one configuration parameter for its work: the template Rule + * to use for actual validation. It can be passed either to + * {@link HTML_QuickForm2_Rule::__construct() the Rule constructor} as local + * configuration or to {@link HTML_QuickForm2_Factory::registerRule()} as + * global one. As usual, global configuration overrides local. + * + * The container will be considered valid if all its elements are valid + * according to a template Rule. + * + * <code> + * $group->addRule('each', 'The fields should contain only letters', + * $group->createRule('regex', '/^[a-z]+$/i')); + * </code> + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @version Release: @package_version@ + */ +class HTML_QuickForm2_Rule_Each extends HTML_QuickForm2_Rule +{ + /** + * Validates the owner's children using the template Rule + * + * @return bool Whether all children are valid according to a template Rule + */ + protected function validateOwner() + { + $rule = clone $this->getConfig(); + foreach ($this->owner->getRecursiveIterator(RecursiveIteratorIterator::LEAVES_ONLY) as $child) { + $rule->setOwner($child); + if (!$rule->validateOwner()) { + return false; + } + } + return true; + } + + /** + * Sets the template Rule to use for actual validation + * + * We do not allow using Required rules here, they are able to validate + * containers themselves without the help of Each rule. + * + * @param HTML_QuickForm2_Rule Template Rule + * @return HTML_QuickForm2_Rule + * @throws HTML_QuickForm2_InvalidArgumentException if $config is either not + * an instance of Rule or is an instance of Rule_Required + */ + public function setConfig($config) + { + if (!$config instanceof HTML_QuickForm2_Rule) { + throw new HTML_QuickForm2_InvalidArgumentException( + 'Each Rule requires a template Rule to validate with, ' . + preg_replace('/\s+/', ' ', var_export($config, true)) . ' given' + ); + } elseif ($config instanceof HTML_QuickForm2_Rule_Required) { + throw new HTML_QuickForm2_InvalidArgumentException( + 'Cannot use "required" Rule as a template' + ); + } + return parent::setConfig($config); + } + + /** + * Sets the element that will be validated by this rule + * + * @param HTML_QuickForm2_Container Container to validate + * @throws HTML_QuickForm2_InvalidArgumentException if trying to use + * this Rule on something that isn't a Container + */ + public function setOwner(HTML_QuickForm2_Node $owner) + { + if (!$owner instanceof HTML_QuickForm2_Container) { + throw new HTML_QuickForm2_InvalidArgumentException( + 'Each Rule can only validate Containers, '. + get_class($owner) . ' given' + ); + } + parent::setOwner($owner); + } +} +?>
\ No newline at end of file diff --git a/libs/HTML/QuickForm2/Rule/Empty.php b/libs/HTML/QuickForm2/Rule/Empty.php new file mode 100644 index 0000000000..76808bb288 --- /dev/null +++ b/libs/HTML/QuickForm2/Rule/Empty.php @@ -0,0 +1,89 @@ +<?php +/** + * Rule checking that the field is empty + * + * PHP version 5 + * + * LICENSE: + * + * Copyright (c) 2006-2010, Alexey Borzov <avb@php.net>, + * Bertrand Mansion <golgote@mamasam.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * The names of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version SVN: $Id: Empty.php 299480 2010-05-19 06:55:03Z avb $ + * @link http://pear.php.net/package/HTML_QuickForm2 + */ + +/** + * Base class for HTML_QuickForm2 rules + */ +require_once 'HTML/QuickForm2/Rule.php'; + +/** + * Rule checking that the field is empty + * + * Handles both simple form fields and file uploads, the latter are considered + * valid iff no file upload was attempted. + * + * The rule doesn't make much sense if used separately, but can be very helpful + * if chained: + * <code> + * $spamCheck->addRule('empty') + * ->or_($email->createRule('nonempty', 'Supply a valid email if you want to receive our spam') + * ->and_($email->createRule('email'))); + * </code> + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @version Release: @package_version@ + */ +class HTML_QuickForm2_Rule_Empty extends HTML_QuickForm2_Rule +{ + protected function validateOwner() + { + $value = $this->owner->getValue(); + if (!$this->owner instanceof HTML_QuickForm2_Element_InputFile) { + return 0 == strlen($value); + } else { + return isset($value['error']) && UPLOAD_ERR_NO_FILE == $value['error']; + } + } + + protected function getJavascriptCallback() + { + return "function() { return " . $this->owner->getJavascriptValue() . " == ''; }"; + } +} + +?>
\ No newline at end of file diff --git a/libs/HTML/QuickForm2/Rule/Length.php b/libs/HTML/QuickForm2/Rule/Length.php new file mode 100644 index 0000000000..178bbe35cb --- /dev/null +++ b/libs/HTML/QuickForm2/Rule/Length.php @@ -0,0 +1,236 @@ +<?php +/** + * Rule checking the value's length + * + * PHP version 5 + * + * LICENSE: + * + * Copyright (c) 2006-2010, Alexey Borzov <avb@php.net>, + * Bertrand Mansion <golgote@mamasam.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * The names of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version SVN: $Id: Length.php 299480 2010-05-19 06:55:03Z avb $ + * @link http://pear.php.net/package/HTML_QuickForm2 + */ + +/** + * Base class for HTML_QuickForm2 rules + */ +require_once 'HTML/QuickForm2/Rule.php'; + +/** + * Rule checking the value's length + * + * The rule needs an "allowed length" parameter for its work, it can be either + * - a scalar: the value will be valid if it is exactly this long + * - an array: the value will be valid if its length is between the given values + * (inclusive). If one of these evaluates to 0, then length will be compared + * only with the remaining one. + * See {@link mergeConfig()} for description of possible ways to pass + * configuration parameters. + * + * The Rule considers empty fields as valid and doesn't try to compare their + * lengths with provided limits. + * + * For convenience this Rule is also registered with the names 'minlength' and + * 'maxlength' (having, respectively, 'max' and 'min' parameters set to 0): + * <code> + * $password->addRule('minlength', 'The password should be at least 6 characters long', 6); + * $message->addRule('maxlength', 'Your message is too verbose', 1000); + * </code> + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @version Release: @package_version@ + */ +class HTML_QuickForm2_Rule_Length extends HTML_QuickForm2_Rule +{ + /** + * Validates the owner element + * + * @return bool whether length of the element's value is within allowed range + */ + protected function validateOwner() + { + if (0 == ($valueLength = strlen($this->owner->getValue()))) { + return true; + } + + $allowedLength = $this->getConfig(); + if (is_scalar($allowedLength)) { + return $valueLength == $allowedLength; + } else { + return (empty($allowedLength['min']) || $valueLength >= $allowedLength['min']) && + (empty($allowedLength['max']) || $valueLength <= $allowedLength['max']); + } + } + + protected function getJavascriptCallback() + { + $allowedLength = $this->getConfig(); + if (is_scalar($allowedLength)) { + $check = "length == {$allowedLength}"; + } else { + $checks = array(); + if (!empty($allowedLength['min'])) { + $checks[] = "length >= {$allowedLength['min']}"; + } + if (!empty($allowedLength['max'])) { + $checks[] = "length <= {$allowedLength['max']}"; + } + $check = implode(' && ', $checks); + } + return "function() { var length = " . $this->owner->getJavascriptValue() . + ".length; if (0 == length) { return true; } else { return {$check}; } }"; + } + + /** + * Adds the 'min' and 'max' fields from one array to the other + * + * @param array Rule configuration, array with 'min' and 'max' keys + * @param array Additional configuration, fields will be added to + * $length if it doesn't contain such a key already + * @return array + */ + protected static function mergeMinMaxLength($length, $config) + { + if (array_key_exists('min', $config) || array_key_exists('max', $config)) { + if (!array_key_exists('min', $length) && array_key_exists('min', $config)) { + $length['min'] = $config['min']; + } + if (!array_key_exists('max', $length) && array_key_exists('max', $config)) { + $length['max'] = $config['max']; + } + } else { + if (!array_key_exists('min', $length)) { + $length['min'] = reset($config); + } + if (!array_key_exists('max', $length)) { + $length['max'] = end($config); + } + } + return $length; + } + + /** + * Merges length limits given on rule creation with those given to registerRule() + * + * "Global" length limits may be passed to + * {@link HTML_QuickForm2_Factory::registerRule()} in either of the + * following formats + * - scalar (exact length) + * - array(minlength, maxlength) + * - array(['min' => minlength, ]['max' => maxlength]) + * + * "Local" length limits may be passed to the constructor in either of + * the following formats + * - scalar (if global config is unset then it is treated as an exact + * length, if 'min' or 'max' is in global config then it is treated + * as 'max' or 'min', respectively) + * - array(minlength, maxlength) + * - array(['min' => minlength, ]['max' => maxlength]) + * + * As usual, global configuration overrides local one. + * + * @param int|array Local length limits + * @param int|array Global length limits, usually provided to {@link HTML_QuickForm2_Factory::registerRule()} + * @return int|array Merged length limits + */ + public static function mergeConfig($localConfig, $globalConfig) + { + if (!isset($globalConfig)) { + $length = $localConfig; + + } elseif (!is_array($globalConfig)) { + $length = $globalConfig; + + } else { + $length = self::mergeMinMaxLength(array(), $globalConfig); + if (isset($localConfig)) { + $length = self::mergeMinMaxLength( + $length, is_array($localConfig)? $localConfig: array($localConfig) + ); + } + } + return $length; + } + + /** + * Sets the allowed length limits + * + * $config can be either of the following + * - integer (rule checks for exact length) + * - array(minlength, maxlength) + * - array(['min' => minlength, ]['max' => maxlength]) + * + * @param int|array Length limits + * @return HTML_QuickForm2_Rule + * @throws HTML_QuickForm2_InvalidArgumentException if bogus length limits + * were provided + */ + public function setConfig($config) + { + if (is_array($config)) { + $config = self::mergeMinMaxLength(array(), $config) + + array('min' => 0, 'max' => 0); + } + if (is_array($config) && ($config['min'] < 0 || $config['max'] < 0) || + !is_array($config) && $config < 0) + { + throw new HTML_QuickForm2_InvalidArgumentException( + 'Length Rule requires limits to be nonnegative, ' . + preg_replace('/\s+/', ' ', var_export($config, true)) . ' given' + ); + + } elseif (is_array($config) && $config['min'] == 0 && $config['max'] == 0 || + !is_array($config) && 0 == $config) + { + throw new HTML_QuickForm2_InvalidArgumentException( + 'Length Rule requires at least one non-zero limit, ' . + preg_replace('/\s+/', ' ', var_export($config, true)) . ' given' + ); + } + + if (!empty($config['min']) && !empty($config['max'])) { + if ($config['min'] > $config['max']) { + list($config['min'], $config['max']) = array($config['max'], $config['min']); + } elseif ($config['min'] == $config['max']) { + $config = $config['min']; + } + } + return parent::setConfig($config); + } +} +?> diff --git a/libs/HTML/QuickForm2/Rule/MaxFileSize.php b/libs/HTML/QuickForm2/Rule/MaxFileSize.php new file mode 100644 index 0000000000..b879b14502 --- /dev/null +++ b/libs/HTML/QuickForm2/Rule/MaxFileSize.php @@ -0,0 +1,124 @@ +<?php +/** + * Rule checking that uploaded file size does not exceed the given limit + * + * PHP version 5 + * + * LICENSE: + * + * Copyright (c) 2006-2010, Alexey Borzov <avb@php.net>, + * Bertrand Mansion <golgote@mamasam.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * The names of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version SVN: $Id: MaxFileSize.php 294057 2010-01-26 21:10:28Z avb $ + * @link http://pear.php.net/package/HTML_QuickForm2 + */ + +/** + * Base class for HTML_QuickForm2 rules + */ +require_once 'HTML/QuickForm2/Rule.php'; + +/** + * Rule checking that uploaded file size does not exceed the given limit + * + * The Rule needs one configuration parameter for its work: the size limit. + * This limit can be passed either to + * {@link HTML_QuickForm2_Rule::__construct() the Rule constructor} as local + * configuration or to {@link HTML_QuickForm2_Factory::registerRule()} as + * global one. As usual, global configuration overrides local one. + * + * Note that if file upload failed due to upload_max_filesize php.ini setting + * or MAX_FILE_SIZE form field, then this rule won't even be called, due to + * File element's built-in validation setting the error message. + * + * The Rule considers missing file uploads (UPLOAD_ERR_NO_FILE) valid. + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @version Release: @package_version@ + */ +class HTML_QuickForm2_Rule_MaxFileSize extends HTML_QuickForm2_Rule +{ + /** + * Validates the owner element + * + * @return bool whether uploaded file's size is within given limit + */ + protected function validateOwner() + { + $value = $this->owner->getValue(); + if (!isset($value['error']) || UPLOAD_ERR_NO_FILE == $value['error']) { + return true; + } + return ($this->getConfig() >= @filesize($value['tmp_name'])); + } + + /** + * Sets maximum allowed file size + * + * @param int Maximum allowed size + * @return HTML_QuickForm2_Rule + * @throws HTML_QuickForm2_InvalidArgumentException if a bogus size limit was provided + */ + public function setConfig($config) + { + if (0 >= $config) { + throw new HTML_QuickForm2_InvalidArgumentException( + 'MaxFileSize Rule requires a positive size limit, ' . + preg_replace('/\s+/', ' ', var_export($config, true)) . ' given' + ); + } + return parent::setConfig($config); + } + + /** + * Sets the element that will be validated by this rule + * + * @param HTML_QuickForm2_Element_InputFile File upload field to validate + * @throws HTML_QuickForm2_InvalidArgumentException if trying to use + * this Rule on something that isn't a file upload field + */ + public function setOwner(HTML_QuickForm2_Node $owner) + { + if (!$owner instanceof HTML_QuickForm2_Element_InputFile) { + throw new HTML_QuickForm2_InvalidArgumentException( + 'MaxFileSize Rule can only validate file upload fields, '. + get_class($owner) . ' given' + ); + } + parent::setOwner($owner); + } +} +?> diff --git a/libs/HTML/QuickForm2/Rule/MimeType.php b/libs/HTML/QuickForm2/Rule/MimeType.php new file mode 100644 index 0000000000..067a41c1d0 --- /dev/null +++ b/libs/HTML/QuickForm2/Rule/MimeType.php @@ -0,0 +1,122 @@ +<?php +/** + * Rule checking that uploaded file is of the correct MIME type + * + * PHP version 5 + * + * LICENSE: + * + * Copyright (c) 2006-2010, Alexey Borzov <avb@php.net>, + * Bertrand Mansion <golgote@mamasam.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * The names of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version SVN: $Id: MimeType.php 294057 2010-01-26 21:10:28Z avb $ + * @link http://pear.php.net/package/HTML_QuickForm2 + */ + +/** + * Base class for HTML_QuickForm2 rules + */ +require_once 'HTML/QuickForm2/Rule.php'; + +/** + * Rule checking that uploaded file is of the correct MIME type + * + * The Rule needs one configuration parameter for its work: a string with a + * desired MIME type or array of such strings. This parameter can be passed + * either to {@link HTML_QuickForm2_Rule::__construct() the Rule constructor} + * as local configuration or to {@link HTML_QuickForm2_Factory::registerRule()} + * as global one. As usual, global configuration overrides local one. + * + * The Rule considers missing file uploads (UPLOAD_ERR_NO_FILE) valid. + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @version Release: @package_version@ + */ +class HTML_QuickForm2_Rule_MimeType extends HTML_QuickForm2_Rule +{ + /** + * Validates the owner element + * + * @return bool whether uploaded file's MIME type is correct + */ + protected function validateOwner() + { + $value = $this->owner->getValue(); + if (!isset($value['error']) || UPLOAD_ERR_NO_FILE == $value['error']) { + return true; + } + $mime = $this->getConfig(); + return is_array($mime)? in_array($value['type'], $mime): + $value['type'] == $mime; + } + + /** + * Sets allowed MIME type(s) for the uploaded file + * + * @param string|array Allowed MIME type or an array of types + * @return HTML_QuickForm2_Rule + * @throws HTML_QuickForm2_InvalidArgumentException if bogus configuration provided + */ + public function setConfig($config) + { + if (0 == count($config) || !is_string($config) && !is_array($config)) { + throw new HTML_QuickForm2_InvalidArgumentException( + 'MimeType Rule requires MIME type(s), ' . + preg_replace('/\s+/', ' ', var_export($config, true)) . ' given' + ); + } + return parent::setConfig($config); + } + + /** + * Sets the element that will be validated by this rule + * + * @param HTML_QuickForm2_Element_InputFile File upload field to validate + * @throws HTML_QuickForm2_InvalidArgumentException if trying to use + * this Rule on something that isn't a file upload field + */ + public function setOwner(HTML_QuickForm2_Node $owner) + { + if (!$owner instanceof HTML_QuickForm2_Element_InputFile) { + throw new HTML_QuickForm2_InvalidArgumentException( + 'MimeType Rule can only validate file upload fields, '. + get_class($owner) . ' given' + ); + } + parent::setOwner($owner); + } +} +?> diff --git a/libs/HTML/QuickForm2/Rule/Nonempty.php b/libs/HTML/QuickForm2/Rule/Nonempty.php new file mode 100644 index 0000000000..e815089072 --- /dev/null +++ b/libs/HTML/QuickForm2/Rule/Nonempty.php @@ -0,0 +1,141 @@ +<?php +/** + * Rule checking that the field is not empty + * + * PHP version 5 + * + * LICENSE: + * + * Copyright (c) 2006-2010, Alexey Borzov <avb@php.net>, + * Bertrand Mansion <golgote@mamasam.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * The names of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version SVN: $Id: Nonempty.php 299706 2010-05-24 18:32:37Z avb $ + * @link http://pear.php.net/package/HTML_QuickForm2 + */ + +/** + * Base class for HTML_QuickForm2 rules + */ +require_once 'HTML/QuickForm2/Rule.php'; + +/** + * Rule checking that the field is not empty + * + * Handles simple form fields, file uploads and Containers. + * + * When validating <select multiple> fields and Containers it may use an + * optional configuration parameter for minimum number of nonempty values, + * defaulting to 1. It can be passed either to + * {@link HTML_QuickForm2_Rule::__construct() the Rule constructor} as local + * configuration or to {@link HTML_QuickForm2_Factory::registerRule()} as + * global one. As usual, global configuration overrides local. + * + * <code> + * // Required rule is 'nonempty' with a bit of special handling + * $login->addRule('required', 'Please provide your login'); + * $multiSelect->addRule('required', 'Please select at least two options', 2); + * </code> + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @version Release: @package_version@ + */ +class HTML_QuickForm2_Rule_Nonempty extends HTML_QuickForm2_Rule +{ + protected function validateOwner() + { + if ($this->owner instanceof HTML_QuickForm2_Container) { + $nonempty = 0; + foreach ($this->owner->getRecursiveIterator(RecursiveIteratorIterator::LEAVES_ONLY) as $child) { + $rule = new self($child); + if ($rule->validateOwner()) { + $nonempty++; + } + } + return $nonempty >= $this->getConfig(); + } + + $value = $this->owner->getValue(); + if ($this->owner instanceof HTML_QuickForm2_Element_InputFile) { + return isset($value['error']) && (UPLOAD_ERR_OK == $value['error']); + } elseif (is_array($value)) { + return count(array_filter($value, 'strlen')) >= $this->getConfig(); + } else { + return (bool)strlen($value); + } + } + + /** + * Sets minimum number of nonempty values + * + * This is useful for multiple selects and Containers, will be ignored for + * all other elements. Defaults to 1, thus multiple select will be + * considered not empty if at least one option is selected, Container will + * be considered not empty if at least one contained element is not empty. + * + * @param int Maximum allowed size + * @return HTML_QuickForm2_Rule + * @throws HTML_QuickForm2_InvalidArgumentException if a bogus size limit was provided + */ + public function setConfig($config) + { + if (is_null($config)) { + $config = 1; + } elseif (1 > intval($config)) { + throw new HTML_QuickForm2_InvalidArgumentException( + 'Nonempty Rule accepts a positive count of nonempty values, ' . + preg_replace('/\s+/', ' ', var_export($config, true)) . ' given' + ); + } + return parent::setConfig(intval($config)); + } + + protected function getJavascriptCallback() + { + $js = "function() {var value = " . $this->owner->getJavascriptValue() . ";"; + if (!$this->owner instanceof HTML_QuickForm2_Container) { + $js .= " if (!value instanceof Array) { return value != ''; } else { " . + "var valid = 0; for (var i = 0; i < value.length; i++) { " . + "if ('' != value[i]) { valid++; } } return valid >= " . $this->getConfig() . "; } }"; + } else { + $js .= " var values = value.getValues(); var valid = 0; " . + "for (var i = 0; i < values.length; i++) { " . + "if ('' != values[i]) { valid++; } } return valid >= " . $this->getConfig() . "; }"; + } + return $js; + } +} + +?> diff --git a/libs/HTML/QuickForm2/Rule/NotCallback.php b/libs/HTML/QuickForm2/Rule/NotCallback.php new file mode 100644 index 0000000000..ace4f83704 --- /dev/null +++ b/libs/HTML/QuickForm2/Rule/NotCallback.php @@ -0,0 +1,80 @@ +<?php +/** + * Rule checking the value via a callback function (method) with logical negation + * + * PHP version 5 + * + * LICENSE: + * + * Copyright (c) 2006-2010, Alexey Borzov <avb@php.net>, + * Bertrand Mansion <golgote@mamasam.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * The names of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version SVN: $Id: NotCallback.php 299305 2010-05-12 20:15:28Z avb $ + * @link http://pear.php.net/package/HTML_QuickForm2 + */ + +/** + * Rule checking the value via a callback function (method) + */ +require_once 'HTML/QuickForm2/Rule/Callback.php'; + +/** + * Rule checking the value via a callback function (method) with logical negation + * + * The Rule accepts the same configuration parameters as the Callback Rule + * does, but the callback is expected to return false if the element is valid + * and true if it is invalid. + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @version Release: @package_version@ + */ +class HTML_QuickForm2_Rule_NotCallback extends HTML_QuickForm2_Rule_Callback +{ + /** + * Validates the owner element + * + * @return bool negated result of a callback function + */ + protected function validateOwner() + { + $value = $this->owner->getValue(); + $config = $this->getConfig(); + return !call_user_func_array( + $config['callback'], array_merge(array($value), $config['arguments']) + ); + } +} +?>
\ No newline at end of file diff --git a/libs/HTML/QuickForm2/Rule/NotRegex.php b/libs/HTML/QuickForm2/Rule/NotRegex.php new file mode 100644 index 0000000000..acb7873787 --- /dev/null +++ b/libs/HTML/QuickForm2/Rule/NotRegex.php @@ -0,0 +1,106 @@ +<?php +/** + * Checks that the element's value does not match a regular expression + * + * PHP version 5 + * + * LICENSE: + * + * Copyright (c) 2006-2010, Alexey Borzov <avb@php.net>, + * Bertrand Mansion <golgote@mamasam.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * The names of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version SVN: $Id: NotRegex.php 299480 2010-05-19 06:55:03Z avb $ + * @link http://pear.php.net/package/HTML_QuickForm2 + */ + +/** + * Validates values using regular expressions + */ +require_once 'HTML/QuickForm2/Rule/Regex.php'; + +/** + * Checks that the element's value does not match a regular expression + * + * The Rule behaves like Regex Rule, but it considers the element valid if its + * value does not match the given regular expression. + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @version Release: @package_version@ + */ +class HTML_QuickForm2_Rule_NotRegex extends HTML_QuickForm2_Rule_Regex +{ + /** + * Validates the owner element + * + * @return bool whether element's value does not match given regular expression + */ + protected function validateOwner() + { + $value = $this->owner->getValue(); + if ($this->owner instanceof HTML_QuickForm2_Element_InputFile) { + if (!isset($value['error']) || UPLOAD_ERR_NO_FILE == $value['error']) { + return true; + } + $value = $value['name']; + } elseif (!strlen($value)) { + return true; + } + return !preg_match($this->getConfig() . 'D', $value); + } + + /** + * Returns the client-side validation callback + * + * For this to work properly, slashes have to be used as regex delimiters. + * The method takes care of transforming PHP unicode escapes in regexps to + * JS unicode escapes if using 'u' modifier (see bug #12376) + * + * @return string + */ + protected function getJavascriptCallback() + { + $regex = $this->getConfig(); + + if ($pos = strpos($regex, 'u', strrpos($regex, '/'))) { + $regex = substr($regex, 0, $pos) . substr($regex, $pos + 1); + $regex = preg_replace('/(?<!\\\\)(?>\\\\\\\\)*\\\\x{([a-fA-F0-9]+)}/', '\\u$1', $regex); + } + + return "function() { var regex = {$regex}; var value = " . $this->owner->getJavascriptValue() . + "; return value == '' || !regex.test(value); }"; + } +} +?>
\ No newline at end of file diff --git a/libs/HTML/QuickForm2/Rule/Regex.php b/libs/HTML/QuickForm2/Rule/Regex.php new file mode 100644 index 0000000000..a3eeea30f3 --- /dev/null +++ b/libs/HTML/QuickForm2/Rule/Regex.php @@ -0,0 +1,133 @@ +<?php +/** + * Validates values using regular expressions + * + * PHP version 5 + * + * LICENSE: + * + * Copyright (c) 2006-2010, Alexey Borzov <avb@php.net>, + * Bertrand Mansion <golgote@mamasam.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * The names of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version SVN: $Id: Regex.php 299480 2010-05-19 06:55:03Z avb $ + * @link http://pear.php.net/package/HTML_QuickForm2 + */ + +/** + * Base class for HTML_QuickForm2 rules + */ +require_once 'HTML/QuickForm2/Rule.php'; + +/** + * Validates values using regular expressions + * + * The Rule needs one configuration parameter for its work: a Perl-compatible + * regular expression. This parameter can be passed either to + * {@link HTML_QuickForm2_Rule::__construct() the Rule constructor} as local + * configuration or to {@link HTML_QuickForm2_Factory::registerRule()} + * as global one. As usual, global configuration overrides local one. + * + * The Rule can also validate file uploads, in this case the regular expression + * is applied to upload's 'name' field. + * + * The Rule considers empty fields (file upload fields with UPLOAD_ERR_NO_FILE) + * as valid and doesn't try to test them with the regular expression. + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @version Release: @package_version@ + */ +class HTML_QuickForm2_Rule_Regex extends HTML_QuickForm2_Rule +{ + /** + * Validates the owner element + * + * @return bool whether element's value matches given regular expression + */ + protected function validateOwner() + { + $value = $this->owner->getValue(); + if ($this->owner instanceof HTML_QuickForm2_Element_InputFile) { + if (!isset($value['error']) || UPLOAD_ERR_NO_FILE == $value['error']) { + return true; + } + $value = $value['name']; + } elseif (!strlen($value)) { + return true; + } + return preg_match($this->getConfig() . 'D', $value); + } + + /** + * Sets the regular expression to validate with + * + * @param string Regular expression + * @return HTML_QuickForm2_Rule + * @throws HTML_QuickForm2_InvalidArgumentException if $config is not a string + */ + public function setConfig($config) + { + if (!is_string($config)) { + throw new HTML_QuickForm2_InvalidArgumentException( + 'Regex Rule requires a regular expression, ' . + preg_replace('/\s+/', ' ', var_export($config, true)) . ' given' + ); + } + return parent::setConfig($config); + } + + /** + * Returns the client-side validation callback + * + * For this to work properly, slashes have to be used as regex delimiters. + * The method takes care of transforming PHP unicode escapes in regexps to + * JS unicode escapes if using 'u' modifier (see bug #12376) + * + * @return string + */ + protected function getJavascriptCallback() + { + $regex = $this->getConfig(); + + if ($pos = strpos($regex, 'u', strrpos($regex, '/'))) { + $regex = substr($regex, 0, $pos) . substr($regex, $pos + 1); + $regex = preg_replace('/(?<!\\\\)(?>\\\\\\\\)*\\\\x{([a-fA-F0-9]+)}/', '\\u$1', $regex); + } + + return "function() { var regex = {$regex}; var value = " . $this->owner->getJavascriptValue() . + "; return value == '' || regex.test(value); }"; + } +} +?>
\ No newline at end of file diff --git a/libs/HTML/QuickForm2/Rule/Required.php b/libs/HTML/QuickForm2/Rule/Required.php new file mode 100644 index 0000000000..9fa3f3c1af --- /dev/null +++ b/libs/HTML/QuickForm2/Rule/Required.php @@ -0,0 +1,88 @@ +<?php +/** + * Rule for required elements + * + * PHP version 5 + * + * LICENSE: + * + * Copyright (c) 2006-2010, Alexey Borzov <avb@php.net>, + * Bertrand Mansion <golgote@mamasam.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * The names of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version SVN: $Id: Required.php 294057 2010-01-26 21:10:28Z avb $ + * @link http://pear.php.net/package/HTML_QuickForm2 + */ + +/** + * Rule checking that the form field is not empty + */ +require_once 'HTML/QuickForm2/Rule/Nonempty.php'; + +/** + * Rule for required elements + * + * The main difference from "nonempty" Rule is that + * - elements to which this Rule is attached will be considered required + * ({@link HTML_QuickForm2_Node::isRequired()} will return true for them) and + * marked accordingly when outputting the form + * - this Rule can only be added directly to the element and other Rules can + * only be added to it via and_() method + * + * @category HTML + * @package HTML_QuickForm2 + * @author Alexey Borzov <avb@php.net> + * @author Bertrand Mansion <golgote@mamasam.com> + * @version Release: @package_version@ + */ +class HTML_QuickForm2_Rule_Required extends HTML_QuickForm2_Rule_Nonempty +{ + /** + * Disallows adding a rule to the chain with an "or" operator + * + * Required rules are different from all others because they affect the + * visual representation of an element ("* denotes required field"). + * Therefore we cannot allow chaining other rules to these via or_(), since + * this will effectively mean that the field is not required anymore and the + * visual difference is bogus. + * + * @param HTML_QuickForm2_Rule + * @throws HTML_QuickForm2_Exception + */ + public function or_(HTML_QuickForm2_Rule $next) + { + throw new HTML_QuickForm2_Exception( + 'or_(): Cannot add a rule to "required" rule' + ); + } +} +?> |