/libs/HTML/QuickForm2/Element/Select.php
PHP | 575 lines | 264 code | 41 blank | 270 comment | 39 complexity | a301198923f2a48397c028d7e0d6b016 MD5 | raw file
Possible License(s): LGPL-3.0, JSON, MIT, GPL-3.0, LGPL-2.1, GPL-2.0, AGPL-1.0, BSD-2-Clause, BSD-3-Clause
- <?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);
- }
- public 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;
- }
- }
- }
- }
- }
- ?>