HTML_QuickForm2
[ class tree: HTML_QuickForm2 ] [ index: HTML_QuickForm2 ] [ all elements ]

Source for file Container.php

Documentation is available at Container.php

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

Documentation generated on Mon, 22 Oct 2007 12:30:12 -0400 by phpDocumentor 1.4.0. PEAR Logo Copyright © PHP Group 2004.