home *** CD-ROM | disk | FTP | other *** search
/ Cricao de Sites - 650 Layouts Prontos / WebMasters.iso / Servidores / xampp-win32-1.6.7-installer.exe / php / PEAR / HTML / QuickForm2 / Element / Select.php < prev    next >
Encoding:
PHP Script  |  2008-07-02  |  19.2 KB  |  565 lines

  1. <?php
  2. /**
  3.  * Classes for <select> elements
  4.  *
  5.  * PHP version 5
  6.  *
  7.  * LICENSE:
  8.  * 
  9.  * Copyright (c) 2006, 2007, Alexey Borzov <avb@php.net>,
  10.  *                           Bertrand Mansion <golgote@mamasam.com>
  11.  * All rights reserved.
  12.  *
  13.  * Redistribution and use in source and binary forms, with or without
  14.  * modification, are permitted provided that the following conditions
  15.  * are met:
  16.  *
  17.  *    * Redistributions of source code must retain the above copyright
  18.  *      notice, this list of conditions and the following disclaimer.
  19.  *    * Redistributions in binary form must reproduce the above copyright
  20.  *      notice, this list of conditions and the following disclaimer in the 
  21.  *      documentation and/or other materials provided with the distribution.
  22.  *    * The names of the authors may not be used to endorse or promote products 
  23.  *      derived from this software without specific prior written permission.
  24.  *
  25.  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  26.  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  27.  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  28.  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  29.  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  30.  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  31.  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  32.  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
  33.  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  34.  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  35.  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  36.  *
  37.  * @category   HTML
  38.  * @package    HTML_QuickForm2
  39.  * @author     Alexey Borzov <avb@php.net>
  40.  * @author     Bertrand Mansion <golgote@mamasam.com>
  41.  * @license    http://opensource.org/licenses/bsd-license.php New BSD License
  42.  * @version    CVS: $Id: Select.php,v 1.11 2007/06/30 20:36:00 avb Exp $
  43.  * @link       http://pear.php.net/package/HTML_QuickForm2
  44.  */
  45.  
  46. /**
  47.  * Base class for simple HTML_QuickForm2 elements  
  48.  */
  49. require_once 'HTML/QuickForm2/Element.php';
  50.  
  51.  
  52. /**
  53.  * Collection of <option>s and <optgroup>s
  54.  *
  55.  * This class handles the output of <option> tags. The class is not intended to 
  56.  * be used directly.
  57.  * 
  58.  * @category   HTML
  59.  * @package    HTML_QuickForm2
  60.  * @author     Alexey Borzov <avb@php.net>
  61.  * @author     Bertrand Mansion <golgote@mamasam.com>
  62.  * @version    Release: 0.2.0
  63.  */
  64. class HTML_QuickForm2_Element_Select_OptionContainer extends HTML_Common2
  65.     implements IteratorAggregate, Countable
  66. {
  67.    /**
  68.     * List of options and optgroups in this container
  69.     *
  70.     * Options are stored as arrays (for performance reasons), optgroups as 
  71.     * instances of Optgroup class.
  72.     *
  73.     * @var array
  74.     */
  75.     protected $options = array();
  76.  
  77.    /**
  78.     * Reference to parent <select>'s values   
  79.     * @var array
  80.     */
  81.     protected $values;
  82.  
  83.    /**
  84.     * Reference to parent <select>'s possible values   
  85.     * @var array
  86.     */
  87.     protected $possibleValues;
  88.  
  89.  
  90.    /**
  91.     * Class constructor  
  92.     *
  93.     * @param    array   Reference to values of parent <select> element
  94.     * @param    array   Reference to possible values of parent <select> element
  95.     */
  96.     public function __construct(&$values, &$possibleValues)
  97.     {
  98.         $this->values         =& $values;
  99.         $this->possibleValues =& $possibleValues;
  100.     }
  101.  
  102.    /**
  103.     * Adds a new option  
  104.     *
  105.     * Please note that if you pass 'selected' attribute in the $attributes
  106.     * parameter then this option's value will be added to <select>'s values.
  107.     *
  108.     * @param    string  Option text
  109.     * @param    string  'value' attribute for <option> tag
  110.     * @param    mixed   Additional attributes for <option> tag (either as a
  111.     *                   string or as an associative array)
  112.     */
  113.     public function addOption($text, $value, $attributes = null)
  114.     {
  115.         if (null === $attributes) {
  116.             $attributes = array('value' => (string)$value);
  117.         } else {
  118.             $attributes = self::prepareAttributes($attributes);
  119.             if (isset($attributes['selected'])) {
  120.                 // the 'selected' attribute will be set in __toString()
  121.                 unset($attributes['selected']);
  122.                 if (!in_array($value, $this->values)) {
  123.                     $this->values[] = $value;
  124.                 }
  125.             }
  126.             $attributes['value'] = (string)$value;
  127.         }
  128.         if (!isset($attributes['disabled'])) {
  129.             $this->possibleValues[(string)$value] = true;
  130.         }
  131.         $this->options[] = array('text' => $text, 'attr' => $attributes);
  132.     }
  133.  
  134.    /**
  135.     * Adds a new optgroup  
  136.     *
  137.     * @param    string  'label' attribute for optgroup tag
  138.     * @param    mixed   Additional attributes for <optgroup> tag (either as a
  139.     *                   string or as an associative array)
  140.     * @return   HTML_QuickForm2_Element_Select_Optgroup
  141.     */
  142.     public function addOptgroup($label, $attributes = null)
  143.     {
  144.         $optgroup = new HTML_QuickForm2_Element_Select_Optgroup(
  145.                             $this->values, $this->possibleValues, 
  146.                             $label, $attributes
  147.                         );
  148.         $this->options[] = $optgroup;
  149.         return $optgroup;
  150.     }
  151.  
  152.    /**
  153.     * Returns an array of contained options  
  154.     *
  155.     * @return   array
  156.     */
  157.     public function getOptions()
  158.     {
  159.         return $this->options;
  160.     }
  161.  
  162.     public function __toString()
  163.     {
  164.         $indentLvl = $this->getIndentLevel();
  165.         $indent    = $this->getIndent() . self::getOption('indent');
  166.         $linebreak = self::getOption('linebreak');
  167.         $html      = '';
  168.         $strValues = array_map('strval', $this->values);
  169.         foreach ($this->options as $option) {
  170.             if (is_array($option)) {
  171.                 if (in_array($option['attr']['value'], $strValues, true)) {
  172.                     $option['attr']['selected'] = 'selected';
  173.                 }
  174.                 $html .= $indent . '<option' . 
  175.                          self::getAttributesString($option['attr']) .
  176.                          '>' . $option['text'] . '</option>' . $linebreak;
  177.             } elseif ($option instanceof HTML_QuickForm2_Element_Select_OptionContainer) {
  178.                 $option->setIndentLevel($indentLvl + 1);
  179.                 $html .= $option->__toString();
  180.             }
  181.         }
  182.         return $html;
  183.     }
  184.  
  185.    /**
  186.     * Returns an iterator over contained elements
  187.     *
  188.     * @return   HTML_QuickForm2_Element_Select_OptionIterator
  189.     */
  190.     public function getIterator()
  191.     {
  192.         return new HTML_QuickForm2_Element_Select_OptionIterator($this->options);
  193.     }
  194.  
  195.    /**
  196.     * Returns a recursive iterator over contained elements  
  197.     *
  198.     * @return   RecursiveIteratorIterator
  199.     */
  200.     public function getRecursiveIterator()
  201.     {
  202.         return new RecursiveIteratorIterator(
  203.             new HTML_QuickForm2_Element_Select_OptionIterator($this->options),
  204.             RecursiveIteratorIterator::SELF_FIRST
  205.         );
  206.     }
  207.  
  208.    /**
  209.     * Returns the number of options in the container
  210.     *
  211.     * @return   int
  212.     */
  213.     public function count()
  214.     {
  215.         return count($this->options);
  216.     }
  217. }
  218.  
  219.  
  220. /**
  221.  * Class representing an <optgroup> tag
  222.  *
  223.  * Do not instantiate this class yourself, use 
  224.  * {@link HTML_QuickForm2_Element_Select::addOptgroup()} method
  225.  *
  226.  * @category   HTML
  227.  * @package    HTML_QuickForm2
  228.  * @author     Alexey Borzov <avb@php.net>
  229.  * @author     Bertrand Mansion <golgote@mamasam.com>
  230.  * @version    Release: 0.2.0
  231.  */
  232. class HTML_QuickForm2_Element_Select_Optgroup 
  233.     extends HTML_QuickForm2_Element_Select_OptionContainer
  234. {
  235.    /**
  236.     * Class constructor
  237.     *
  238.     * @param    array   Reference to values of parent <select> element
  239.     * @param    array   Reference to possible values of parent <select> element
  240.     * @param    string  'label' attribute for optgroup tag
  241.     * @param    mixed   Additional attributes for <optgroup> tag (either as a
  242.     *                   string or as an associative array)
  243.     */
  244.     public function __construct(&$values, &$possibleValues, $label, $attributes = null)
  245.     {
  246.         parent::__construct($values, $possibleValues);
  247.         $this->setAttributes($attributes);
  248.         $this->attributes['label'] = (string)$label;
  249.     }
  250.  
  251.     public function __toString()
  252.     {
  253.         $indent    = $this->getIndent();
  254.         $linebreak = self::getOption('linebreak');
  255.         return $indent . '<optgroup' . $this->getAttributes(true) . '>' .
  256.                $linebreak . parent::__toString() . $indent . '</optgroup>' . $linebreak;
  257.     }
  258. }
  259.  
  260. /**
  261.  * Implements a recursive iterator for options arrays
  262.  *
  263.  * @category   HTML
  264.  * @package    HTML_QuickForm2
  265.  * @author     Alexey Borzov <avb@php.net>
  266.  * @author     Bertrand Mansion <golgote@mamasam.com>
  267.  * @version    Release: 0.2.0
  268.  */
  269. class HTML_QuickForm2_Element_Select_OptionIterator extends RecursiveArrayIterator 
  270.     implements RecursiveIterator
  271. {
  272.     public function hasChildren()
  273.     {
  274.         return $this->current() instanceof HTML_QuickForm2_Element_Select_OptionContainer;
  275.     }
  276.     
  277.     public function getChildren()
  278.     {
  279.         return new HTML_QuickForm2_Element_Select_OptionIterator(
  280.             $this->current()->getOptions()
  281.         );
  282.     }
  283. }
  284.  
  285.  
  286. /**
  287.  * Class representing a <select> element
  288.  *
  289.  * @category   HTML
  290.  * @package    HTML_QuickForm2
  291.  * @author     Alexey Borzov <avb@php.net>
  292.  * @author     Bertrand Mansion <golgote@mamasam.com>
  293.  * @version    Release: 0.2.0
  294.  */
  295. class HTML_QuickForm2_Element_Select extends HTML_QuickForm2_Element
  296. {
  297.     protected $persistent = true;
  298.  
  299.    /**
  300.     * Values for the select element (i.e. values of the selected options)  
  301.     * @var  array
  302.     */
  303.     protected $values = array();
  304.  
  305.    /**
  306.     * Possible values for select elements
  307.     *
  308.     * A value is considered possible if it is present as a value attribute of
  309.     * some option and that option is not disabled.
  310.     * @var array
  311.     */
  312.     protected $possibleValues = array();
  313.  
  314.  
  315.    /**
  316.     * Object containing options for the <select> element
  317.     * @var  HTML_QuickForm2_Element_Select_OptionContainer
  318.     */
  319.     protected $optionContainer;
  320.  
  321.    /**
  322.     * Class constructor
  323.     *
  324.     * @param    string  Element name
  325.     * @param    mixed   Attributes (either a string or an array)
  326.     * @param    array   Data used to populate the element's options, passed to
  327.     *                   {@link loadOptions()} method. Format:
  328.     *                   <code>
  329.     *                   $data = array('options' => array('option1', 'option2'));
  330.     *                   </code>
  331.     * @throws   HTML_QuickForm2_InvalidArgumentException    if junk is given in $options
  332.     */
  333.     public function __construct($name = null, $attributes = null, array $data = array())
  334.     {
  335.         $options = isset($data['options'])? $data['options']: array();
  336.         unset($data['options']);
  337.         parent::__construct($name, $attributes, $data);
  338.         $this->loadOptions($options);
  339.     }
  340.  
  341.     public function getType()
  342.     {
  343.         return 'select';
  344.     }
  345.  
  346.     public function __toString()
  347.     {
  348.         if ($this->frozen) {
  349.             return $this->getFrozenHtml();
  350.         } else {
  351.             if (empty($this->attributes['multiple'])) {
  352.                 $attrString = $this->getAttributes(true);
  353.             } else {
  354.                 $this->attributes['name'] .= '[]';
  355.                 $attrString = $this->getAttributes(true);
  356.                 $this->attributes['name']  = substr($this->attributes['name'], 0, -2);
  357.             }
  358.             $indent = $this->getIndent();
  359.             return $indent . '<select' . $attrString . '>' .
  360.                    self::getOption('linebreak') .
  361.                    $this->optionContainer->__toString() .
  362.                    $indent . '</select>';
  363.         }
  364.     }
  365.  
  366.     protected function getFrozenHtml()
  367.     {
  368.         if (null === ($value = $this->getValue())) {
  369.             return ' ';
  370.         }
  371.         $valueHash = is_array($value)? array_flip($value): array($value => true);
  372.         $options   = array();
  373.         foreach ($this->optionContainer->getRecursiveIterator() as $child) {
  374.             if (is_array($child) && isset($valueHash[$child['attr']['value']]) &&
  375.                 empty($child['attr']['disabled'])) 
  376.             {
  377.                 $options[] = $child['text'];
  378.             }
  379.         }
  380.  
  381.         $html = implode('<br />', $options);
  382.         if ($this->persistent) {
  383.             $name = $this->attributes['name'] . 
  384.                     (empty($this->attributes['multiple'])? '': '[]');
  385.             // Only use id attribute if doing single hidden input
  386.             $idAttr = (1 == count($valueHash))? array('id' => $this->getId()): array(); 
  387.             foreach ($valueHash as $key => $item) {
  388.                 $html .= '<input type="hidden"' . self::getAttributesString(array(
  389.                              'name'  => $name,
  390.                              'value' => $key
  391.                          ) + $idAttr) . ' />';
  392.             }
  393.         }
  394.         return $html;
  395.     }
  396.  
  397.    /**
  398.     * Returns the value of the <select> element
  399.     *
  400.     * Please note that the returned value may not necessarily be equal to that
  401.     * passed to {@link setValue()}. It passes "intrinsic validation" confirming
  402.     * that such value could possibly be submitted by this <select> element.   
  403.     * Specifically, this method will return null if the elements "disabled"
  404.     * attribute is set, it will not return values if there are no options having
  405.     * such a "value" attribute or if such options' "disabled" attribute is set.
  406.     * It will also only return a scalar value for single selects, mimicking
  407.     * the common browsers' behaviour. 
  408.     *
  409.     * @return   mixed   "value" attribute of selected option in case of single
  410.     *                   select, array of selected options' "value" attributes in
  411.     *                   case of multiple selects, null if no options selected  
  412.     */
  413.     public function getValue()
  414.     {
  415.         if (0 == count($this->optionContainer) || 0 == count($this->values) ||
  416.             0 == count($this->possibleValues) || !empty($this->attributes['disabled']))
  417.         {
  418.             return null;
  419.         }
  420.  
  421.         $values = array();
  422.         foreach ($this->values as $value) {
  423.             if (!empty($this->possibleValues[$value])) {
  424.                 $values[] = $value;
  425.             }
  426.         }
  427.         if (0 == count($values)) {
  428.             return null;
  429.         } elseif (!empty($this->attributes['multiple'])) {
  430.             return $values;
  431.         } elseif (1 == count($values)) {
  432.             return $values[0];
  433.         } else {
  434.             // The <select> is not multiple, but several options are to be 
  435.             // selected. At least IE and Mozilla select the last selected 
  436.             // option in this case, we should do the same
  437.             foreach ($this->optionContainer->getRecursiveIterator() as $child) {
  438.                 if (is_array($child) && in_array($child['attr']['value'], $values)) {
  439.                     $lastValue = $child['attr']['value'];
  440.                 }
  441.             }
  442.             return $lastValue;
  443.         }
  444.     }
  445.  
  446.     public function setValue($value)
  447.     {
  448.         if (is_array($value)) {
  449.             $this->values = array_values($value);
  450.         } else {
  451.             $this->values = array($value);
  452.         }
  453.         return $this;
  454.     }
  455.  
  456.    /**
  457.     * Loads <option>s (and <optgroup>s) for select element
  458.     *
  459.     * The method expects a array of options and optgroups:
  460.     * <pre>
  461.     * array(
  462.     *     'option value 1' => 'option text 1',
  463.     *     ...
  464.     *     'option value N' => 'option text N',
  465.     *     'optgroup label 1' => array(
  466.     *         'option value' => 'option text',
  467.     *         ...
  468.     *     ),
  469.     *     ...
  470.     * )
  471.     * </pre>
  472.     * If value is a scalar, then array key is treated as "value" attribute of 
  473.     * <option> and value as this <option>'s text. If value is an array, then 
  474.     * key is treated as a "label" attribute of <optgroup> and value as an 
  475.     * array of <option>s for this <optgroup>.
  476.     * 
  477.     * If you need to specify additional attributes for <option> and <optgroup>
  478.     * tags, then you need to use {@link addOption()} and {@link addOptgroup()}
  479.     * methods instead of this one.
  480.     * 
  481.     * @param    array
  482.     * @throws   HTML_QuickForm2_InvalidArgumentException    if junk is given in $options
  483.     * @return   HTML_QuickForm2_Element_Select
  484.     */
  485.     public function loadOptions(array $options)
  486.     {
  487.         $this->possibleValues  = array();
  488.         $this->optionContainer = new HTML_QuickForm2_Element_Select_OptionContainer(
  489.                                      $this->values, $this->possibleValues
  490.                                  );
  491.         $this->loadOptionsFromArray($this->optionContainer, $options);
  492.         return $this;
  493.     }
  494.  
  495.  
  496.    /**
  497.     * Adds options from given array into given container 
  498.     *
  499.     * @param    HTML_QuickForm2_Element_Select_OptionContainer  options will be
  500.     *           added to this container
  501.     * @param    array   options array
  502.     */
  503.     protected function loadOptionsFromArray(
  504.         HTML_QuickForm2_Element_Select_OptionContainer $container, $options
  505.     )
  506.     {
  507.         foreach ($options as $key => $value) {
  508.             if (is_array($value)) {
  509.                 $optgroup = $container->addOptgroup($key);
  510.                 $this->loadOptionsFromArray($optgroup, $value);
  511.             } else {
  512.                 $container->addOption($value, $key);
  513.             }
  514.         }
  515.     }
  516.  
  517.  
  518.    /**
  519.     * Adds a new option  
  520.     *
  521.     * Please note that if you pass 'selected' attribute in the $attributes
  522.     * parameter then this option's value will be added to <select>'s values.
  523.     *
  524.     * @param    string  Option text
  525.     * @param    string  'value' attribute for <option> tag
  526.     * @param    mixed   Additional attributes for <option> tag (either as a
  527.     *                   string or as an associative array)
  528.     */
  529.     public function addOption($text, $value, $attributes = null)
  530.     {
  531.         return $this->optionContainer->addOption($text, $value, $attributes);
  532.     }
  533.  
  534.    /**
  535.     * Adds a new optgroup  
  536.     *
  537.     * @param    string  'label' attribute for optgroup tag
  538.     * @param    mixed   Additional attributes for <optgroup> tag (either as a
  539.     *                   string or as an associative array)
  540.     * @return   HTML_QuickForm2_Element_Select_Optgroup
  541.     */
  542.     public function addOptgroup($label, $attributes = null)
  543.     {
  544.         return $this->optionContainer->addOptgroup($label, $attributes);
  545.     }
  546.  
  547.     protected function updateValue()
  548.     {
  549.         if (!$this->getAttribute('multiple')) {
  550.             parent::updateValue();
  551.         } else {
  552.             $name = $this->getName();
  553.             foreach ($this->getDataSources() as $ds) {
  554.                 if (null !== ($value = $ds->getValue($name)) ||
  555.                     $ds instanceof HTML_QuickForm2_DataSource_Submit)
  556.                 {
  557.                     $this->setValue(null === $value? array(): $value);
  558.                     return;
  559.                 }
  560.             }
  561.         }
  562.     }
  563. }
  564. ?>
  565.