00001 <?php
00026 require_once 'Zend/View/Helper/Navigation/HelperAbstract.php';
00027
00037 class Zend_View_Helper_Navigation_Menu
00038 extends Zend_View_Helper_Navigation_HelperAbstract
00039 {
00045 protected $_ulClass = 'navigation';
00046
00052 protected $_onlyActiveBranch = false;
00053
00059 protected $_renderParents = true;
00060
00066 protected $_partial = null;
00067
00077 public function menu(Zend_Navigation_Container $container = null)
00078 {
00079 if (null !== $container) {
00080 $this->setContainer($container);
00081 }
00082
00083 return $this;
00084 }
00085
00086
00087
00094 public function setUlClass($ulClass)
00095 {
00096 if (is_string($ulClass)) {
00097 $this->_ulClass = $ulClass;
00098 }
00099
00100 return $this;
00101 }
00102
00108 public function getUlClass()
00109 {
00110 return $this->_ulClass;
00111 }
00112
00120 public function setOnlyActiveBranch($flag = true)
00121 {
00122 $this->_onlyActiveBranch = (bool) $flag;
00123 return $this;
00124 }
00125
00134 public function getOnlyActiveBranch()
00135 {
00136 return $this->_onlyActiveBranch;
00137 }
00138
00149 public function setRenderParents($flag = true)
00150 {
00151 $this->_renderParents = (bool) $flag;
00152 return $this;
00153 }
00154
00163 public function getRenderParents()
00164 {
00165 return $this->_renderParents;
00166 }
00167
00179 public function setPartial($partial)
00180 {
00181 if (null === $partial || is_string($partial) || is_array($partial)) {
00182 $this->_partial = $partial;
00183 }
00184
00185 return $this;
00186 }
00187
00193 public function getPartial()
00194 {
00195 return $this->_partial;
00196 }
00197
00198
00199
00209 public function htmlify(Zend_Navigation_Page $page)
00210 {
00211
00212 $label = $page->getLabel();
00213 $title = $page->getTitle();
00214
00215
00216 if ($this->getUseTranslator() && $t = $this->getTranslator()) {
00217 if (is_string($label) && !empty($label)) {
00218 $label = $t->translate($label);
00219 }
00220 if (is_string($title) && !empty($title)) {
00221 $title = $t->translate($title);
00222 }
00223 }
00224
00225
00226 $attribs = array(
00227 'id' => $page->getId(),
00228 'title' => $title,
00229 'class' => $page->getClass()
00230 );
00231
00232
00233 if ($href = $page->getHref()) {
00234 $element = 'a';
00235 $attribs['href'] = $href;
00236 $attribs['target'] = $page->getTarget();
00237 } else {
00238 $element = 'span';
00239 }
00240
00241 return '<' . $element . $this->_htmlAttribs($attribs) . '>'
00242 . $this->view->escape($label)
00243 . '</' . $element . '>';
00244 }
00245
00252 protected function _normalizeOptions(array $options = array())
00253 {
00254 if (isset($options['indent'])) {
00255 $options['indent'] = $this->_getWhitespace($options['indent']);
00256 } else {
00257 $options['indent'] = $this->getIndent();
00258 }
00259
00260 if (isset($options['ulClass']) && $options['ulClass'] !== null) {
00261 $options['ulClass'] = (string) $options['ulClass'];
00262 } else {
00263 $options['ulClass'] = $this->getUlClass();
00264 }
00265
00266 if (array_key_exists('minDepth', $options)) {
00267 if (null !== $options['minDepth']) {
00268 $options['minDepth'] = (int) $options['minDepth'];
00269 }
00270 } else {
00271 $options['minDepth'] = $this->getMinDepth();
00272 }
00273
00274 if ($options['minDepth'] < 0 || $options['minDepth'] === null) {
00275 $options['minDepth'] = 0;
00276 }
00277
00278 if (array_key_exists('maxDepth', $options)) {
00279 if (null !== $options['maxDepth']) {
00280 $options['maxDepth'] = (int) $options['maxDepth'];
00281 }
00282 } else {
00283 $options['maxDepth'] = $this->getMaxDepth();
00284 }
00285
00286 if (!isset($options['onlyActiveBranch'])) {
00287 $options['onlyActiveBranch'] = $this->getOnlyActiveBranch();
00288 }
00289
00290 if (!isset($options['renderParents'])) {
00291 $options['renderParents'] = $this->getRenderParents();
00292 }
00293
00294 return $options;
00295 }
00296
00297
00298
00311 protected function _renderDeepestMenu(Zend_Navigation_Container $container,
00312 $ulClass,
00313 $indent,
00314 $minDepth,
00315 $maxDepth)
00316 {
00317 if (!$active = $this->findActive($container, $minDepth - 1, $maxDepth)) {
00318 return '';
00319 }
00320
00321
00322 if ($active['depth'] < $minDepth) {
00323 if (!$active['page']->hasPages()) {
00324 return '';
00325 }
00326 } else if (!$active['page']->hasPages()) {
00327
00328 $active['page'] = $active['page']->getParent();
00329 } else if (is_int($maxDepth) && $active['depth'] +1 > $maxDepth) {
00330
00331 $active['page'] = $active['page']->getParent();
00332 }
00333
00334 $ulClass = $ulClass ? ' class="' . $ulClass . '"' : '';
00335 $html = $indent . '<ul' . $ulClass . '>' . self::EOL;
00336
00337 foreach ($active['page'] as $subPage) {
00338 if (!$this->accept($subPage)) {
00339 continue;
00340 }
00341 $liClass = $subPage->isActive(true) ? ' class="active"' : '';
00342 $html .= $indent . ' <li' . $liClass . '>' . self::EOL;
00343 $html .= $indent . ' ' . $this->htmlify($subPage) . self::EOL;
00344 $html .= $indent . ' </li>' . self::EOL;
00345 }
00346
00347 $html .= $indent . '</ul>';
00348
00349 return $html;
00350 }
00351
00363 protected function _renderMenu(Zend_Navigation_Container $container,
00364 $ulClass,
00365 $indent,
00366 $minDepth,
00367 $maxDepth,
00368 $onlyActive)
00369 {
00370 $html = '';
00371
00372
00373 if ($found = $this->findActive($container, $minDepth, $maxDepth)) {
00374 $foundPage = $found['page'];
00375 $foundDepth = $found['depth'];
00376 } else {
00377 $foundPage = null;
00378 }
00379
00380
00381 $iterator = new RecursiveIteratorIterator($container,
00382 RecursiveIteratorIterator::SELF_FIRST);
00383 if (is_int($maxDepth)) {
00384 $iterator->setMaxDepth($maxDepth);
00385 }
00386
00387
00388 $prevDepth = -1;
00389 foreach ($iterator as $page) {
00390 $depth = $iterator->getDepth();
00391 $isActive = $page->isActive(true);
00392 if ($depth < $minDepth || !$this->accept($page)) {
00393
00394 continue;
00395 } else if ($onlyActive && !$isActive) {
00396
00397 $accept = false;
00398 if ($foundPage) {
00399 if ($foundPage->hasPage($page)) {
00400
00401 $accept = true;
00402 } else if ($foundPage->getParent()->hasPage($page)) {
00403
00404 if (!$foundPage->hasPages() ||
00405 is_int($maxDepth) && $foundDepth + 1 > $maxDepth) {
00406
00407
00408 $accept = true;
00409 }
00410 }
00411 }
00412
00413 if (!$accept) {
00414 continue;
00415 }
00416 }
00417
00418
00419 $depth -= $minDepth;
00420 $myIndent = $indent . str_repeat(' ', $depth);
00421
00422 if ($depth > $prevDepth) {
00423
00424 if ($ulClass && $depth == 0) {
00425 $ulClass = ' class="' . $ulClass . '"';
00426 } else {
00427 $ulClass = '';
00428 }
00429 $html .= $myIndent . '<ul' . $ulClass . '>' . self::EOL;
00430 } else if ($prevDepth > $depth) {
00431
00432 for ($i = $prevDepth; $i > $depth; $i--) {
00433 $ind = $indent . str_repeat(' ', $i);
00434 $html .= $ind . ' </li>' . self::EOL;
00435 $html .= $ind . '</ul>' . self::EOL;
00436 }
00437
00438 $html .= $myIndent . ' </li>' . self::EOL;
00439 } else {
00440
00441 $html .= $myIndent . ' </li>' . self::EOL;
00442 }
00443
00444
00445 $liClass = $isActive ? ' class="active"' : '';
00446 $html .= $myIndent . ' <li' . $liClass . '>' . self::EOL
00447 . $myIndent . ' ' . $this->htmlify($page) . self::EOL;
00448
00449
00450 $prevDepth = $depth;
00451 }
00452
00453 if ($html) {
00454
00455 for ($i = $prevDepth+1; $i > 0; $i--) {
00456 $myIndent = $indent . str_repeat(' ', $i-1);
00457 $html .= $myIndent . ' </li>' . self::EOL
00458 . $myIndent . '</ul>' . self::EOL;
00459 }
00460 $html = rtrim($html, self::EOL);
00461 }
00462
00463 return $html;
00464 }
00465
00484 public function renderMenu(Zend_Navigation_Container $container = null,
00485 array $options = array())
00486 {
00487 if (null === $container) {
00488 $container = $this->getContainer();
00489 }
00490
00491 $options = $this->_normalizeOptions($options);
00492
00493 if ($options['onlyActiveBranch'] && !$options['renderParents']) {
00494 $html = $this->_renderDeepestMenu($container,
00495 $options['ulClass'],
00496 $options['indent'],
00497 $options['minDepth'],
00498 $options['maxDepth']);
00499 } else {
00500 $html = $this->_renderMenu($container,
00501 $options['ulClass'],
00502 $options['indent'],
00503 $options['minDepth'],
00504 $options['maxDepth'],
00505 $options['onlyActiveBranch']);
00506 }
00507
00508 return $html;
00509 }
00510
00541 public function renderSubMenu(Zend_Navigation_Container $container = null,
00542 $ulClass = null,
00543 $indent = null)
00544 {
00545 return $this->renderMenu($container, array(
00546 'indent' => $indent,
00547 'ulClass' => $ulClass,
00548 'minDepth' => null,
00549 'maxDepth' => null,
00550 'onlyActiveBranch' => true,
00551 'renderParents' => false
00552 ));
00553 }
00554
00577 public function renderPartial(Zend_Navigation_Container $container = null,
00578 $partial = null)
00579 {
00580 if (null === $container) {
00581 $container = $this->getContainer();
00582 }
00583
00584 if (null === $partial) {
00585 $partial = $this->getPartial();
00586 }
00587
00588 if (empty($partial)) {
00589 require_once 'Zend/View/Exception.php';
00590 throw new Zend_View_Exception(
00591 'Unable to render menu: No partial view script provided');
00592 }
00593
00594 $model = array(
00595 'container' => $container
00596 );
00597
00598 if (is_array($partial)) {
00599 if (count($partial) != 2) {
00600 require_once 'Zend/View/Exception.php';
00601 throw new Zend_View_Exception(
00602 'Unable to render menu: A view partial supplied as ' .
00603 'an array must contain two values: partial view ' .
00604 'script and module where script can be found');
00605 }
00606
00607 return $this->view->partial($partial[0], $partial[1], $model);
00608 }
00609
00610 return $this->view->partial($partial, null, $model);
00611 }
00612
00613
00614
00633 public function render(Zend_Navigation_Container $container = null)
00634 {
00635 if ($partial = $this->getPartial()) {
00636 return $this->renderPartial($container, $partial);
00637 } else {
00638 return $this->renderMenu($container);
00639 }
00640 }
00641 }