/libs/HTML/QuickForm2/Container.php
PHP | 487 lines | 242 code | 33 blank | 212 comment | 33 complexity | 907e655970384bc7761709412e756b25 MD5 | raw file
- <?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
- */
- public 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());
- }
- }
- ?>