--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/Zend/Navigation/Container.php Mon Dec 13 18:29:26 2010 +0100
@@ -0,0 +1,503 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category Zend
+ * @package Zend_Navigation
+ * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ * @version $Id: Container.php 20096 2010-01-06 02:05:09Z bkarwin $
+ */
+
+/**
+ * Zend_Navigation_Container
+ *
+ * Container class for Zend_Navigation_Page classes.
+ *
+ * @category Zend
+ * @package Zend_Navigation
+ * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+abstract class Zend_Navigation_Container implements RecursiveIterator, Countable
+{
+ /**
+ * Contains sub pages
+ *
+ * @var array
+ */
+ protected $_pages = array();
+
+ /**
+ * An index that contains the order in which to iterate pages
+ *
+ * @var array
+ */
+ protected $_index = array();
+
+ /**
+ * Whether index is dirty and needs to be re-arranged
+ *
+ * @var bool
+ */
+ protected $_dirtyIndex = false;
+
+ // Internal methods:
+
+ /**
+ * Sorts the page index according to page order
+ *
+ * @return void
+ */
+ protected function _sort()
+ {
+ if ($this->_dirtyIndex) {
+ $newIndex = array();
+ $index = 0;
+
+ foreach ($this->_pages as $hash => $page) {
+ $order = $page->getOrder();
+ if ($order === null) {
+ $newIndex[$hash] = $index;
+ $index++;
+ } else {
+ $newIndex[$hash] = $order;
+ }
+ }
+
+ asort($newIndex);
+ $this->_index = $newIndex;
+ $this->_dirtyIndex = false;
+ }
+ }
+
+ // Public methods:
+
+ /**
+ * Notifies container that the order of pages are updated
+ *
+ * @return void
+ */
+ public function notifyOrderUpdated()
+ {
+ $this->_dirtyIndex = true;
+ }
+
+ /**
+ * Adds a page to the container
+ *
+ * This method will inject the container as the given page's parent by
+ * calling {@link Zend_Navigation_Page::setParent()}.
+ *
+ * @param Zend_Navigation_Page|array|Zend_Config $page page to add
+ * @return Zend_Navigation_Container fluent interface,
+ * returns self
+ * @throws Zend_Navigation_Exception if page is invalid
+ */
+ public function addPage($page)
+ {
+ if ($page === $this) {
+ require_once 'Zend/Navigation/Exception.php';
+ throw new Zend_Navigation_Exception(
+ 'A page cannot have itself as a parent');
+ }
+
+ if (is_array($page) || $page instanceof Zend_Config) {
+ require_once 'Zend/Navigation/Page.php';
+ $page = Zend_Navigation_Page::factory($page);
+ } elseif (!$page instanceof Zend_Navigation_Page) {
+ require_once 'Zend/Navigation/Exception.php';
+ throw new Zend_Navigation_Exception(
+ 'Invalid argument: $page must be an instance of ' .
+ 'Zend_Navigation_Page or Zend_Config, or an array');
+ }
+
+ $hash = $page->hashCode();
+
+ if (array_key_exists($hash, $this->_index)) {
+ // page is already in container
+ return $this;
+ }
+
+ // adds page to container and sets dirty flag
+ $this->_pages[$hash] = $page;
+ $this->_index[$hash] = $page->getOrder();
+ $this->_dirtyIndex = true;
+
+ // inject self as page parent
+ $page->setParent($this);
+
+ return $this;
+ }
+
+ /**
+ * Adds several pages at once
+ *
+ * @param array|Zend_Config $pages pages to add
+ * @return Zend_Navigation_Container fluent interface, returns self
+ * @throws Zend_Navigation_Exception if $pages is not array or Zend_Config
+ */
+ public function addPages($pages)
+ {
+ if ($pages instanceof Zend_Config) {
+ $pages = $pages->toArray();
+ }
+
+ if (!is_array($pages)) {
+ require_once 'Zend/Navigation/Exception.php';
+ throw new Zend_Navigation_Exception(
+ 'Invalid argument: $pages must be an array or an ' .
+ 'instance of Zend_Config');
+ }
+
+ foreach ($pages as $page) {
+ $this->addPage($page);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Sets pages this container should have, removing existing pages
+ *
+ * @param array $pages pages to set
+ * @return Zend_Navigation_Container fluent interface, returns self
+ */
+ public function setPages(array $pages)
+ {
+ $this->removePages();
+ return $this->addPages($pages);
+ }
+
+ /**
+ * Returns pages in the container
+ *
+ * @return array array of Zend_Navigation_Page instances
+ */
+ public function getPages()
+ {
+ return $this->_pages;
+ }
+
+ /**
+ * Removes the given page from the container
+ *
+ * @param Zend_Navigation_Page|int $page page to remove, either a page
+ * instance or a specific page order
+ * @return bool whether the removal was
+ * successful
+ */
+ public function removePage($page)
+ {
+ if ($page instanceof Zend_Navigation_Page) {
+ $hash = $page->hashCode();
+ } elseif (is_int($page)) {
+ $this->_sort();
+ if (!$hash = array_search($page, $this->_index)) {
+ return false;
+ }
+ } else {
+ return false;
+ }
+
+ if (isset($this->_pages[$hash])) {
+ unset($this->_pages[$hash]);
+ unset($this->_index[$hash]);
+ $this->_dirtyIndex = true;
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Removes all pages in container
+ *
+ * @return Zend_Navigation_Container fluent interface, returns self
+ */
+ public function removePages()
+ {
+ $this->_pages = array();
+ $this->_index = array();
+ return $this;
+ }
+
+ /**
+ * Checks if the container has the given page
+ *
+ * @param Zend_Navigation_Page $page page to look for
+ * @param bool $recursive [optional] whether to search
+ * recursively. Default is false.
+ * @return bool whether page is in container
+ */
+ public function hasPage(Zend_Navigation_Page $page, $recursive = false)
+ {
+ if (array_key_exists($page->hashCode(), $this->_index)) {
+ return true;
+ } elseif ($recursive) {
+ foreach ($this->_pages as $childPage) {
+ if ($childPage->hasPage($page, true)) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Returns true if container contains any pages
+ *
+ * @return bool whether container has any pages
+ */
+ public function hasPages()
+ {
+ return count($this->_index) > 0;
+ }
+
+ /**
+ * Returns a child page matching $property == $value, or null if not found
+ *
+ * @param string $property name of property to match against
+ * @param mixed $value value to match property against
+ * @return Zend_Navigation_Page|null matching page or null
+ */
+ public function findOneBy($property, $value)
+ {
+ $iterator = new RecursiveIteratorIterator($this,
+ RecursiveIteratorIterator::SELF_FIRST);
+
+ foreach ($iterator as $page) {
+ if ($page->get($property) == $value) {
+ return $page;
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns all child pages matching $property == $value, or an empty array
+ * if no pages are found
+ *
+ * @param string $property name of property to match against
+ * @param mixed $value value to match property against
+ * @return array array containing only Zend_Navigation_Page
+ * instances
+ */
+ public function findAllBy($property, $value)
+ {
+ $found = array();
+
+ $iterator = new RecursiveIteratorIterator($this,
+ RecursiveIteratorIterator::SELF_FIRST);
+
+ foreach ($iterator as $page) {
+ if ($page->get($property) == $value) {
+ $found[] = $page;
+ }
+ }
+
+ return $found;
+ }
+
+ /**
+ * Returns page(s) matching $property == $value
+ *
+ * @param string $property name of property to match against
+ * @param mixed $value value to match property against
+ * @param bool $all [optional] whether an array of all matching
+ * pages should be returned, or only the first.
+ * If true, an array will be returned, even if not
+ * matching pages are found. If false, null will
+ * be returned if no matching page is found.
+ * Default is false.
+ * @return Zend_Navigation_Page|null matching page or null
+ */
+ public function findBy($property, $value, $all = false)
+ {
+ if ($all) {
+ return $this->findAllBy($property, $value);
+ } else {
+ return $this->findOneBy($property, $value);
+ }
+ }
+
+ /**
+ * Magic overload: Proxy calls to finder methods
+ *
+ * Examples of finder calls:
+ * <code>
+ * // METHOD // SAME AS
+ * $nav->findByLabel('foo'); // $nav->findOneBy('label', 'foo');
+ * $nav->findOneByLabel('foo'); // $nav->findOneBy('label', 'foo');
+ * $nav->findAllByClass('foo'); // $nav->findAllBy('class', 'foo');
+ * </code>
+ *
+ * @param string $method method name
+ * @param array $arguments method arguments
+ * @throws Zend_Navigation_Exception if method does not exist
+ */
+ public function __call($method, $arguments)
+ {
+ if (@preg_match('/(find(?:One|All)?By)(.+)/', $method, $match)) {
+ return $this->{$match[1]}($match[2], $arguments[0]);
+ }
+
+ require_once 'Zend/Navigation/Exception.php';
+ throw new Zend_Navigation_Exception(sprintf(
+ 'Bad method call: Unknown method %s::%s',
+ get_class($this),
+ $method));
+ }
+
+ /**
+ * Returns an array representation of all pages in container
+ *
+ * @return array
+ */
+ public function toArray()
+ {
+ $pages = array();
+
+ $this->_dirtyIndex = true;
+ $this->_sort();
+ $indexes = array_keys($this->_index);
+ foreach ($indexes as $hash) {
+ $pages[] = $this->_pages[$hash]->toArray();
+ }
+ return $pages;
+ }
+
+ // RecursiveIterator interface:
+
+ /**
+ * Returns current page
+ *
+ * Implements RecursiveIterator interface.
+ *
+ * @return Zend_Navigation_Page current page or null
+ * @throws Zend_Navigation_Exception if the index is invalid
+ */
+ public function current()
+ {
+ $this->_sort();
+ current($this->_index);
+ $hash = key($this->_index);
+
+ if (isset($this->_pages[$hash])) {
+ return $this->_pages[$hash];
+ } else {
+ require_once 'Zend/Navigation/Exception.php';
+ throw new Zend_Navigation_Exception(
+ 'Corruption detected in container; ' .
+ 'invalid key found in internal iterator');
+ }
+ }
+
+ /**
+ * Returns hash code of current page
+ *
+ * Implements RecursiveIterator interface.
+ *
+ * @return string hash code of current page
+ */
+ public function key()
+ {
+ $this->_sort();
+ return key($this->_index);
+ }
+
+ /**
+ * Moves index pointer to next page in the container
+ *
+ * Implements RecursiveIterator interface.
+ *
+ * @return void
+ */
+ public function next()
+ {
+ $this->_sort();
+ next($this->_index);
+ }
+
+ /**
+ * Sets index pointer to first page in the container
+ *
+ * Implements RecursiveIterator interface.
+ *
+ * @return void
+ */
+ public function rewind()
+ {
+ $this->_sort();
+ reset($this->_index);
+ }
+
+ /**
+ * Checks if container index is valid
+ *
+ * Implements RecursiveIterator interface.
+ *
+ * @return bool
+ */
+ public function valid()
+ {
+ $this->_sort();
+ return current($this->_index) !== false;
+ }
+
+ /**
+ * Proxy to hasPages()
+ *
+ * Implements RecursiveIterator interface.
+ *
+ * @return bool whether container has any pages
+ */
+ public function hasChildren()
+ {
+ return $this->hasPages();
+ }
+
+ /**
+ * Returns the child container.
+ *
+ * Implements RecursiveIterator interface.
+ *
+ * @return Zend_Navigation_Page|null
+ */
+ public function getChildren()
+ {
+ $hash = key($this->_index);
+
+ if (isset($this->_pages[$hash])) {
+ return $this->_pages[$hash];
+ }
+
+ return null;
+ }
+
+ // Countable interface:
+
+ /**
+ * Returns number of pages in container
+ *
+ * Implements Countable interface.
+ *
+ * @return int number of pages in the container
+ */
+ public function count()
+ {
+ return count($this->_index);
+ }
+}