PageRenderTime 58ms CodeModel.GetById 20ms app.highlight 28ms RepoModel.GetById 1ms app.codeStats 1ms

/Zend/Navigation/Page.php

http://grupal.googlecode.com/
PHP | 1367 lines | 593 code | 147 blank | 627 comment | 96 complexity | 368dd17cb2ea96299d7a5517781333df MD5 | raw file
   1<?php
   2/**
   3 * Zend Framework
   4 *
   5 * LICENSE
   6 *
   7 * This source file is subject to the new BSD license that is bundled
   8 * with this package in the file LICENSE.txt.
   9 * It is also available through the world-wide-web at this URL:
  10 * http://framework.zend.com/license/new-bsd
  11 * If you did not receive a copy of the license and are unable to
  12 * obtain it through the world-wide-web, please send an email
  13 * to license@zend.com so we can send you a copy immediately.
  14 *
  15 * @category  Zend
  16 * @package   Zend_Navigation
  17 * @copyright  Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
  18 * @license   http://framework.zend.com/license/new-bsd     New BSD License
  19 * @version    $Id: Page.php 25124 2012-11-16 15:07:38Z rob $
  20 */
  21
  22/**
  23 * @see Zend_Navigation_Container
  24 */
  25require_once 'Zend/Navigation/Container.php';
  26
  27/**
  28 * Base class for Zend_Navigation_Page pages
  29 *
  30 * @category  Zend
  31 * @package   Zend_Navigation
  32 * @copyright  Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
  33 * @license   http://framework.zend.com/license/new-bsd     New BSD License
  34 */
  35abstract class Zend_Navigation_Page extends Zend_Navigation_Container
  36{
  37    /**
  38     * Page label
  39     *
  40     * @var string|null
  41     */
  42    protected $_label;
  43
  44    /**
  45     * Fragment identifier (anchor identifier)
  46     * 
  47     * The fragment identifier (anchor identifier) pointing to an anchor within 
  48     * a resource that is subordinate to another, primary resource.
  49     * The fragment identifier introduced by a hash mark "#".
  50     * Example: http://www.example.org/foo.html#bar ("bar" is the fragment identifier)
  51     * 
  52     * @link http://www.w3.org/TR/html401/intro/intro.html#fragment-uri
  53     * 
  54     * @var string|null
  55     */
  56    protected $_fragment;
  57
  58    /**
  59     * Page id
  60     *
  61     * @var string|null
  62     */
  63    protected $_id;
  64
  65    /**
  66     * Style class for this page (CSS)
  67     *
  68     * @var string|null
  69     */
  70    protected $_class;
  71
  72    /**
  73     * A more descriptive title for this page
  74     *
  75     * @var string|null
  76     */
  77    protected $_title;
  78
  79    /**
  80     * This page's target
  81     *
  82     * @var string|null
  83     */
  84    protected $_target;
  85
  86    /**
  87     * Accessibility key character
  88     *
  89     * This attribute assigns an access key to an element. An access key is a
  90     * single character from the document character set.
  91     *
  92     * @link http://www.w3.org/TR/html401/interact/forms.html#access-keys
  93     *
  94     * @var string|null
  95     */
  96    protected $_accesskey;
  97
  98    /**
  99     * Forward links to other pages
 100     *
 101     * @link http://www.w3.org/TR/html4/struct/links.html#h-12.3.1
 102     *
 103     * @var array
 104     */
 105    protected $_rel = array();
 106
 107    /**
 108     * Reverse links to other pages
 109     *
 110     * @link http://www.w3.org/TR/html4/struct/links.html#h-12.3.1
 111     *
 112     * @var array
 113     */
 114    protected $_rev = array();
 115
 116    /**
 117     * Page order used by parent container
 118     *
 119     * @var int|null
 120     */
 121    protected $_order;
 122
 123    /**
 124     * ACL resource associated with this page
 125     *
 126     * @var string|Zend_Acl_Resource_Interface|null
 127     */
 128    protected $_resource;
 129
 130    /**
 131     * ACL privilege associated with this page
 132     *
 133     * @var string|null
 134     */
 135    protected $_privilege;
 136
 137    /**
 138     * Whether this page should be considered active
 139     *
 140     * @var bool
 141     */
 142    protected $_active = false;
 143
 144    /**
 145     * Whether this page should be considered visible
 146     *
 147     * @var bool
 148     */
 149    protected $_visible = true;
 150
 151    /**
 152     * Parent container
 153     *
 154     * @var Zend_Navigation_Container|null
 155     */
 156    protected $_parent;
 157
 158    /**
 159     * Custom page properties, used by __set(), __get() and __isset()
 160     *
 161     * @var array
 162     */
 163    protected $_properties = array();
 164
 165    /**
 166     * Custom HTML attributes
 167     *
 168     * @var array
 169     */
 170    protected $_customHtmlAttribs = array();
 171
 172    /**
 173     * The type of page to use when it wasn't set
 174     *
 175     * @var string
 176     */
 177    protected static $_defaultPageType;
 178
 179    // Initialization:
 180
 181    /**
 182     * Factory for Zend_Navigation_Page classes
 183     *
 184     * A specific type to construct can be specified by specifying the key
 185     * 'type' in $options. If type is 'uri' or 'mvc', the type will be resolved
 186     * to Zend_Navigation_Page_Uri or Zend_Navigation_Page_Mvc. Any other value
 187     * for 'type' will be considered the full name of the class to construct.
 188     * A valid custom page class must extend Zend_Navigation_Page.
 189     *
 190     * If 'type' is not given, the type of page to construct will be determined
 191     * by the following rules:
 192     * - If $options contains either of the keys 'action', 'controller',
 193     *   'module', or 'route', a Zend_Navigation_Page_Mvc page will be created.
 194     * - If $options contains the key 'uri', a Zend_Navigation_Page_Uri page
 195     *   will be created.
 196     *
 197     * @param  array|Zend_Config $options  options used for creating page
 198     * @return Zend_Navigation_Page        a page instance
 199     * @throws Zend_Navigation_Exception   if $options is not array/Zend_Config
 200     * @throws Zend_Exception              if 'type' is specified and
 201     *                                     Zend_Loader is unable to load the
 202     *                                     class
 203     * @throws Zend_Navigation_Exception   if something goes wrong during
 204     *                                     instantiation of the page
 205     * @throws Zend_Navigation_Exception   if 'type' is given, and the specified
 206     *                                     type does not extend this class
 207     * @throws Zend_Navigation_Exception   if unable to determine which class
 208     *                                     to instantiate
 209     */
 210    public static function factory($options)
 211    {
 212        if ($options instanceof Zend_Config) {
 213            $options = $options->toArray();
 214        }
 215
 216        if (!is_array($options)) {
 217            require_once 'Zend/Navigation/Exception.php';
 218            throw new Zend_Navigation_Exception(
 219                'Invalid argument: $options must be an array or Zend_Config');
 220        }
 221
 222        if (isset($options['type'])) {
 223            $type = $options['type'];
 224        } elseif(self::getDefaultPageType()!= null) {
 225            $type = self::getDefaultPageType();
 226        }
 227
 228        if(isset($type)) {
 229            if (is_string($type) && !empty($type)) {
 230                switch (strtolower($type)) {
 231                    case 'mvc':
 232                        $type = 'Zend_Navigation_Page_Mvc';
 233                        break;
 234                    case 'uri':
 235                        $type = 'Zend_Navigation_Page_Uri';
 236                        break;
 237                }
 238
 239                if (!class_exists($type)) {
 240                    require_once 'Zend/Loader.php';
 241                    @Zend_Loader::loadClass($type);
 242                }
 243
 244                $page = new $type($options);
 245                if (!$page instanceof Zend_Navigation_Page) {
 246                    require_once 'Zend/Navigation/Exception.php';
 247                    throw new Zend_Navigation_Exception(sprintf(
 248                            'Invalid argument: Detected type "%s", which ' .
 249                            'is not an instance of Zend_Navigation_Page',
 250                            $type));
 251                }
 252                return $page;
 253            }
 254        }
 255
 256        $hasUri = isset($options['uri']);
 257        $hasMvc = isset($options['action']) || isset($options['controller']) ||
 258                  isset($options['module']) || isset($options['route']) ||
 259                  isset($options['params']);
 260
 261        if ($hasMvc) {
 262            require_once 'Zend/Navigation/Page/Mvc.php';
 263            return new Zend_Navigation_Page_Mvc($options);
 264        } elseif ($hasUri) {
 265            require_once 'Zend/Navigation/Page/Uri.php';
 266            return new Zend_Navigation_Page_Uri($options);
 267        } else {
 268            require_once 'Zend/Navigation/Exception.php';
 269            
 270            $message = 'Invalid argument: Unable to determine class to instantiate';
 271            if (isset($options['label'])) {
 272                $message .= ' (Page label: ' . $options['label'] . ')';
 273        }
 274            
 275            throw new Zend_Navigation_Exception($message);
 276    }
 277    }
 278
 279    /**
 280     * Page constructor
 281     *
 282     * @param  array|Zend_Config $options   [optional] page options. Default is
 283     *                                      null, which should set defaults.
 284     * @throws Zend_Navigation_Exception    if invalid options are given
 285     */
 286    public function __construct($options = null)
 287    {
 288        if (is_array($options)) {
 289            $this->setOptions($options);
 290        } elseif ($options instanceof Zend_Config) {
 291            $this->setConfig($options);
 292        }
 293
 294        // do custom initialization
 295        $this->_init();
 296    }
 297
 298    /**
 299     * Initializes page (used by subclasses)
 300     *
 301     * @return void
 302     */
 303    protected function _init()
 304    {
 305    }
 306
 307    /**
 308     * Sets page properties using a Zend_Config object
 309     *
 310     * @param  Zend_Config $config        config object to get properties from
 311     * @return Zend_Navigation_Page       fluent interface, returns self
 312     * @throws Zend_Navigation_Exception  if invalid options are given
 313     */
 314    public function setConfig(Zend_Config $config)
 315    {
 316        return $this->setOptions($config->toArray());
 317    }
 318
 319    /**
 320     * Sets page properties using options from an associative array
 321     *
 322     * Each key in the array corresponds to the according set*() method, and
 323     * each word is separated by underscores, e.g. the option 'target'
 324     * corresponds to setTarget(), and the option 'reset_params' corresponds to
 325     * the method setResetParams().
 326     *
 327     * @param  array $options             associative array of options to set
 328     * @return Zend_Navigation_Page       fluent interface, returns self
 329     * @throws Zend_Navigation_Exception  if invalid options are given
 330     */
 331    public function setOptions(array $options)
 332    {
 333        foreach ($options as $key => $value) {
 334            $this->set($key, $value);
 335        }
 336
 337        return $this;
 338    }
 339
 340    // Accessors:
 341
 342    /**
 343     * Sets page label
 344     *
 345     * @param  string $label              new page label
 346     * @return Zend_Navigation_Page       fluent interface, returns self
 347     * @throws Zend_Navigation_Exception  if empty/no string is given
 348     */
 349    public function setLabel($label)
 350    {
 351        if (null !== $label && !is_string($label)) {
 352            require_once 'Zend/Navigation/Exception.php';
 353            throw new Zend_Navigation_Exception(
 354                    'Invalid argument: $label must be a string or null');
 355        }
 356
 357        $this->_label = $label;
 358        return $this;
 359    }
 360
 361    /**
 362     * Returns page label
 363     *
 364     * @return string  page label or null
 365     */
 366    public function getLabel()
 367    {
 368        return $this->_label;
 369    }
 370
 371    /**
 372     * Sets a fragment identifier
 373     *
 374     * @param  string $fragment   new fragment identifier
 375     * @return Zend_Navigation_Page         fluent interface, returns self
 376     * @throws Zend_Navigation_Exception    if empty/no string is given
 377     */
 378    public function setFragment($fragment)
 379    {
 380        if (null !== $fragment && !is_string($fragment)) {
 381            require_once 'Zend/Navigation/Exception.php';
 382            throw new Zend_Navigation_Exception(
 383                    'Invalid argument: $fragment must be a string or null');
 384        }
 385 
 386        $this->_fragment = $fragment;
 387        return $this;
 388    }
 389    
 390     /**
 391     * Returns fragment identifier
 392     *
 393     * @return string|null  fragment identifier
 394     */
 395    public function getFragment()
 396    {
 397        return $this->_fragment;
 398    }
 399
 400    /**
 401     * Sets page id
 402     *
 403     * @param  string|null $id            [optional] id to set. Default is null,
 404     *                                    which sets no id.
 405     * @return Zend_Navigation_Page       fluent interface, returns self
 406     * @throws Zend_Navigation_Exception  if not given string or null
 407     */
 408    public function setId($id = null)
 409    {
 410        if (null !== $id && !is_string($id) && !is_numeric($id)) {
 411            require_once 'Zend/Navigation/Exception.php';
 412            throw new Zend_Navigation_Exception(
 413                    'Invalid argument: $id must be a string, number or null');
 414        }
 415
 416        $this->_id = null === $id ? $id : (string) $id;
 417
 418        return $this;
 419    }
 420
 421    /**
 422     * Returns page id
 423     *
 424     * @return string|null  page id or null
 425     */
 426    public function getId()
 427    {
 428        return $this->_id;
 429    }
 430
 431    /**
 432     * Sets page CSS class
 433     *
 434     * @param  string|null $class         [optional] CSS class to set. Default
 435     *                                    is null, which sets no CSS class.
 436     * @return Zend_Navigation_Page       fluent interface, returns self
 437     * @throws Zend_Navigation_Exception  if not given string or null
 438     */
 439    public function setClass($class = null)
 440    {
 441        if (null !== $class && !is_string($class)) {
 442            require_once 'Zend/Navigation/Exception.php';
 443            throw new Zend_Navigation_Exception(
 444                    'Invalid argument: $class must be a string or null');
 445        }
 446
 447        $this->_class = $class;
 448        return $this;
 449    }
 450
 451    /**
 452     * Returns page class (CSS)
 453     *
 454     * @return string|null  page's CSS class or null
 455     */
 456    public function getClass()
 457    {
 458        return $this->_class;
 459    }
 460
 461    /**
 462     * Sets page title
 463     *
 464     * @param  string $title              [optional] page title. Default is
 465     *                                    null, which sets no title.
 466     * @return Zend_Navigation_Page       fluent interface, returns self
 467     * @throws Zend_Navigation_Exception  if not given string or null
 468     */
 469    public function setTitle($title = null)
 470    {
 471        if (null !== $title && !is_string($title)) {
 472            require_once 'Zend/Navigation/Exception.php';
 473            throw new Zend_Navigation_Exception(
 474                    'Invalid argument: $title must be a non-empty string');
 475        }
 476
 477        $this->_title = $title;
 478        return $this;
 479    }
 480
 481    /**
 482     * Returns page title
 483     *
 484     * @return string|null  page title or null
 485     */
 486    public function getTitle()
 487    {
 488        return $this->_title;
 489    }
 490
 491    /**
 492     * Sets page target
 493     *
 494     * @param  string|null $target        [optional] target to set. Default is
 495     *                                    null, which sets no target.
 496     * @return Zend_Navigation_Page       fluent interface, returns self
 497     * @throws Zend_Navigation_Exception  if target is not string or null
 498     */
 499    public function setTarget($target = null)
 500    {
 501        if (null !== $target && !is_string($target)) {
 502            require_once 'Zend/Navigation/Exception.php';
 503            throw new Zend_Navigation_Exception(
 504                    'Invalid argument: $target must be a string or null');
 505        }
 506
 507        $this->_target = $target;
 508        return $this;
 509    }
 510
 511    /**
 512     * Returns page target
 513     *
 514     * @return string|null  page target or null
 515     */
 516    public function getTarget()
 517    {
 518        return $this->_target;
 519    }
 520
 521    /**
 522     * Sets access key for this page
 523     *
 524     * @param  string|null $character     [optional] access key to set. Default
 525     *                                    is null, which sets no access key.
 526     * @return Zend_Navigation_Page       fluent interface, returns self
 527     * @throws Zend_Navigation_Exception  if access key is not string or null or
 528     *                                    if the string length not equal to one
 529     */
 530    public function setAccesskey($character = null)
 531    {
 532        if (null !== $character
 533            && (!is_string($character) || 1 != strlen($character)))
 534        {
 535            require_once 'Zend/Navigation/Exception.php';
 536            throw new Zend_Navigation_Exception(
 537                'Invalid argument: $character must be a single character or null'
 538            );
 539        }
 540 
 541        $this->_accesskey = $character;
 542        return $this;
 543    }
 544
 545     /**
 546     * Returns page access key
 547     *
 548     * @return string|null  page access key or null
 549     */
 550    public function getAccesskey()
 551    {
 552        return $this->_accesskey;
 553    }
 554
 555    /**
 556     * Sets the page's forward links to other pages
 557     *
 558     * This method expects an associative array of forward links to other pages,
 559     * where each element's key is the name of the relation (e.g. alternate,
 560     * prev, next, help, etc), and the value is a mixed value that could somehow
 561     * be considered a page.
 562     *
 563     * @param  array|Zend_Config $relations  [optional] an associative array of
 564     *                                       forward links to other pages
 565     * @return Zend_Navigation_Page          fluent interface, returns self
 566     */
 567    public function setRel($relations = null)
 568    {
 569        $this->_rel = array();
 570
 571        if (null !== $relations) {
 572            if ($relations instanceof Zend_Config) {
 573                $relations = $relations->toArray();
 574            }
 575
 576            if (!is_array($relations)) {
 577                require_once 'Zend/Navigation/Exception.php';
 578                throw new Zend_Navigation_Exception(
 579                        'Invalid argument: $relations must be an ' .
 580                        'array or an instance of Zend_Config');
 581            }
 582
 583            foreach ($relations as $name => $relation) {
 584                if (is_string($name)) {
 585                    $this->_rel[$name] = $relation;
 586                }
 587            }
 588        }
 589
 590        return $this;
 591    }
 592
 593    /**
 594     * Returns the page's forward links to other pages
 595     *
 596     * This method returns an associative array of forward links to other pages,
 597     * where each element's key is the name of the relation (e.g. alternate,
 598     * prev, next, help, etc), and the value is a mixed value that could somehow
 599     * be considered a page.
 600     *
 601     * @param  string $relation  [optional] name of relation to return. If not
 602     *                           given, all relations will be returned.
 603     * @return array             an array of relations. If $relation is not
 604     *                           specified, all relations will be returned in
 605     *                           an associative array.
 606     */
 607    public function getRel($relation = null)
 608    {
 609        if (null !== $relation) {
 610            return isset($this->_rel[$relation]) ?
 611                   $this->_rel[$relation] :
 612                   null;
 613        }
 614
 615        return $this->_rel;
 616    }
 617
 618    /**
 619     * Sets the page's reverse links to other pages
 620     *
 621     * This method expects an associative array of reverse links to other pages,
 622     * where each element's key is the name of the relation (e.g. alternate,
 623     * prev, next, help, etc), and the value is a mixed value that could somehow
 624     * be considered a page.
 625     *
 626     * @param  array|Zend_Config $relations  [optional] an associative array of
 627     *                                       reverse links to other pages
 628     * @return Zend_Navigation_Page          fluent interface, returns self
 629     */
 630    public function setRev($relations = null)
 631    {
 632        $this->_rev = array();
 633
 634        if (null !== $relations) {
 635            if ($relations instanceof Zend_Config) {
 636                $relations = $relations->toArray();
 637            }
 638
 639            if (!is_array($relations)) {
 640                require_once 'Zend/Navigation/Exception.php';
 641                throw new Zend_Navigation_Exception(
 642                        'Invalid argument: $relations must be an ' .
 643                        'array or an instance of Zend_Config');
 644            }
 645
 646            foreach ($relations as $name => $relation) {
 647                if (is_string($name)) {
 648                    $this->_rev[$name] = $relation;
 649                }
 650            }
 651        }
 652
 653        return $this;
 654    }
 655
 656    /**
 657     * Returns the page's reverse links to other pages
 658     *
 659     * This method returns an associative array of forward links to other pages,
 660     * where each element's key is the name of the relation (e.g. alternate,
 661     * prev, next, help, etc), and the value is a mixed value that could somehow
 662     * be considered a page.
 663     *
 664     * @param  string $relation  [optional] name of relation to return. If not
 665     *                           given, all relations will be returned.
 666     * @return array             an array of relations. If $relation is not
 667     *                           specified, all relations will be returned in
 668     *                           an associative array.
 669     */
 670    public function getRev($relation = null)
 671    {
 672        if (null !== $relation) {
 673            return isset($this->_rev[$relation]) ?
 674                   $this->_rev[$relation] :
 675                   null;
 676        }
 677
 678        return $this->_rev;
 679    }
 680
 681    /**
 682     * Sets a single custom HTML attribute
 683     *
 684     * @param  string      $name            name of the HTML attribute
 685     * @param  string|null $value           value for the HTML attribute
 686     * @return Zend_Navigation_Page         fluent interface, returns self
 687     * @throws Zend_Navigation_Exception    if name is not string or value is
 688     *                                      not null or a string
 689     */
 690    public function setCustomHtmlAttrib($name, $value)
 691    {
 692        if (!is_string($name)) {
 693            require_once 'Zend/Navigation/Exception.php';
 694            throw new Zend_Navigation_Exception(
 695                'Invalid argument: $name must be a string'
 696            );
 697        }
 698
 699        if (null !== $value && !is_string($value)) {
 700            require_once 'Zend/Navigation/Exception.php';
 701            throw new Zend_Navigation_Exception(
 702                'Invalid argument: $value must be a string or null'
 703            );
 704        }
 705
 706        if (null === $value && isset($this->_customHtmlAttribs[$name])) {
 707            unset($this->_customHtmlAttribs[$name]);
 708        } else {
 709            $this->_customHtmlAttribs[$name] = $value;
 710        }
 711
 712        return $this;
 713    }
 714
 715    /**
 716     * Returns a single custom HTML attributes by name
 717     *
 718     * @param  string $name                 name of the HTML attribute
 719     * @return string|null                  value for the HTML attribute or null
 720     * @throws Zend_Navigation_Exception    if name is not string
 721     */
 722    public function getCustomHtmlAttrib($name)
 723    {
 724        if (!is_string($name)) {
 725            require_once 'Zend/Navigation/Exception.php';
 726            throw new Zend_Navigation_Exception(
 727                'Invalid argument: $name must be a string'
 728            );
 729        }
 730
 731        if (isset($this->_customHtmlAttribs[$name])) {
 732            return $this->_customHtmlAttribs[$name];
 733        }
 734
 735        return null;
 736    }
 737
 738    /**
 739     * Sets multiple custom HTML attributes at once
 740     *
 741     * @param array $attribs        an associative array of html attributes
 742     * @return Zend_Navigation_Page fluent interface, returns self
 743     */
 744    public function setCustomHtmlAttribs(array $attribs)
 745    {
 746        foreach ($attribs as $key => $value) {
 747            $this->setCustomHtmlAttrib($key, $value);
 748        }
 749        return $this;
 750    }
 751
 752    /**
 753     * Returns all custom HTML attributes as an array
 754     *
 755     * @return array    an array containing custom HTML attributes
 756     */
 757    public function getCustomHtmlAttribs()
 758    {
 759        return $this->_customHtmlAttribs;
 760    }
 761
 762    /**
 763     * Removes a custom HTML attribute from the page
 764     *
 765     * @param  string $name          name of the custom HTML attribute
 766     * @return Zend_Navigation_Page  fluent interface, returns self
 767     */
 768    public function removeCustomHtmlAttrib($name)
 769    {
 770        if (!is_string($name)) {
 771            require_once 'Zend/Navigation/Exception.php';
 772            throw new Zend_Navigation_Exception(
 773                'Invalid argument: $name must be a string'
 774            );
 775        }
 776
 777        if (isset($this->_customHtmlAttribs[$name])) {
 778            unset($this->_customHtmlAttribs[$name]);
 779        }
 780    }
 781
 782    /**
 783     * Clear all custom HTML attributes
 784     *
 785     * @return Zend_Navigation_Page fluent interface, returns self
 786     */
 787    public function clearCustomHtmlAttribs()
 788    {
 789        $this->_customHtmlAttribs = array();
 790
 791        return $this;
 792    }
 793
 794    /**
 795     * Sets page order to use in parent container
 796     *
 797     * @param  int $order                 [optional] page order in container.
 798     *                                    Default is null, which sets no
 799     *                                    specific order.
 800     * @return Zend_Navigation_Page       fluent interface, returns self
 801     * @throws Zend_Navigation_Exception  if order is not integer or null
 802     */
 803    public function setOrder($order = null)
 804    {
 805        if (is_string($order)) {
 806            $temp = (int) $order;
 807            if ($temp < 0 || $temp > 0 || $order == '0') {
 808                $order = $temp;
 809            }
 810        }
 811
 812        if (null !== $order && !is_int($order)) {
 813            require_once 'Zend/Navigation/Exception.php';
 814            throw new Zend_Navigation_Exception(
 815                    'Invalid argument: $order must be an integer or null, ' .
 816                    'or a string that casts to an integer');
 817        }
 818
 819        $this->_order = $order;
 820
 821        // notify parent, if any
 822        if (isset($this->_parent)) {
 823            $this->_parent->notifyOrderUpdated();
 824        }
 825
 826        return $this;
 827    }
 828
 829    /**
 830     * Returns page order used in parent container
 831     *
 832     * @return int|null  page order or null
 833     */
 834    public function getOrder()
 835    {
 836        return $this->_order;
 837    }
 838
 839    /**
 840     * Sets ACL resource assoicated with this page
 841     *
 842     * @param  string|Zend_Acl_Resource_Interface $resource  [optional] resource
 843     *                                                       to associate with
 844     *                                                       page. Default is
 845     *                                                       null, which sets no
 846     *                                                       resource.
 847     * @throws Zend_Navigation_Exception                     if $resource if
 848     *                                                       invalid
 849     * @return Zend_Navigation_Page                          fluent interface,
 850     *                                                       returns self
 851     */
 852    public function setResource($resource = null)
 853    {
 854        if (null === $resource || is_string($resource) ||
 855            $resource instanceof Zend_Acl_Resource_Interface) {
 856            $this->_resource = $resource;
 857        } else {
 858            require_once 'Zend/Navigation/Exception.php';
 859            throw new Zend_Navigation_Exception(
 860                    'Invalid argument: $resource must be null, a string, ' .
 861                    ' or an instance of Zend_Acl_Resource_Interface');
 862        }
 863
 864        return $this;
 865    }
 866
 867    /**
 868     * Returns ACL resource assoicated with this page
 869     *
 870     * @return string|Zend_Acl_Resource_Interface|null  ACL resource or null
 871     */
 872    public function getResource()
 873    {
 874        return $this->_resource;
 875    }
 876
 877    /**
 878     * Sets ACL privilege associated with this page
 879     *
 880     * @param  string|null $privilege  [optional] ACL privilege to associate
 881     *                                 with this page. Default is null, which
 882     *                                 sets no privilege.
 883     * @return Zend_Navigation_Page    fluent interface, returns self
 884     */
 885    public function setPrivilege($privilege = null)
 886    {
 887        $this->_privilege = is_string($privilege) ? $privilege : null;
 888        return $this;
 889    }
 890
 891    /**
 892     * Returns ACL privilege associated with this page
 893     *
 894     * @return string|null  ACL privilege or null
 895     */
 896    public function getPrivilege()
 897    {
 898        return $this->_privilege;
 899    }
 900
 901    /**
 902     * Sets whether page should be considered active or not
 903     *
 904     * @param  bool $active          [optional] whether page should be
 905     *                               considered active or not. Default is true.
 906     * @return Zend_Navigation_Page  fluent interface, returns self
 907     */
 908    public function setActive($active = true)
 909    {
 910        $this->_active = (bool) $active;
 911        return $this;
 912    }
 913
 914    /**
 915     * Returns whether page should be considered active or not
 916     *
 917     * @param  bool $recursive  [optional] whether page should be considered
 918     *                          active if any child pages are active. Default is
 919     *                          false.
 920     * @return bool             whether page should be considered active
 921     */
 922    public function isActive($recursive = false)
 923    {
 924        if (!$this->_active && $recursive) {
 925            foreach ($this->_pages as $page) {
 926                if ($page->isActive(true)) {
 927                    return true;
 928                }
 929            }
 930            return false;
 931        }
 932
 933        return $this->_active;
 934    }
 935
 936    /**
 937     * Proxy to isActive()
 938     *
 939     * @param  bool $recursive  [optional] whether page should be considered
 940     *                          active if any child pages are active. Default
 941     *                          is false.
 942     * @return bool             whether page should be considered active
 943     */
 944    public function getActive($recursive = false)
 945    {
 946        return $this->isActive($recursive);
 947    }
 948
 949    /**
 950     * Sets whether the page should be visible or not
 951     *
 952     * @param  bool $visible         [optional] whether page should be
 953     *                               considered visible or not. Default is true.
 954     * @return Zend_Navigation_Page  fluent interface, returns self
 955     */
 956    public function setVisible($visible = true)
 957    {
 958        if (is_string($visible) && 'false' == strtolower($visible)) {
 959            $visible = false;
 960        }
 961        $this->_visible = (bool) $visible;
 962        return $this;
 963    }
 964
 965    /**
 966     * Returns a boolean value indicating whether the page is visible
 967     *
 968     * @param  bool $recursive  [optional] whether page should be considered
 969     *                          invisible if parent is invisible. Default is
 970     *                          false.
 971     * @return bool             whether page should be considered visible
 972     */
 973    public function isVisible($recursive = false)
 974    {
 975        if ($recursive && isset($this->_parent) &&
 976            $this->_parent instanceof Zend_Navigation_Page) {
 977            if (!$this->_parent->isVisible(true)) {
 978                return false;
 979            }
 980        }
 981
 982        return $this->_visible;
 983    }
 984
 985    /**
 986     * Proxy to isVisible()
 987     *
 988     * Returns a boolean value indicating whether the page is visible
 989     *
 990     * @param  bool $recursive  [optional] whether page should be considered
 991     *                          invisible if parent is invisible. Default is
 992     *                          false.
 993     * @return bool             whether page should be considered visible
 994     */
 995    public function getVisible($recursive = false)
 996    {
 997        return $this->isVisible($recursive);
 998    }
 999
1000    /**
1001     * Sets parent container
1002     *
1003     * @param  Zend_Navigation_Container $parent  [optional] new parent to set.
1004     *                                            Default is null which will set
1005     *                                            no parent.
1006     * @return Zend_Navigation_Page               fluent interface, returns self
1007     */
1008    public function setParent(Zend_Navigation_Container $parent = null)
1009    {
1010        if ($parent === $this) {
1011            require_once 'Zend/Navigation/Exception.php';
1012            throw new Zend_Navigation_Exception(
1013                'A page cannot have itself as a parent');
1014        }
1015
1016        // return if the given parent already is parent
1017        if ($parent === $this->_parent) {
1018            return $this;
1019        }
1020
1021        // remove from old parent
1022        if (null !== $this->_parent) {
1023            $this->_parent->removePage($this);
1024        }
1025
1026        // set new parent
1027        $this->_parent = $parent;
1028
1029        // add to parent if page and not already a child
1030        if (null !== $this->_parent && !$this->_parent->hasPage($this, false)) {
1031            $this->_parent->addPage($this);
1032        }
1033
1034        return $this;
1035    }
1036
1037    /**
1038     * Returns parent container
1039     *
1040     * @return Zend_Navigation_Container|null  parent container or null
1041     */
1042    public function getParent()
1043    {
1044        return $this->_parent;
1045    }
1046
1047    /**
1048     * Sets the given property
1049     *
1050     * If the given property is native (id, class, title, etc), the matching
1051     * set method will be used. Otherwise, it will be set as a custom property.
1052     *
1053     * @param  string $property           property name
1054     * @param  mixed  $value              value to set
1055     * @return Zend_Navigation_Page       fluent interface, returns self
1056     * @throws Zend_Navigation_Exception  if property name is invalid
1057     */
1058    public function set($property, $value)
1059    {
1060        if (!is_string($property) || empty($property)) {
1061            require_once 'Zend/Navigation/Exception.php';
1062            throw new Zend_Navigation_Exception(
1063                    'Invalid argument: $property must be a non-empty string');
1064        }
1065
1066        $method = 'set' . self::_normalizePropertyName($property);
1067
1068        if ($method != 'setOptions' && $method != 'setConfig' &&
1069            method_exists($this, $method)) {
1070            $this->$method($value);
1071        } else {
1072            $this->_properties[$property] = $value;
1073        }
1074
1075        return $this;
1076    }
1077
1078    /**
1079     * Returns the value of the given property
1080     *
1081     * If the given property is native (id, class, title, etc), the matching
1082     * get method will be used. Otherwise, it will return the matching custom
1083     * property, or null if not found.
1084     *
1085     * @param  string $property           property name
1086     * @return mixed                      the property's value or null
1087     * @throws Zend_Navigation_Exception  if property name is invalid
1088     */
1089    public function get($property)
1090    {
1091        if (!is_string($property) || empty($property)) {
1092            require_once 'Zend/Navigation/Exception.php';
1093            throw new Zend_Navigation_Exception(
1094                    'Invalid argument: $property must be a non-empty string');
1095        }
1096
1097        $method = 'get' . self::_normalizePropertyName($property);
1098
1099        if (method_exists($this, $method)) {
1100            return $this->$method();
1101        } elseif (isset($this->_properties[$property])) {
1102            return $this->_properties[$property];
1103        }
1104
1105        return null;
1106    }
1107
1108    // Magic overloads:
1109
1110    /**
1111     * Sets a custom property
1112     *
1113     * Magic overload for enabling <code>$page->propname = $value</code>.
1114     *
1115     * @param  string $name               property name
1116     * @param  mixed  $value              value to set
1117     * @return void
1118     * @throws Zend_Navigation_Exception  if property name is invalid
1119     */
1120    public function __set($name, $value)
1121    {
1122        $this->set($name, $value);
1123    }
1124
1125    /**
1126     * Returns a property, or null if it doesn't exist
1127     *
1128     * Magic overload for enabling <code>$page->propname</code>.
1129     *
1130     * @param  string $name               property name
1131     * @return mixed                      property value or null
1132     * @throws Zend_Navigation_Exception  if property name is invalid
1133     */
1134    public function __get($name)
1135    {
1136        return $this->get($name);
1137    }
1138
1139    /**
1140     * Checks if a property is set
1141     *
1142     * Magic overload for enabling <code>isset($page->propname)</code>.
1143     *
1144     * Returns true if the property is native (id, class, title, etc), and
1145     * true or false if it's a custom property (depending on whether the
1146     * property actually is set).
1147     *
1148     * @param  string $name  property name
1149     * @return bool          whether the given property exists
1150     */
1151    public function __isset($name)
1152    {
1153        $method = 'get' . self::_normalizePropertyName($name);
1154        if (method_exists($this, $method)) {
1155            return true;
1156        }
1157
1158        return isset($this->_properties[$name]);
1159    }
1160
1161    /**
1162     * Unsets the given custom property
1163     *
1164     * Magic overload for enabling <code>unset($page->propname)</code>.
1165     *
1166     * @param  string $name               property name
1167     * @return void
1168     * @throws Zend_Navigation_Exception  if the property is native
1169     */
1170    public function __unset($name)
1171    {
1172        $method = 'set' . self::_normalizePropertyName($name);
1173        if (method_exists($this, $method)) {
1174            require_once 'Zend/Navigation/Exception.php';
1175            throw new Zend_Navigation_Exception(sprintf(
1176                    'Unsetting native property "%s" is not allowed',
1177                    $name));
1178        }
1179
1180        if (isset($this->_properties[$name])) {
1181            unset($this->_properties[$name]);
1182        }
1183    }
1184
1185    /**
1186     * Returns page label
1187     *
1188     * Magic overload for enabling <code>echo $page</code>.
1189     *
1190     * @return string  page label
1191     */
1192    public function __toString()
1193    {
1194        return $this->_label;
1195    }
1196
1197    // Public methods:
1198
1199    /**
1200     * Adds a forward relation to the page
1201     *
1202     * @param  string $relation      relation name (e.g. alternate, glossary,
1203     *                               canonical, etc)
1204     * @param  mixed  $value         value to set for relation
1205     * @return Zend_Navigation_Page  fluent interface, returns self
1206     */
1207    public function addRel($relation, $value)
1208    {
1209        if (is_string($relation)) {
1210            $this->_rel[$relation] = $value;
1211        }
1212        return $this;
1213    }
1214
1215    /**
1216     * Adds a reverse relation to the page
1217     *
1218     * @param  string $relation      relation name (e.g. alternate, glossary,
1219     *                               canonical, etc)
1220     * @param  mixed  $value         value to set for relation
1221     * @return Zend_Navigation_Page  fluent interface, returns self
1222     */
1223    public function addRev($relation, $value)
1224    {
1225        if (is_string($relation)) {
1226            $this->_rev[$relation] = $value;
1227        }
1228        return $this;
1229    }
1230
1231    /**
1232     * Removes a forward relation from the page
1233     *
1234     * @param  string $relation      name of relation to remove
1235     * @return Zend_Navigation_Page  fluent interface, returns self
1236     */
1237    public function removeRel($relation)
1238    {
1239        if (isset($this->_rel[$relation])) {
1240            unset($this->_rel[$relation]);
1241        }
1242
1243        return $this;
1244    }
1245
1246    /**
1247     * Removes a reverse relation from the page
1248     *
1249     * @param  string $relation      name of relation to remove
1250     * @return Zend_Navigation_Page  fluent interface, returns self
1251     */
1252    public function removeRev($relation)
1253    {
1254        if (isset($this->_rev[$relation])) {
1255            unset($this->_rev[$relation]);
1256        }
1257
1258        return $this;
1259    }
1260
1261    /**
1262     * Returns an array containing the defined forward relations
1263     *
1264     * @return array  defined forward relations
1265     */
1266    public function getDefinedRel()
1267    {
1268        return array_keys($this->_rel);
1269    }
1270
1271    /**
1272     * Returns an array containing the defined reverse relations
1273     *
1274     * @return array  defined reverse relations
1275     */
1276    public function getDefinedRev()
1277    {
1278        return array_keys($this->_rev);
1279    }
1280
1281    /**
1282     * Returns custom properties as an array
1283     *
1284     * @return array  an array containing custom properties
1285     */
1286    public function getCustomProperties()
1287    {
1288        return $this->_properties;
1289    }
1290
1291    /**
1292     * Returns a hash code value for the page
1293     *
1294     * @return string  a hash code value for this page
1295     */
1296    public final function hashCode()
1297    {
1298        return spl_object_hash($this);
1299    }
1300
1301    /**
1302     * Returns an array representation of the page
1303     *
1304     * @return array  associative array containing all page properties
1305     */
1306    public function toArray()
1307    {
1308        return array_merge(
1309            $this->getCustomProperties(),
1310            array(
1311                'label'             => $this->getlabel(),
1312                'fragment'          => $this->getFragment(),
1313                'id'                => $this->getId(),
1314                'class'             => $this->getClass(),
1315                'title'             => $this->getTitle(),
1316                'target'            => $this->getTarget(),
1317                'accesskey'         => $this->getAccesskey(),
1318                'rel'               => $this->getRel(),
1319                'rev'               => $this->getRev(),
1320                'customHtmlAttribs' => $this->getCustomHtmlAttribs(),
1321                'order'             => $this->getOrder(),
1322                'resource'          => $this->getResource(),
1323                'privilege'         => $this->getPrivilege(),
1324                'active'            => $this->isActive(),
1325                'visible'           => $this->isVisible(),
1326                'type'              => get_class($this),
1327                'pages'             => parent::toArray()
1328            )
1329        );
1330    }
1331
1332    // Internal methods:
1333
1334    /**
1335     * Normalizes a property name
1336     *
1337     * @param  string $property  property name to normalize
1338     * @return string            normalized property name
1339     */
1340    protected static function _normalizePropertyName($property)
1341    {
1342        return str_replace(' ', '', ucwords(str_replace('_', ' ', $property)));
1343    }
1344
1345    public static function setDefaultPageType($type = null) {
1346        if($type !== null && !is_string($type)) {
1347            throw new Zend_Navigation_Exception(
1348                'Cannot set default page type: type is no string but should be'
1349            );
1350        }
1351
1352        self::$_defaultPageType = $type;
1353    }
1354
1355    public static function getDefaultPageType() {
1356        return self::$_defaultPageType;
1357    }
1358
1359    // Abstract methods:
1360
1361    /**
1362     * Returns href for this page
1363     *
1364     * @return string  the page's href
1365     */
1366    abstract public function getHref();
1367}