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 / Container.php next >
Encoding:
PHP Script  |  2008-07-02  |  15.4 KB  |  478 lines

  1. <?php
  2. /**
  3.  * Base class for simple HTML_QuickForm2 containers
  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: Container.php,v 1.20 2007/10/22 10:11:47 mansion Exp $
  43.  * @link       http://pear.php.net/package/HTML_QuickForm2
  44.  */
  45.  
  46. /**
  47.  * Base class for all HTML_QuickForm2 elements
  48.  */
  49. require_once 'HTML/QuickForm2/Node.php';
  50.  
  51. /**
  52.  * Abstract base class for simple QuickForm2 containers
  53.  *
  54.  * @category   HTML
  55.  * @package    HTML_QuickForm2
  56.  * @author     Alexey Borzov <avb@php.net>
  57.  * @author     Bertrand Mansion <golgote@mamasam.com>
  58.  * @version    Release: 0.2.0
  59.  */
  60. abstract class HTML_QuickForm2_Container extends HTML_QuickForm2_Node
  61.     implements IteratorAggregate, Countable
  62. {
  63.    /**
  64.     * Array of elements contained in this container
  65.     * @var array
  66.     */
  67.     protected $elements = array();
  68.  
  69.    /**
  70.     * 'name' and 'id' attributes should be always present and their setting
  71.     * should go through setName() and setId().
  72.     * @var array
  73.     */
  74.     protected $watchedAttributes = array('id', 'name');
  75.  
  76.     protected function onAttributeChange($name, $value = null)
  77.     {
  78.         if ('name' == $name) {
  79.             if (null === $value) {
  80.                 throw new HTML_QuickForm2_InvalidArgumentException(
  81.                     "Required attribute 'name' can not be removed"
  82.                 );
  83.             } else {
  84.                 $this->setName($value);
  85.             }
  86.         } elseif ('id' == $name) {
  87.             if (null === $value) {
  88.                 throw new HTML_QuickForm2_InvalidArgumentException(
  89.                     "Required attribute 'id' can not be removed"
  90.                 );
  91.             } else {
  92.                 $this->setId($value);
  93.             }
  94.         }
  95.     }
  96.  
  97.     public function getName()
  98.     {
  99.         return $this->attributes['name'];
  100.     }
  101.  
  102.     public function setName($name)
  103.     {
  104.         $this->attributes['name'] = (string)$name;
  105.         return $this;
  106.     }
  107.  
  108.     public function getId()
  109.     {
  110.         return isset($this->attributes['id'])? $this->attributes['id']: null;
  111.     }
  112.  
  113.     public function setId($id = null)
  114.     {
  115.         if (is_null($id)) {
  116.             $id = self::generateId($this->getName());
  117.         } else {
  118.             self::storeId($id);
  119.         }
  120.         $this->attributes['id'] = (string)$id;
  121.         return $this;
  122.     }
  123.  
  124.     public function toggleFrozen($freeze = null)
  125.     {
  126.         if (null !== $freeze) {
  127.             foreach ($this as $child) {
  128.                 $child->toggleFrozen($freeze);
  129.             }
  130.         }
  131.         return parent::toggleFrozen($freeze);
  132.     }
  133.  
  134.     public function persistentFreeze($persistent = null)
  135.     {
  136.         if (null !== $persistent) {
  137.             foreach ($this as $child) {
  138.                 $child->persistentFreeze($persistent);
  139.             }
  140.         }
  141.         return parent::persistentFreeze($persistent);
  142.     }
  143.  
  144.    /**
  145.     * Returns the element's value
  146.     *
  147.     * The default implementation for Containers is to return an array with
  148.     * contained elements' values. The array is indexed the same way $_GET and
  149.     * $_POST arrays would be for these elements.
  150.     *
  151.     * @return   array|null
  152.     */
  153.     public function getValue()
  154.     {
  155.         $values = array();
  156.         foreach ($this as $child) {
  157.             $value = $child->getValue();
  158.             if (null !== $value) {
  159.                 if ($child instanceof HTML_QuickForm2_Container) {
  160.                     $values = self::arrayMerge($values, $value);
  161.                 } else {
  162.                     $name = $child->getName();
  163.                     if (!strpos($name, '[')) {
  164.                         $values[$name] = $value;
  165.                     } else {
  166.                         $tokens   =  explode('[', str_replace(']', '', $name));
  167.                         $valueAry =& $values;
  168.                         do {
  169.                             $token = array_shift($tokens);
  170.                             if (!isset($valueAry[$token])) {
  171.                                 $valueAry[$token] = array();
  172.                             }
  173.                             $valueAry =& $valueAry[$token];
  174.                         } while (count($tokens) > 1);
  175.                         $valueAry[$tokens[0]] = $value;
  176.                     }
  177.                 }
  178.             }
  179.         }
  180.         return empty($values)? null: $values;
  181.     }
  182.  
  183.    /**
  184.     * Merges two arrays
  185.     *
  186.     * Merges two arrays like the PHP function array_merge_recursive does,
  187.     * the difference being that existing integer keys will not be renumbered.
  188.     *
  189.     * @param    array
  190.     * @param    array
  191.     * @return   array   resulting array
  192.     */
  193.     protected static function arrayMerge($a, $b)
  194.     {
  195.         foreach ($b as $k => $v) {
  196.             if (!is_array($v) || isset($a[$k]) && !is_array($a[$k])) {
  197.                 $a[$k] = $v;
  198.             } else {
  199.                 $a[$k] = self::arrayMerge(isset($a[$k])? $a[$k]: array(), $v);
  200.             }
  201.         }
  202.         return $a;
  203.     }
  204.  
  205.    /**
  206.     * Returns an array of this container's elements
  207.     *
  208.     * @return   array   Container elements
  209.     */
  210.     public function getElements()
  211.     {
  212.         return $this->elements;
  213.     }
  214.  
  215.    /**
  216.     * Appends an element to the container
  217.     *
  218.     * If the element was previously added to the container or to another
  219.     * container, it is first removed there.
  220.     *
  221.     * @param    HTML_QuickForm2_Node     Element to add
  222.     * @return   HTML_QuickForm2_Node     Added element
  223.     * @throws   HTML_QuickForm2_InvalidArgumentException
  224.     */
  225.     public function appendChild(HTML_QuickForm2_Node $element)
  226.     {
  227.         if ($this === $element->getContainer()) {
  228.             $this->removeChild($element);
  229.         }
  230.         $element->setContainer($this);
  231.         $this->elements[] = $element;
  232.         return $element;
  233.     }
  234.  
  235.    /**
  236.     * Appends an element to the container (possibly creating it first)
  237.     *
  238.     * If the first parameter is an instance of HTML_QuickForm2_Node then all
  239.     * other parameters are ignored and the method just calls {@link appendChild()}.
  240.     * In the other case the element is first created via
  241.     * {@link HTML_QuickForm2_Factory::createElement()} and then added via the
  242.     * same method. This is a convenience method to reduce typing and ease
  243.     * porting from HTML_QuickForm.
  244.     *
  245.     * @param    string|HTML_QuickForm2_Node  Either type name (treated
  246.     *               case-insensitively) or an element instance
  247.     * @param    mixed   Element name
  248.     * @param    mixed   Element attributes
  249.     * @param    array   Element-specific data
  250.     * @return   HTML_QuickForm2_Node     Added element
  251.     * @throws   HTML_QuickForm2_InvalidArgumentException
  252.     * @throws   HTML_QuickForm2_NotFoundException
  253.     */
  254.     public function addElement($elementOrType, $name = null, $attributes = null,
  255.                                array $data = array())
  256.     {
  257.         if ($elementOrType instanceof HTML_QuickForm2_Node) {
  258.             return $this->appendChild($elementOrType);
  259.         } else {
  260.             return $this->appendChild(HTML_QuickForm2_Factory::createElement(
  261.                 $elementOrType, $name, $attributes, $data
  262.             ));
  263.         }
  264.     }
  265.  
  266.    /**
  267.     * Removes the element from this container
  268.     *
  269.     * If the reference object is not given, the element will be appended.
  270.     *
  271.     * @param    HTML_QuickForm2_Node     Element to remove
  272.     * @return   HTML_QuickForm2_Node     Removed object
  273.     */
  274.     public function removeChild(HTML_QuickForm2_Node $element)
  275.     {
  276.  
  277.         if ($element->getContainer() !== $this) {
  278.             throw new HTML_QuickForm2_NotFoundException(
  279.                 "Element with name '".$element->getName()."' was not found"
  280.             );
  281.         }
  282.         foreach ($this as $key => $child){
  283.             if ($child === $element) {
  284.                 unset($this->elements[$key]);
  285.                 $element->setContainer(null);
  286.                 break;
  287.             }
  288.         }
  289.         return $element;
  290.     }
  291.  
  292.  
  293.    /**
  294.     * Returns an element if its id is found
  295.     *
  296.     * @param    string  Element id to find
  297.     * @return   HTML_QuickForm2_Node|null
  298.     */
  299.     public function getElementById($id)
  300.     {
  301.         foreach ($this->getRecursiveIterator() as $element) {
  302.             if ($id == $element->getId()) {
  303.                 return $element;
  304.             }
  305.         }
  306.         return null;
  307.     }
  308.  
  309.    /**
  310.     * Returns an array of elements which name corresponds to element
  311.     *
  312.     * @param    string  Elements name to find
  313.     * @return   array
  314.     */
  315.     public function getElementsByName($name)
  316.     {
  317.         $found = array();
  318.         foreach ($this->getRecursiveIterator() as $element) {
  319.             if ($element->getName() == $name) {
  320.                 $found[] = $element;
  321.             }
  322.         }
  323.         return $found;
  324.     }
  325.  
  326.    /**
  327.     * Inserts an element in the container
  328.     *
  329.     * If the reference object is not given, the element will be appended.
  330.     *
  331.     * @param    HTML_QuickForm2_Node     Element to insert
  332.     * @param    HTML_QuickForm2_Node     Reference to insert before
  333.     * @return   HTML_QuickForm2_Node     Inserted element
  334.     */
  335.     public function insertBefore(HTML_QuickForm2_Node $element, HTML_QuickForm2_Node $reference = null)
  336.     {
  337.         if (null === $reference) {
  338.             return $this->appendChild($element);
  339.         }
  340.         $offset = 0;
  341.         foreach ($this as $child) {
  342.             if ($child === $reference) {
  343.                 if ($this === $element->getContainer()) {
  344.                     $this->removeChild($element);
  345.                 }
  346.                 $element->setContainer($this);
  347.                 array_splice($this->elements, $offset, 0, array($element));
  348.                 return $element;
  349.             }
  350.             $offset++;
  351.         }
  352.         throw new HTML_QuickForm2_NotFoundException(
  353.             "Reference element with name '".$reference->getName()."' was not found"
  354.         );
  355.     }
  356.  
  357.    /**
  358.     * Returns a recursive iterator for the container elements
  359.     *
  360.     * @return    HTML_QuickForm2_ContainerIterator
  361.     */
  362.     public function getIterator()
  363.     {
  364.         return new HTML_QuickForm2_ContainerIterator($this);
  365.     }
  366.  
  367.    /**
  368.     * Returns a recursive iterator iterator for the container elements
  369.     *
  370.     * @return    RecursiveIteratorIterator
  371.     */
  372.     public function getRecursiveIterator()
  373.     {
  374.         return new RecursiveIteratorIterator(
  375.                         new HTML_QuickForm2_ContainerIterator($this),
  376.                         RecursiveIteratorIterator::SELF_FIRST
  377.                     );
  378.     }
  379.  
  380.    /**
  381.     * Returns the number of elements in the container
  382.     *
  383.     * @return    int
  384.     */
  385.     public function count()
  386.     {
  387.         return count($this->elements);
  388.     }
  389.  
  390.    /**
  391.     * Called when the element needs to update its value from form's data sources
  392.     *
  393.     * The default behaviour is just to call the updateValue() methods of
  394.     * contained elements, since default Container doesn't have any value itself
  395.     */
  396.     protected function updateValue()
  397.     {
  398.         foreach ($this as $child) {
  399.             $child->updateValue();
  400.         }
  401.     }
  402.  
  403.  
  404.    /**
  405.     * Performs the server-side validation
  406.     *
  407.     * This method also calls validate() on all contained elements.
  408.     *
  409.     * @return   boolean Whether the container and all contained elements are valid
  410.     */
  411.     protected function validate()
  412.     {
  413.         $valid = parent::validate();
  414.         foreach ($this as $child) {
  415.             $valid = $child->validate() && $valid;
  416.         }
  417.         return $valid;
  418.     }
  419.  
  420.    /**
  421.     * Appends an element to the container, creating it first
  422.     *
  423.     * The element will be created via {@link HTML_QuickForm2_Factory::createElement()}
  424.     * and then added via the {@link appendChild()} method.
  425.     * The element type is deduced from the method name. Camelcases will be
  426.     * converted to underscores and lowercased.
  427.     * This is a convenience method to reduce typing.
  428.     *
  429.     * @param    mixed   Element name
  430.     * @param    mixed   Element attributes
  431.     * @param    array   Element-specific data
  432.     * @return   HTML_QuickForm2_Node     Added element
  433.     * @throws   HTML_QuickForm2_InvalidArgumentException
  434.     * @throws   HTML_QuickForm2_NotFoundException
  435.     */
  436.     public function __call($m, $a)
  437.     {
  438.         if (preg_match('/^(add)([a-zA-Z0-9_]+)$/', $m, $match)) {
  439.             if ($match[1] == 'add') {
  440.                 $type = strtolower($match[2]);
  441.                 $name = isset($a[0]) ? $a[0] : null;
  442.                 $attr = isset($a[1]) ? $a[1] : null;
  443.                 $data = isset($a[2]) ? $a[2] : array();
  444.                 return $this->addElement($type, $name, $attr, $data);
  445.             }
  446.         }
  447.         trigger_error("Fatal error: Call to undefined method ".get_class($this)."::".$m."()", E_USER_ERROR);
  448.     }
  449. }
  450.  
  451. /**
  452.  * Implements a recursive iterator for the container elements
  453.  *
  454.  * @category   HTML
  455.  * @package    HTML_QuickForm2
  456.  * @author     Alexey Borzov <avb@php.net>
  457.  * @author     Bertrand Mansion <golgote@mamasam.com>
  458.  * @version    Release: 0.2.0
  459.  */
  460. class HTML_QuickForm2_ContainerIterator extends RecursiveArrayIterator implements RecursiveIterator
  461. {
  462.     public function __construct(HTML_QuickForm2_Container $container)
  463.     {
  464.         parent::__construct($container->getElements());
  465.     }
  466.  
  467.     public function hasChildren()
  468.     {
  469.         return $this->current() instanceof HTML_QuickForm2_Container;
  470.     }
  471.  
  472.     public function getChildren()
  473.     {
  474.         return new HTML_QuickForm2_ContainerIterator($this->current());
  475.     }
  476. }
  477.  
  478. ?>