File indexing completed on 2025-03-02 05:29:58
0001 <?php 0002 /** 0003 * Zend Framework 0004 * 0005 * LICENSE 0006 * 0007 * This source file is subject to the new BSD license that is bundled 0008 * with this package in the file LICENSE.txt. 0009 * It is also available through the world-wide-web at this URL: 0010 * http://framework.zend.com/license/new-bsd 0011 * If you did not receive a copy of the license and are unable to 0012 * obtain it through the world-wide-web, please send an email 0013 * to license@zend.com so we can send you a copy immediately. 0014 * 0015 * @category Zend 0016 * @package Zend_View 0017 * @subpackage Helper 0018 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0019 * @license http://framework.zend.com/license/new-bsd New BSD License 0020 * @version $Id$ 0021 */ 0022 0023 /** 0024 * @see Zend_View_Helper_Navigation_Helper 0025 */ 0026 // require_once 'Zend/View/Helper/Navigation/Helper.php'; 0027 0028 /** 0029 * @see Zend_View_Helper_HtmlElement 0030 */ 0031 // require_once 'Zend/View/Helper/HtmlElement.php'; 0032 0033 /** 0034 * Base class for navigational helpers 0035 * 0036 * @category Zend 0037 * @package Zend_View 0038 * @subpackage Helper 0039 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0040 * @license http://framework.zend.com/license/new-bsd New BSD License 0041 */ 0042 abstract class Zend_View_Helper_Navigation_HelperAbstract 0043 extends Zend_View_Helper_HtmlElement 0044 implements Zend_View_Helper_Navigation_Helper 0045 { 0046 /** 0047 * Container to operate on by default 0048 * 0049 * @var Zend_Navigation_Container 0050 */ 0051 protected $_container; 0052 0053 /** 0054 * The minimum depth a page must have to be included when rendering 0055 * 0056 * @var int 0057 */ 0058 protected $_minDepth; 0059 0060 /** 0061 * The maximum depth a page can have to be included when rendering 0062 * 0063 * @var int 0064 */ 0065 protected $_maxDepth; 0066 0067 /** 0068 * Indentation string 0069 * 0070 * @var string 0071 */ 0072 protected $_indent = ''; 0073 0074 /** 0075 * Whether HTML/XML output should be formatted 0076 * 0077 * @var bool 0078 */ 0079 protected $_formatOutput = true; 0080 0081 /** 0082 * Prefix for IDs when they are normalized 0083 * 0084 * @var string|null 0085 */ 0086 protected $_prefixForId = null; 0087 0088 /** 0089 * Skip current prefix for IDs when they are normalized (flag) 0090 * 0091 * @var bool 0092 */ 0093 protected $_skipPrefixForId = false; 0094 0095 /** 0096 * Translator 0097 * 0098 * @var Zend_Translate_Adapter 0099 */ 0100 protected $_translator; 0101 0102 /** 0103 * ACL to use when iterating pages 0104 * 0105 * @var Zend_Acl 0106 */ 0107 protected $_acl; 0108 0109 /** 0110 * Wheter invisible items should be rendered by this helper 0111 * 0112 * @var bool 0113 */ 0114 protected $_renderInvisible = false; 0115 0116 /** 0117 * ACL role to use when iterating pages 0118 * 0119 * @var string|Zend_Acl_Role_Interface 0120 */ 0121 protected $_role; 0122 0123 /** 0124 * Whether translator should be used for page labels and titles 0125 * 0126 * @var bool 0127 */ 0128 protected $_useTranslator = true; 0129 0130 /** 0131 * Whether ACL should be used for filtering out pages 0132 * 0133 * @var bool 0134 */ 0135 protected $_useAcl = true; 0136 0137 /** 0138 * Default ACL to use when iterating pages if not explicitly set in the 0139 * instance by calling {@link setAcl()} 0140 * 0141 * @var Zend_Acl 0142 */ 0143 protected static $_defaultAcl; 0144 0145 /** 0146 * Default ACL role to use when iterating pages if not explicitly set in the 0147 * instance by calling {@link setRole()} 0148 * 0149 * @var string|Zend_Acl_Role_Interface 0150 */ 0151 protected static $_defaultRole; 0152 0153 // Accessors: 0154 0155 /** 0156 * Sets navigation container the helper operates on by default 0157 * 0158 * Implements {@link Zend_View_Helper_Navigation_Interface::setContainer()}. 0159 * 0160 * @param Zend_Navigation_Container $container [optional] container 0161 * to operate on. 0162 * Default is null, 0163 * meaning container 0164 * will be reset. 0165 * @return Zend_View_Helper_Navigation_HelperAbstract fluent interface, 0166 * returns self 0167 */ 0168 public function setContainer(Zend_Navigation_Container $container = null) 0169 { 0170 $this->_container = $container; 0171 return $this; 0172 } 0173 0174 /** 0175 * Returns the navigation container helper operates on by default 0176 * 0177 * Implements {@link Zend_View_Helper_Navigation_Interface::getContainer()}. 0178 * 0179 * If a helper is not explicitly set in this helper instance by calling 0180 * {@link setContainer()} or by passing it through the helper entry point, 0181 * this method will look in {@link Zend_Registry} for a container by using 0182 * the key 'Zend_Navigation'. 0183 * 0184 * If no container is set, and nothing is found in Zend_Registry, a new 0185 * container will be instantiated and stored in the helper. 0186 * 0187 * @return Zend_Navigation_Container navigation container 0188 */ 0189 public function getContainer() 0190 { 0191 if (null === $this->_container) { 0192 // try to fetch from registry first 0193 // require_once 'Zend/Registry.php'; 0194 if (Zend_Registry::isRegistered('Zend_Navigation')) { 0195 $nav = Zend_Registry::get('Zend_Navigation'); 0196 if ($nav instanceof Zend_Navigation_Container) { 0197 return $this->_container = $nav; 0198 } 0199 } 0200 0201 // nothing found in registry, create new container 0202 // require_once 'Zend/Navigation.php'; 0203 $this->_container = new Zend_Navigation(); 0204 } 0205 0206 return $this->_container; 0207 } 0208 0209 /** 0210 * Sets the minimum depth a page must have to be included when rendering 0211 * 0212 * @param int $minDepth [optional] minimum 0213 * depth. Default is 0214 * null, which sets 0215 * no minimum depth. 0216 * @return Zend_View_Helper_Navigation_HelperAbstract fluent interface, 0217 * returns self 0218 */ 0219 public function setMinDepth($minDepth = null) 0220 { 0221 if (null === $minDepth || is_int($minDepth)) { 0222 $this->_minDepth = $minDepth; 0223 } else { 0224 $this->_minDepth = (int) $minDepth; 0225 } 0226 return $this; 0227 } 0228 0229 /** 0230 * Returns minimum depth a page must have to be included when rendering 0231 * 0232 * @return int|null minimum depth or null 0233 */ 0234 public function getMinDepth() 0235 { 0236 if (!is_int($this->_minDepth) || $this->_minDepth < 0) { 0237 return 0; 0238 } 0239 return $this->_minDepth; 0240 } 0241 0242 /** 0243 * Sets the maximum depth a page can have to be included when rendering 0244 * 0245 * @param int $maxDepth [optional] maximum 0246 * depth. Default is 0247 * null, which sets no 0248 * maximum depth. 0249 * @return Zend_View_Helper_Navigation_HelperAbstract fluent interface, 0250 * returns self 0251 */ 0252 public function setMaxDepth($maxDepth = null) 0253 { 0254 if (null === $maxDepth || is_int($maxDepth)) { 0255 $this->_maxDepth = $maxDepth; 0256 } else { 0257 $this->_maxDepth = (int) $maxDepth; 0258 } 0259 return $this; 0260 } 0261 0262 /** 0263 * Returns maximum depth a page can have to be included when rendering 0264 * 0265 * @return int|null maximum depth or null 0266 */ 0267 public function getMaxDepth() 0268 { 0269 return $this->_maxDepth; 0270 } 0271 0272 /** 0273 * Set the indentation string for using in {@link render()}, optionally a 0274 * number of spaces to indent with 0275 * 0276 * @param string|int $indent indentation string or 0277 * number of spaces 0278 * @return Zend_View_Helper_Navigation_HelperAbstract fluent interface, 0279 * returns self 0280 */ 0281 public function setIndent($indent) 0282 { 0283 $this->_indent = $this->_getWhitespace($indent); 0284 return $this; 0285 } 0286 0287 /** 0288 * Returns indentation (format output is respected) 0289 * 0290 * @return string indentation string or an empty string 0291 */ 0292 public function getIndent() 0293 { 0294 if (false === $this->getFormatOutput()) { 0295 return ''; 0296 } 0297 0298 return $this->_indent; 0299 } 0300 0301 /** 0302 * Returns the EOL character (format output is respected) 0303 * 0304 * @see self::EOL 0305 * @see getFormatOutput() 0306 * 0307 * @return string standard EOL charater or an empty string 0308 */ 0309 public function getEOL() 0310 { 0311 if (false === $this->getFormatOutput()) { 0312 return ''; 0313 } 0314 0315 return self::EOL; 0316 } 0317 0318 /** 0319 * Sets whether HTML/XML output should be formatted 0320 * 0321 * @param bool $formatOutput [optional] whether output 0322 * should be formatted. Default 0323 * is true. 0324 * 0325 * @return Zend_View_Helper_Navigation_Sitemap fluent interface, returns 0326 * self 0327 */ 0328 public function setFormatOutput($formatOutput = true) 0329 { 0330 $this->_formatOutput = (bool)$formatOutput; 0331 0332 return $this; 0333 } 0334 0335 /** 0336 * Returns whether HTML/XML output should be formatted 0337 * 0338 * @return bool whether HTML/XML output should be formatted 0339 */ 0340 public function getFormatOutput() 0341 { 0342 return $this->_formatOutput; 0343 } 0344 0345 /** 0346 * Sets prefix for IDs when they are normalized 0347 * 0348 * @param string $prefix Prefix for IDs 0349 * @return Zend_View_Helper_Navigation_HelperAbstract fluent interface, returns self 0350 */ 0351 public function setPrefixForId($prefix) 0352 { 0353 if (is_string($prefix)) { 0354 $this->_prefixForId = trim($prefix); 0355 } 0356 0357 return $this; 0358 } 0359 0360 /** 0361 * Returns prefix for IDs when they are normalized 0362 * 0363 * @return string Prefix for 0364 */ 0365 public function getPrefixForId() 0366 { 0367 if (null === $this->_prefixForId) { 0368 $prefix = get_class($this); 0369 $this->_prefixForId = strtolower( 0370 trim(substr($prefix, strrpos($prefix, '_')), '_') 0371 ) . '-'; 0372 } 0373 0374 return $this->_prefixForId; 0375 } 0376 0377 /** 0378 * Skip the current prefix for IDs when they are normalized 0379 * 0380 * @param bool $flag 0381 * @return Zend_View_Helper_Navigation_HelperAbstract fluent interface, returns self 0382 */ 0383 public function skipPrefixForId($flag = true) 0384 { 0385 $this->_skipPrefixForId = (bool) $flag; 0386 return $this; 0387 } 0388 0389 /** 0390 * Sets translator to use in helper 0391 * 0392 * Implements {@link Zend_View_Helper_Navigation_Helper::setTranslator()}. 0393 * 0394 * @param mixed $translator [optional] translator. 0395 * Expects an object of 0396 * type 0397 * {@link Zend_Translate_Adapter} 0398 * or {@link Zend_Translate}, 0399 * or null. Default is 0400 * null, which sets no 0401 * translator. 0402 * @return Zend_View_Helper_Navigation_HelperAbstract fluent interface, 0403 * returns self 0404 */ 0405 public function setTranslator($translator = null) 0406 { 0407 if (null == $translator || 0408 $translator instanceof Zend_Translate_Adapter) { 0409 $this->_translator = $translator; 0410 } elseif ($translator instanceof Zend_Translate) { 0411 $this->_translator = $translator->getAdapter(); 0412 } 0413 0414 return $this; 0415 } 0416 0417 /** 0418 * Returns translator used in helper 0419 * 0420 * Implements {@link Zend_View_Helper_Navigation_Helper::getTranslator()}. 0421 * 0422 * @return Zend_Translate_Adapter|null translator or null 0423 */ 0424 public function getTranslator() 0425 { 0426 if (null === $this->_translator) { 0427 // require_once 'Zend/Registry.php'; 0428 if (Zend_Registry::isRegistered('Zend_Translate')) { 0429 $this->setTranslator(Zend_Registry::get('Zend_Translate')); 0430 } 0431 } 0432 0433 return $this->_translator; 0434 } 0435 0436 /** 0437 * Sets ACL to use when iterating pages 0438 * 0439 * Implements {@link Zend_View_Helper_Navigation_Helper::setAcl()}. 0440 * 0441 * @param Zend_Acl $acl [optional] ACL object. 0442 * Default is null. 0443 * @return Zend_View_Helper_Navigation_HelperAbstract fluent interface, 0444 * returns self 0445 */ 0446 public function setAcl(Zend_Acl $acl = null) 0447 { 0448 $this->_acl = $acl; 0449 return $this; 0450 } 0451 0452 /** 0453 * Returns ACL or null if it isn't set using {@link setAcl()} or 0454 * {@link setDefaultAcl()} 0455 * 0456 * Implements {@link Zend_View_Helper_Navigation_Helper::getAcl()}. 0457 * 0458 * @return Zend_Acl|null ACL object or null 0459 */ 0460 public function getAcl() 0461 { 0462 if ($this->_acl === null && self::$_defaultAcl !== null) { 0463 return self::$_defaultAcl; 0464 } 0465 0466 return $this->_acl; 0467 } 0468 0469 /** 0470 * Sets ACL role(s) to use when iterating pages 0471 * 0472 * Implements {@link Zend_View_Helper_Navigation_Helper::setRole()}. 0473 * 0474 * @param mixed $role [optional] role to 0475 * set. Expects a string, 0476 * an instance of type 0477 * {@link Zend_Acl_Role_Interface}, 0478 * or null. Default is 0479 * null, which will set 0480 * no role. 0481 * @throws Zend_View_Exception if $role is invalid 0482 * @return Zend_View_Helper_Navigation_HelperAbstract fluent interface, 0483 * returns self 0484 */ 0485 public function setRole($role = null) 0486 { 0487 if (null === $role || is_string($role) || 0488 $role instanceof Zend_Acl_Role_Interface) { 0489 $this->_role = $role; 0490 } else { 0491 // require_once 'Zend/View/Exception.php'; 0492 $e = new Zend_View_Exception(sprintf( 0493 '$role must be a string, null, or an instance of ' 0494 . 'Zend_Acl_Role_Interface; %s given', 0495 gettype($role) 0496 )); 0497 $e->setView($this->view); 0498 throw $e; 0499 } 0500 0501 return $this; 0502 } 0503 0504 /** 0505 * Returns ACL role to use when iterating pages, or null if it isn't set 0506 * using {@link setRole()} or {@link setDefaultRole()} 0507 * 0508 * Implements {@link Zend_View_Helper_Navigation_Helper::getRole()}. 0509 * 0510 * @return string|Zend_Acl_Role_Interface|null role or null 0511 */ 0512 public function getRole() 0513 { 0514 if ($this->_role === null && self::$_defaultRole !== null) { 0515 return self::$_defaultRole; 0516 } 0517 0518 return $this->_role; 0519 } 0520 0521 /** 0522 * Sets whether ACL should be used 0523 * 0524 * Implements {@link Zend_View_Helper_Navigation_Helper::setUseAcl()}. 0525 * 0526 * @param bool $useAcl [optional] whether ACL 0527 * should be used. 0528 * Default is true. 0529 * @return Zend_View_Helper_Navigation_HelperAbstract fluent interface, 0530 * returns self 0531 */ 0532 public function setUseAcl($useAcl = true) 0533 { 0534 $this->_useAcl = (bool) $useAcl; 0535 return $this; 0536 } 0537 0538 /** 0539 * Returns whether ACL should be used 0540 * 0541 * Implements {@link Zend_View_Helper_Navigation_Helper::getUseAcl()}. 0542 * 0543 * @return bool whether ACL should be used 0544 */ 0545 public function getUseAcl() 0546 { 0547 return $this->_useAcl; 0548 } 0549 0550 /** 0551 * Return renderInvisible flag 0552 * 0553 * @return bool 0554 */ 0555 public function getRenderInvisible() 0556 { 0557 return $this->_renderInvisible; 0558 } 0559 0560 /** 0561 * Render invisible items? 0562 * 0563 * @param bool $renderInvisible [optional] boolean flag 0564 * @return Zend_View_Helper_Navigation_HelperAbstract fluent interface 0565 * returns self 0566 */ 0567 public function setRenderInvisible($renderInvisible = true) 0568 { 0569 $this->_renderInvisible = (bool) $renderInvisible; 0570 return $this; 0571 } 0572 0573 /** 0574 * Sets whether translator should be used 0575 * 0576 * Implements {@link Zend_View_Helper_Navigation_Helper::setUseTranslator()}. 0577 * 0578 * @param bool $useTranslator [optional] whether 0579 * translator should be 0580 * used. Default is true. 0581 * @return Zend_View_Helper_Navigation_HelperAbstract fluent interface, 0582 * returns self 0583 */ 0584 public function setUseTranslator($useTranslator = true) 0585 { 0586 $this->_useTranslator = (bool) $useTranslator; 0587 return $this; 0588 } 0589 0590 /** 0591 * Returns whether translator should be used 0592 * 0593 * Implements {@link Zend_View_Helper_Navigation_Helper::getUseTranslator()}. 0594 * 0595 * @return bool whether translator should be used 0596 */ 0597 public function getUseTranslator() 0598 { 0599 return $this->_useTranslator; 0600 } 0601 0602 // Magic overloads: 0603 0604 /** 0605 * Magic overload: Proxy calls to the navigation container 0606 * 0607 * @param string $method method name in container 0608 * @param array $arguments [optional] arguments to pass 0609 * @return mixed returns what the container returns 0610 * @throws Zend_Navigation_Exception if method does not exist in container 0611 */ 0612 public function __call($method, array $arguments = array()) 0613 { 0614 return call_user_func_array( 0615 array($this->getContainer(), $method), 0616 $arguments); 0617 } 0618 0619 /** 0620 * Magic overload: Proxy to {@link render()}. 0621 * 0622 * This method will trigger an E_USER_ERROR if rendering the helper causes 0623 * an exception to be thrown. 0624 * 0625 * Implements {@link Zend_View_Helper_Navigation_Helper::__toString()}. 0626 * 0627 * @return string 0628 */ 0629 public function __toString() 0630 { 0631 try { 0632 return $this->render(); 0633 } catch (Exception $e) { 0634 $msg = get_class($e) . ': ' . $e->getMessage(); 0635 trigger_error($msg, E_USER_ERROR); 0636 return ''; 0637 } 0638 } 0639 0640 // Public methods: 0641 0642 /** 0643 * Finds the deepest active page in the given container 0644 * 0645 * @param Zend_Navigation_Container $container container to search 0646 * @param int|null $minDepth [optional] minimum depth 0647 * required for page to be 0648 * valid. Default is to use 0649 * {@link getMinDepth()}. A 0650 * null value means no minimum 0651 * depth required. 0652 * @param int|null $minDepth [optional] maximum depth 0653 * a page can have to be 0654 * valid. Default is to use 0655 * {@link getMaxDepth()}. A 0656 * null value means no maximum 0657 * depth required. 0658 * @return array an associative array with 0659 * the values 'depth' and 0660 * 'page', or an empty array 0661 * if not found 0662 */ 0663 public function findActive(Zend_Navigation_Container $container, 0664 $minDepth = null, 0665 $maxDepth = -1) 0666 { 0667 if (!is_int($minDepth)) { 0668 $minDepth = $this->getMinDepth(); 0669 } 0670 if ((!is_int($maxDepth) || $maxDepth < 0) && null !== $maxDepth) { 0671 $maxDepth = $this->getMaxDepth(); 0672 } 0673 0674 $found = null; 0675 $foundDepth = -1; 0676 $iterator = new RecursiveIteratorIterator($container, 0677 RecursiveIteratorIterator::CHILD_FIRST); 0678 0679 foreach ($iterator as $page) { 0680 $currDepth = $iterator->getDepth(); 0681 if ($currDepth < $minDepth || !$this->accept($page)) { 0682 // page is not accepted 0683 continue; 0684 } 0685 0686 if ($page->isActive(false) && $currDepth > $foundDepth) { 0687 // found an active page at a deeper level than before 0688 $found = $page; 0689 $foundDepth = $currDepth; 0690 } 0691 } 0692 0693 if (is_int($maxDepth) && $foundDepth > $maxDepth) { 0694 while ($foundDepth > $maxDepth) { 0695 if (--$foundDepth < $minDepth) { 0696 $found = null; 0697 break; 0698 } 0699 0700 $found = $found->getParent(); 0701 if (!$found instanceof Zend_Navigation_Page) { 0702 $found = null; 0703 break; 0704 } 0705 } 0706 } 0707 0708 if ($found) { 0709 return array('page' => $found, 'depth' => $foundDepth); 0710 } else { 0711 return array(); 0712 } 0713 } 0714 0715 /** 0716 * Checks if the helper has a container 0717 * 0718 * Implements {@link Zend_View_Helper_Navigation_Helper::hasContainer()}. 0719 * 0720 * @return bool whether the helper has a container or not 0721 */ 0722 public function hasContainer() 0723 { 0724 return null !== $this->_container; 0725 } 0726 0727 /** 0728 * Checks if the helper has an ACL instance 0729 * 0730 * Implements {@link Zend_View_Helper_Navigation_Helper::hasAcl()}. 0731 * 0732 * @return bool whether the helper has a an ACL instance or not 0733 */ 0734 public function hasAcl() 0735 { 0736 return null !== $this->_acl; 0737 } 0738 0739 /** 0740 * Checks if the helper has an ACL role 0741 * 0742 * Implements {@link Zend_View_Helper_Navigation_Helper::hasRole()}. 0743 * 0744 * @return bool whether the helper has a an ACL role or not 0745 */ 0746 public function hasRole() 0747 { 0748 return null !== $this->_role; 0749 } 0750 0751 /** 0752 * Checks if the helper has a translator 0753 * 0754 * Implements {@link Zend_View_Helper_Navigation_Helper::hasTranslator()}. 0755 * 0756 * @return bool whether the helper has a translator or not 0757 */ 0758 public function hasTranslator() 0759 { 0760 return null !== $this->_translator; 0761 } 0762 0763 /** 0764 * Returns an HTML string containing an 'a' element for the given page 0765 * 0766 * @param Zend_Navigation_Page $page page to generate HTML for 0767 * @return string HTML string for the given page 0768 */ 0769 public function htmlify(Zend_Navigation_Page $page) 0770 { 0771 // get label and title for translating 0772 $label = $page->getLabel(); 0773 $title = $page->getTitle(); 0774 0775 if ($this->getUseTranslator() && $t = $this->getTranslator()) { 0776 if (is_string($label) && !empty($label)) { 0777 $label = $t->translate($label); 0778 } 0779 if (is_string($title) && !empty($title)) { 0780 $title = $t->translate($title); 0781 } 0782 } 0783 0784 // get attribs for anchor element 0785 $attribs = array_merge( 0786 array( 0787 'id' => $page->getId(), 0788 'title' => $title, 0789 'class' => $page->getClass(), 0790 'href' => $page->getHref(), 0791 'target' => $page->getTarget() 0792 ), 0793 $page->getCustomHtmlAttribs() 0794 ); 0795 0796 return '<a' . $this->_htmlAttribs($attribs) . '>' 0797 . $this->view->escape($label) 0798 . '</a>'; 0799 } 0800 0801 // Iterator filter methods: 0802 0803 /** 0804 * Determines whether a page should be accepted when iterating 0805 * 0806 * Rules: 0807 * - If a page is not visible it is not accepted, unless RenderInvisible has 0808 * been set to true. 0809 * - If helper has no ACL, page is accepted 0810 * - If helper has ACL, but no role, page is not accepted 0811 * - If helper has ACL and role: 0812 * - Page is accepted if it has no resource or privilege 0813 * - Page is accepted if ACL allows page's resource or privilege 0814 * - If page is accepted by the rules above and $recursive is true, the page 0815 * will not be accepted if it is the descendant of a non-accepted page. 0816 * 0817 * @param Zend_Navigation_Page $page page to check 0818 * @param bool $recursive [optional] if true, page will not 0819 * be accepted if it is the 0820 * descendant of a page that is not 0821 * accepted. Default is true. 0822 * @return bool whether page should be accepted 0823 */ 0824 public function accept(Zend_Navigation_Page $page, $recursive = true) 0825 { 0826 // accept by default 0827 $accept = true; 0828 0829 if (!$page->isVisible(false) && !$this->getRenderInvisible()) { 0830 // don't accept invisible pages 0831 $accept = false; 0832 } elseif ($this->getUseAcl() && !$this->_acceptAcl($page)) { 0833 // acl is not amused 0834 $accept = false; 0835 } 0836 0837 if ($accept && $recursive) { 0838 $parent = $page->getParent(); 0839 if ($parent instanceof Zend_Navigation_Page) { 0840 $accept = $this->accept($parent, true); 0841 } 0842 } 0843 0844 return $accept; 0845 } 0846 0847 /** 0848 * Determines whether a page should be accepted by ACL when iterating 0849 * 0850 * Rules: 0851 * - If helper has no ACL, page is accepted 0852 * - If page has a resource or privilege defined, page is accepted 0853 * if the ACL allows access to it using the helper's role 0854 * - If page has no resource or privilege, page is accepted 0855 * 0856 * @param Zend_Navigation_Page $page page to check 0857 * @return bool whether page is accepted by ACL 0858 */ 0859 protected function _acceptAcl(Zend_Navigation_Page $page) 0860 { 0861 if (!$acl = $this->getAcl()) { 0862 // no acl registered means don't use acl 0863 return true; 0864 } 0865 0866 $role = $this->getRole(); 0867 $resource = $page->getResource(); 0868 $privilege = $page->getPrivilege(); 0869 0870 if ($resource || $privilege) { 0871 // determine using helper role and page resource/privilege 0872 return $acl->isAllowed($role, $resource, $privilege); 0873 } 0874 0875 return true; 0876 } 0877 0878 // Util methods: 0879 0880 /** 0881 * Retrieve whitespace representation of $indent 0882 * 0883 * @param int|string $indent 0884 * @return string 0885 */ 0886 protected function _getWhitespace($indent) 0887 { 0888 if (is_int($indent)) { 0889 $indent = str_repeat(' ', $indent); 0890 } 0891 0892 return (string) $indent; 0893 } 0894 0895 /** 0896 * Converts an associative array to a string of tag attributes. 0897 * 0898 * Overloads {@link Zend_View_Helper_HtmlElement::_htmlAttribs()}. 0899 * 0900 * @param array $attribs an array where each key-value pair is converted 0901 * to an attribute name and value 0902 * @return string an attribute string 0903 */ 0904 protected function _htmlAttribs($attribs) 0905 { 0906 // filter out null values and empty string values 0907 foreach ($attribs as $key => $value) { 0908 if ($value === null || (is_string($value) && !strlen($value))) { 0909 unset($attribs[$key]); 0910 } 0911 } 0912 0913 return parent::_htmlAttribs($attribs); 0914 } 0915 0916 /** 0917 * Normalize an ID 0918 * 0919 * Extends {@link Zend_View_Helper_HtmlElement::_normalizeId()}. 0920 * 0921 * @param string $value ID 0922 * @return string Normalized ID 0923 */ 0924 protected function _normalizeId($value) 0925 { 0926 if (false === $this->_skipPrefixForId) { 0927 $prefix = $this->getPrefixForId(); 0928 0929 if (strlen($prefix)) { 0930 return $prefix . $value; 0931 } 0932 } 0933 0934 return parent::_normalizeId($value); 0935 } 0936 0937 // Static methods: 0938 0939 /** 0940 * Sets default ACL to use if another ACL is not explicitly set 0941 * 0942 * @param Zend_Acl $acl [optional] ACL object. Default is null, which 0943 * sets no ACL object. 0944 * @return void 0945 */ 0946 public static function setDefaultAcl(Zend_Acl $acl = null) 0947 { 0948 self::$_defaultAcl = $acl; 0949 } 0950 0951 /** 0952 * Sets default ACL role(s) to use when iterating pages if not explicitly 0953 * set later with {@link setRole()} 0954 * 0955 * @param mixed $role [optional] role to set. Expects null, 0956 * string, or an instance of 0957 * {@link Zend_Acl_Role_Interface}. 0958 * Default is null, which sets no default 0959 * role. 0960 * @throws Zend_View_Exception if role is invalid 0961 * @return void 0962 */ 0963 public static function setDefaultRole($role = null) 0964 { 0965 if (null === $role || 0966 is_string($role) || 0967 $role instanceof Zend_Acl_Role_Interface) { 0968 self::$_defaultRole = $role; 0969 } else { 0970 // require_once 'Zend/View/Exception.php'; 0971 throw new Zend_View_Exception( 0972 '$role must be null|string|Zend_Acl_Role_Interface' 0973 ); 0974 } 0975 } 0976 }