Advertisement
Guest User

App_Zend_Navigation_Menu

a guest
Feb 18th, 2011
169
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 13.11 KB | None | 0 0
  1. <?php
  2. /**
  3.  * file : /library/App/View/Helper/Navigation/Menu
  4.  */
  5. class App_View_Helper_Navigation_Menu extends Zend_View_Helper_Navigation_Menu
  6. {
  7.     protected $_renderParentSiblings = false;
  8.  
  9.  
  10.     /**
  11.      * Returns flag indicating whether parent's siblings should be rendered when rendering
  12.      * only the active branch
  13.      *
  14.      * By default, this value is false.
  15.      *
  16.      * @return bool  whether parent's siblings should be rendered
  17.      */
  18.     public function getRenderParentSiblings()
  19.     {
  20.         return $this->_renderParentSiblings;
  21.     }
  22.  
  23.  
  24.     /**
  25.      * Enables/disables rendering of parent's siblings when only rendering active branch
  26.      *
  27.      * See {@link setOnlyActiveBranch()} for more information.
  28.      *
  29.      * @param  bool $flag                        [optional] render parent's siblings when
  30.      *                                           rendering active branch.
  31.      *                                           Default is false.
  32.      * @return Zend_View_Helper_Navigation_Menu  fluent interface, returns self
  33.      */
  34.     public function setRenderParents($flag = false)
  35.     {
  36.         $this->_renderParentSiblings = (bool) $flag;
  37.         return $this;
  38.     }
  39.  
  40.  
  41.     /**
  42.      * Normalizes given render options
  43.      *
  44.      * @param  array $options  [optional] options to normalize
  45.      * @return array           normalized options
  46.      */
  47.     protected function _normalizeOptions(array $options = array())
  48.     {
  49.         $options = parent::_normalizeOptions($options);
  50.  
  51.         if (!isset($options['renderParentSiblings'])) {
  52.             $options['renderParentSiblings'] = $this->getRenderParentSiblings();
  53.         }
  54.  
  55.         return $options;
  56.     }
  57.  
  58.  
  59.     /**
  60.      * Renders helper
  61.      *
  62.      * Renders a HTML 'ul' for the given $container. If $container is not given,
  63.      * the container registered in the helper will be used.
  64.      *
  65.      * Available $options:
  66.      *
  67.      *
  68.      * @param  Zend_Navigation_Container $container  [optional] container to
  69.      *                                               create menu from. Default
  70.      *                                               is to use the container
  71.      *                                               retrieved from
  72.      *                                               {@link getContainer()}.
  73.      * @param  array                     $options    [optional] options for
  74.      *                                               controlling rendering
  75.      * @return string                                rendered menu
  76.      */
  77.     public function renderMenu(Zend_Navigation_Container $container = null,
  78.                                array $options = array())
  79.     {
  80.         if (null === $container) {
  81.             $container = $this->getContainer();
  82.         }
  83.  
  84.         $options = $this->_normalizeOptions($options);
  85.  
  86.         if($options['renderParentSiblings']) {
  87.             $html = $this->_renderMenuWithParentSiblings($container,
  88.                                             $options['ulClass'],
  89.                                             $options['indent'],
  90.                                             $options['minDepth'],
  91.                                             $options['maxDepth'],
  92.                                             $options['onlyActiveBranch'],
  93.                                             $options['renderParentSiblings']);
  94.            
  95.         } else if ($options['onlyActiveBranch'] && !$options['renderParents']) {
  96.             $html = $this->_renderDeepestMenu($container,
  97.                                               $options['ulClass'],
  98.                                               $options['indent'],
  99.                                               $options['minDepth'],
  100.                                               $options['maxDepth']);
  101.         } else {
  102.             $html = $this->_renderMenu($container,
  103.                                        $options['ulClass'],
  104.                                        $options['indent'],
  105.                                        $options['minDepth'],
  106.                                        $options['maxDepth'],
  107.                                        $options['onlyActiveBranch']);
  108.         }
  109.  
  110.         return $html;
  111.     }
  112.  
  113.  
  114.     /**
  115.      * Renders a menu with all the siblings
  116.      *
  117.      * @param  Zend_Navigation_Container $container   container to render
  118.      * @param  string                    $ulClass     CSS class for first UL
  119.      * @param  string                    $indent      initial indentation
  120.      * @param  int|null                  $minDepth    minimum depth
  121.      * @param  int|null                  $maxDepth    maximum depth
  122.      * @param  bool                      $onlyActive  render only active branch?
  123.      * @param  bool                      $renderParentSiblings  render all parent siblings
  124.      * @return string
  125.      */
  126.     protected function _renderMenuWithParentSiblings(Zend_Navigation_Container $container,
  127.                                                                    $ulClass,
  128.                                                                    $indent,
  129.                                                                    $minDepth,
  130.                                                                    $maxDepth,
  131.                                                                    $onlyActive,
  132.                                                                    $renderParentSiblings)
  133.     {
  134.         $html = '';
  135.  
  136.         // find deepest active
  137.         if ($found = $this->findActive($container, $minDepth, $maxDepth)) {
  138.             $foundPage = $found['page'];
  139.             $foundDepth = $found['depth'];
  140.         } else {
  141.             $foundPage = null;
  142.         }
  143.  
  144.         // create iterator
  145.         $iterator = new RecursiveIteratorIterator($container,
  146.                             RecursiveIteratorIterator::SELF_FIRST);
  147.         if (is_int($maxDepth)) {
  148.             $iterator->setMaxDepth($maxDepth);
  149.         }
  150.  
  151.         // iterate container
  152.         $prevDepth = -1;
  153.         $siblings = array();
  154.         if($foundPage) {
  155.             foreach ($iterator as $page) {
  156.                 $depth = $iterator->getDepth();
  157.                 if($depth >= $minDepth) {
  158.                     if($page->hasPage($foundPage, true) || $page == $foundPage) {
  159.                         if(!is_null($page->getParent())) {
  160.                             foreach ($page->getParent()->getPages() as $sibling) {
  161.                                 $siblings[] = $sibling;
  162.                             }
  163.                         }
  164.                     }
  165.                 }
  166.             }
  167.         }
  168.  
  169.         foreach ($iterator as $page) {
  170.             $depth = $iterator->getDepth();
  171.             /* @var $page Zend_Navigation_Page */
  172.             $isActive = $page->isActive(true);
  173.  
  174.             if(in_array($page, $siblings) && $this->accept($page, true) && $depth >= $minDepth) {
  175.                 $accept = true;
  176.  
  177.             } else if ($depth < $minDepth || !$this->accept($page, true)) {
  178.                 // page is below minDepth or not accepted by acl/visibilty
  179.                 continue;
  180.             } else if ($onlyActive && !$isActive) {
  181.                 // page is not active itself, but might be in the active branch
  182.                 $accept = false;
  183.                 if ($foundPage) {
  184.                     if ($foundPage->hasPage($page)) {
  185.                         // accept if page is a direct child of the active page
  186.                         $accept = true;
  187.                     } else if (!is_null($foundPage->getParent()) && $foundPage->getParent()->hasPage($page)) {
  188.                         // page is a sibling of the active page...
  189.                         if (!$foundPage->hasPages() ||
  190.                             is_int($maxDepth) && $foundDepth + 1 > $maxDepth) {
  191.                             // accept if active page has no children, or the
  192.                             // children are too deep to be rendered
  193.                             $accept = true;
  194.                         }
  195.                     }
  196.                 }
  197.  
  198.                 if (!$accept) {
  199.                     continue;
  200.                 }
  201.             }
  202.  
  203.             // make sure indentation is correct
  204.             $depth -= $minDepth;
  205.             $myIndent = $indent . str_repeat('        ', $depth);
  206.  
  207.             if ($depth > $prevDepth) {
  208.                 // start new ul tag
  209.                 if ($ulClass && $depth ==  0) {
  210.                     $ulClass = ' class="' . $ulClass . '"';
  211.                 } else {
  212.                     $ulClass = '';
  213.                 }
  214.                 $html .= $myIndent . '<ul' . $ulClass . '>' . self::EOL;
  215.             } else if ($prevDepth > $depth) {
  216.                 // close li/ul tags until we're at current depth
  217.                 for ($i = $prevDepth; $i > $depth; $i--) {
  218.                     $ind = $indent . str_repeat('        ', $i);
  219.                     $html .= $ind . '    </li>' . self::EOL;
  220.                     $html .= $ind . '</ul>' . self::EOL;
  221.                 }
  222.                 // close previous li tag
  223.                 $html .= $myIndent . '    </li>' . self::EOL;
  224.             } else {
  225.                 // close previous li tag
  226.                 $html .= $myIndent . '    </li>' . self::EOL;
  227.             }
  228.  
  229.             // render li tag and page
  230.             $liClass = $isActive ? ' class="active"' : '';
  231.             $html .= $myIndent . '    <li' . $liClass . '>' . self::EOL
  232.                    . $myIndent . '        ' . $this->htmlify($page) . self::EOL;
  233.  
  234.             // store as previous depth for next iteration
  235.             $prevDepth = $depth;
  236.         }
  237.  
  238.         if ($html) {
  239.             // done iterating container; close open ul/li tags
  240.             for ($i = $prevDepth+1; $i > 0; $i--) {
  241.                 $myIndent = $indent . str_repeat('        ', $i-1);
  242.                 $html .= $myIndent . '    </li>' . self::EOL
  243.                        . $myIndent . '</ul>' . self::EOL;
  244.             }
  245.             $html = rtrim($html, self::EOL);
  246.         }
  247.  
  248.         return $html;
  249.     }
  250.    
  251.  
  252.     /**
  253.      * OVERLOAD - invisible pages should be found back !!
  254.      *
  255.      * Finds the deepest active page in the given container
  256.      *
  257.      * @param  Zend_Navigation_Container $container  container to search
  258.      * @param  int|null                  $minDepth   [optional] minimum depth
  259.      *                                               required for page to be
  260.      *                                               valid. Default is to use
  261.      *                                               {@link getMinDepth()}. A
  262.      *                                               null value means no minimum
  263.      *                                               depth required.
  264.      * @param  int|null                  $minDepth   [optional] maximum depth
  265.      *                                               a page can have to be
  266.      *                                               valid. Default is to use
  267.      *                                               {@link getMaxDepth()}. A
  268.      *                                               null value means no maximum
  269.      *                                               depth required.
  270.      * @return array                                 an associative array with
  271.      *                                               the values 'depth' and
  272.      *                                               'page', or an empty array
  273.      *                                               if not found
  274.      */
  275.     public function findActive(Zend_Navigation_Container $container,
  276.                                $minDepth = null,
  277.                                $maxDepth = -1)
  278.     {
  279.         if (!is_int($minDepth)) {
  280.             $minDepth = $this->getMinDepth();
  281.         }
  282.         if ((!is_int($maxDepth) || $maxDepth < 0) && null !== $maxDepth) {
  283.             $maxDepth = $this->getMaxDepth();
  284.         }
  285.  
  286.         $found  = null;
  287.         $foundDepth = -1;
  288.         $iterator = new RecursiveIteratorIterator($container,
  289.                 RecursiveIteratorIterator::CHILD_FIRST);
  290.  
  291.         foreach ($iterator as $page) {
  292.             $currDepth = $iterator->getDepth();
  293. //            if ($currDepth < $minDepth || !$this->accept($page)) {
  294.             // hidden pages should be found
  295.             if ($currDepth < $minDepth) {
  296.                 // page is not accepted
  297.                 continue;
  298.             }
  299.  
  300.             if ($page->isActive(false) && $currDepth > $foundDepth) {
  301.                 // found an active page at a deeper level than before
  302.                 $found = $page;
  303.                 $foundDepth = $currDepth;
  304.             }
  305.         }
  306.  
  307.         if (is_int($maxDepth) && $foundDepth > $maxDepth) {
  308.             while ($foundDepth > $maxDepth) {
  309.                 if (--$foundDepth < $minDepth) {
  310.                     $found = null;
  311.                     break;
  312.                 }
  313.  
  314.                 $found = $found->getParent();
  315.                 if (!$found instanceof Zend_Navigation_Page) {
  316.                     $found = null;
  317.                     break;
  318.                 }
  319.             }
  320.         }
  321.  
  322.         if ($found) {
  323.             return array('page' => $found, 'depth' => $foundDepth);
  324.         } else {
  325.             return array();
  326.         }
  327.     }
  328. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement