PageRenderTime 412ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/src/application/libraries/Zend/View/Helper/Navigation/Menu.php

https://bitbucket.org/masnug/grc276-blog-laravel
PHP | 648 lines | 309 code | 64 blank | 275 comment | 75 complexity | 072e87915f5c4b59438ed3966b262918 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_View
  17. * @subpackage Helper
  18. * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
  19. * @license http://framework.zend.com/license/new-bsd New BSD License
  20. * @version $Id: Menu.php 24455 2011-09-11 12:51:54Z padraic $
  21. */
  22. /**
  23. * @see Zend_View_Helper_Navigation_HelperAbstract
  24. */
  25. require_once 'Zend/View/Helper/Navigation/HelperAbstract.php';
  26. /**
  27. * Helper for rendering menus from navigation containers
  28. *
  29. * @category Zend
  30. * @package Zend_View
  31. * @subpackage Helper
  32. * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
  33. * @license http://framework.zend.com/license/new-bsd New BSD License
  34. */
  35. class Zend_View_Helper_Navigation_Menu
  36. extends Zend_View_Helper_Navigation_HelperAbstract
  37. {
  38. /**
  39. * CSS class to use for the ul element
  40. *
  41. * @var string
  42. */
  43. protected $_ulClass = 'navigation';
  44. /**
  45. * Whether only active branch should be rendered
  46. *
  47. * @var bool
  48. */
  49. protected $_onlyActiveBranch = false;
  50. /**
  51. * Whether parents should be rendered when only rendering active branch
  52. *
  53. * @var bool
  54. */
  55. protected $_renderParents = true;
  56. /**
  57. * Partial view script to use for rendering menu
  58. *
  59. * @var string|array
  60. */
  61. protected $_partial = null;
  62. /**
  63. * View helper entry point:
  64. * Retrieves helper and optionally sets container to operate on
  65. *
  66. * @param Zend_Navigation_Container $container [optional] container to
  67. * operate on
  68. * @return Zend_View_Helper_Navigation_Menu fluent interface,
  69. * returns self
  70. */
  71. public function menu(Zend_Navigation_Container $container = null)
  72. {
  73. if (null !== $container) {
  74. $this->setContainer($container);
  75. }
  76. return $this;
  77. }
  78. // Accessors:
  79. /**
  80. * Sets CSS class to use for the first 'ul' element when rendering
  81. *
  82. * @param string $ulClass CSS class to set
  83. * @return Zend_View_Helper_Navigation_Menu fluent interface, returns self
  84. */
  85. public function setUlClass($ulClass)
  86. {
  87. if (is_string($ulClass)) {
  88. $this->_ulClass = $ulClass;
  89. }
  90. return $this;
  91. }
  92. /**
  93. * Returns CSS class to use for the first 'ul' element when rendering
  94. *
  95. * @return string CSS class
  96. */
  97. public function getUlClass()
  98. {
  99. return $this->_ulClass;
  100. }
  101. /**
  102. * Sets a flag indicating whether only active branch should be rendered
  103. *
  104. * @param bool $flag [optional] render only active
  105. * branch. Default is true.
  106. * @return Zend_View_Helper_Navigation_Menu fluent interface, returns self
  107. */
  108. public function setOnlyActiveBranch($flag = true)
  109. {
  110. $this->_onlyActiveBranch = (bool) $flag;
  111. return $this;
  112. }
  113. /**
  114. * Returns a flag indicating whether only active branch should be rendered
  115. *
  116. * By default, this value is false, meaning the entire menu will be
  117. * be rendered.
  118. *
  119. * @return bool whether only active branch should be rendered
  120. */
  121. public function getOnlyActiveBranch()
  122. {
  123. return $this->_onlyActiveBranch;
  124. }
  125. /**
  126. * Enables/disables rendering of parents when only rendering active branch
  127. *
  128. * See {@link setOnlyActiveBranch()} for more information.
  129. *
  130. * @param bool $flag [optional] render parents when
  131. * rendering active branch.
  132. * Default is true.
  133. * @return Zend_View_Helper_Navigation_Menu fluent interface, returns self
  134. */
  135. public function setRenderParents($flag = true)
  136. {
  137. $this->_renderParents = (bool) $flag;
  138. return $this;
  139. }
  140. /**
  141. * Returns flag indicating whether parents should be rendered when rendering
  142. * only the active branch
  143. *
  144. * By default, this value is true.
  145. *
  146. * @return bool whether parents should be rendered
  147. */
  148. public function getRenderParents()
  149. {
  150. return $this->_renderParents;
  151. }
  152. /**
  153. * Sets which partial view script to use for rendering menu
  154. *
  155. * @param string|array $partial partial view script or null. If
  156. * an array is given, it is
  157. * expected to contain two values;
  158. * the partial view script to use,
  159. * and the module where the script
  160. * can be found.
  161. * @return Zend_View_Helper_Navigation_Menu fluent interface, returns self
  162. */
  163. public function setPartial($partial)
  164. {
  165. if (null === $partial || is_string($partial) || is_array($partial)) {
  166. $this->_partial = $partial;
  167. }
  168. return $this;
  169. }
  170. /**
  171. * Returns partial view script to use for rendering menu
  172. *
  173. * @return string|array|null
  174. */
  175. public function getPartial()
  176. {
  177. return $this->_partial;
  178. }
  179. // Public methods:
  180. /**
  181. * Returns an HTML string containing an 'a' element for the given page if
  182. * the page's href is not empty, and a 'span' element if it is empty
  183. *
  184. * Overrides {@link Zend_View_Helper_Navigation_Abstract::htmlify()}.
  185. *
  186. * @param Zend_Navigation_Page $page page to generate HTML for
  187. * @return string HTML string for the given page
  188. */
  189. public function htmlify(Zend_Navigation_Page $page)
  190. {
  191. // get label and title for translating
  192. $label = $page->getLabel();
  193. $title = $page->getTitle();
  194. // translate label and title?
  195. if ($this->getUseTranslator() && $t = $this->getTranslator()) {
  196. if (is_string($label) && !empty($label)) {
  197. $label = $t->translate($label);
  198. }
  199. if (is_string($title) && !empty($title)) {
  200. $title = $t->translate($title);
  201. }
  202. }
  203. // get attribs for element
  204. $attribs = array(
  205. 'id' => $page->getId(),
  206. 'title' => $title,
  207. 'class' => $page->getClass()
  208. );
  209. // does page have a href?
  210. if ($href = $page->getHref()) {
  211. $element = 'a';
  212. $attribs['href'] = $href;
  213. $attribs['target'] = $page->getTarget();
  214. $attribs['accesskey'] = $page->getAccessKey();
  215. } else {
  216. $element = 'span';
  217. }
  218. return '<' . $element . $this->_htmlAttribs($attribs) . '>'
  219. . $this->view->escape($label)
  220. . '</' . $element . '>';
  221. }
  222. /**
  223. * Normalizes given render options
  224. *
  225. * @param array $options [optional] options to normalize
  226. * @return array normalized options
  227. */
  228. protected function _normalizeOptions(array $options = array())
  229. {
  230. if (isset($options['indent'])) {
  231. $options['indent'] = $this->_getWhitespace($options['indent']);
  232. } else {
  233. $options['indent'] = $this->getIndent();
  234. }
  235. if (isset($options['ulClass']) && $options['ulClass'] !== null) {
  236. $options['ulClass'] = (string) $options['ulClass'];
  237. } else {
  238. $options['ulClass'] = $this->getUlClass();
  239. }
  240. if (array_key_exists('minDepth', $options)) {
  241. if (null !== $options['minDepth']) {
  242. $options['minDepth'] = (int) $options['minDepth'];
  243. }
  244. } else {
  245. $options['minDepth'] = $this->getMinDepth();
  246. }
  247. if ($options['minDepth'] < 0 || $options['minDepth'] === null) {
  248. $options['minDepth'] = 0;
  249. }
  250. if (array_key_exists('maxDepth', $options)) {
  251. if (null !== $options['maxDepth']) {
  252. $options['maxDepth'] = (int) $options['maxDepth'];
  253. }
  254. } else {
  255. $options['maxDepth'] = $this->getMaxDepth();
  256. }
  257. if (!isset($options['onlyActiveBranch'])) {
  258. $options['onlyActiveBranch'] = $this->getOnlyActiveBranch();
  259. }
  260. if (!isset($options['renderParents'])) {
  261. $options['renderParents'] = $this->getRenderParents();
  262. }
  263. return $options;
  264. }
  265. // Render methods:
  266. /**
  267. * Renders the deepest active menu within [$minDepth, $maxDeth], (called
  268. * from {@link renderMenu()})
  269. *
  270. * @param Zend_Navigation_Container $container container to render
  271. * @param array $active active page and depth
  272. * @param string $ulClass CSS class for first UL
  273. * @param string $indent initial indentation
  274. * @param int|null $minDepth minimum depth
  275. * @param int|null $maxDepth maximum depth
  276. * @return string rendered menu
  277. */
  278. protected function _renderDeepestMenu(Zend_Navigation_Container $container,
  279. $ulClass,
  280. $indent,
  281. $minDepth,
  282. $maxDepth)
  283. {
  284. if (!$active = $this->findActive($container, $minDepth - 1, $maxDepth)) {
  285. return '';
  286. }
  287. // special case if active page is one below minDepth
  288. if ($active['depth'] < $minDepth) {
  289. if (!$active['page']->hasPages()) {
  290. return '';
  291. }
  292. } else if (!$active['page']->hasPages()) {
  293. // found pages has no children; render siblings
  294. $active['page'] = $active['page']->getParent();
  295. } else if (is_int($maxDepth) && $active['depth'] +1 > $maxDepth) {
  296. // children are below max depth; render siblings
  297. $active['page'] = $active['page']->getParent();
  298. }
  299. $ulClass = $ulClass ? ' class="' . $ulClass . '"' : '';
  300. $html = $indent . '<ul' . $ulClass . '>' . self::EOL;
  301. foreach ($active['page'] as $subPage) {
  302. if (!$this->accept($subPage)) {
  303. continue;
  304. }
  305. $liClass = $subPage->isActive(true) ? ' class="active"' : '';
  306. $html .= $indent . ' <li' . $liClass . '>' . self::EOL;
  307. $html .= $indent . ' ' . $this->htmlify($subPage) . self::EOL;
  308. $html .= $indent . ' </li>' . self::EOL;
  309. }
  310. $html .= $indent . '</ul>';
  311. return $html;
  312. }
  313. /**
  314. * Renders a normal menu (called from {@link renderMenu()})
  315. *
  316. * @param Zend_Navigation_Container $container container to render
  317. * @param string $ulClass CSS class for first UL
  318. * @param string $indent initial indentation
  319. * @param int|null $minDepth minimum depth
  320. * @param int|null $maxDepth maximum depth
  321. * @param bool $onlyActive render only active branch?
  322. * @return string
  323. */
  324. protected function _renderMenu(Zend_Navigation_Container $container,
  325. $ulClass,
  326. $indent,
  327. $minDepth,
  328. $maxDepth,
  329. $onlyActive)
  330. {
  331. $html = '';
  332. // find deepest active
  333. if ($found = $this->findActive($container, $minDepth, $maxDepth)) {
  334. $foundPage = $found['page'];
  335. $foundDepth = $found['depth'];
  336. } else {
  337. $foundPage = null;
  338. }
  339. // create iterator
  340. $iterator = new RecursiveIteratorIterator($container,
  341. RecursiveIteratorIterator::SELF_FIRST);
  342. if (is_int($maxDepth)) {
  343. $iterator->setMaxDepth($maxDepth);
  344. }
  345. // iterate container
  346. $prevDepth = -1;
  347. foreach ($iterator as $page) {
  348. $depth = $iterator->getDepth();
  349. $isActive = $page->isActive(true);
  350. if ($depth < $minDepth || !$this->accept($page)) {
  351. // page is below minDepth or not accepted by acl/visibilty
  352. continue;
  353. } else if ($onlyActive && !$isActive) {
  354. // page is not active itself, but might be in the active branch
  355. $accept = false;
  356. if ($foundPage) {
  357. if ($foundPage->hasPage($page)) {
  358. // accept if page is a direct child of the active page
  359. $accept = true;
  360. } else if ($foundPage->getParent()->hasPage($page)) {
  361. // page is a sibling of the active page...
  362. if (!$foundPage->hasPages() ||
  363. is_int($maxDepth) && $foundDepth + 1 > $maxDepth) {
  364. // accept if active page has no children, or the
  365. // children are too deep to be rendered
  366. $accept = true;
  367. }
  368. }
  369. }
  370. if (!$accept) {
  371. continue;
  372. }
  373. }
  374. // make sure indentation is correct
  375. $depth -= $minDepth;
  376. $myIndent = $indent . str_repeat(' ', $depth);
  377. if ($depth > $prevDepth) {
  378. // start new ul tag
  379. if ($ulClass && $depth == 0) {
  380. $ulClass = ' class="' . $ulClass . '"';
  381. } else {
  382. $ulClass = '';
  383. }
  384. $html .= $myIndent . '<ul' . $ulClass . '>' . self::EOL;
  385. } else if ($prevDepth > $depth) {
  386. // close li/ul tags until we're at current depth
  387. for ($i = $prevDepth; $i > $depth; $i--) {
  388. $ind = $indent . str_repeat(' ', $i);
  389. $html .= $ind . ' </li>' . self::EOL;
  390. $html .= $ind . '</ul>' . self::EOL;
  391. }
  392. // close previous li tag
  393. $html .= $myIndent . ' </li>' . self::EOL;
  394. } else {
  395. // close previous li tag
  396. $html .= $myIndent . ' </li>' . self::EOL;
  397. }
  398. // render li tag and page
  399. $liClass = $isActive ? ' class="active"' : '';
  400. $html .= $myIndent . ' <li' . $liClass . '>' . self::EOL
  401. . $myIndent . ' ' . $this->htmlify($page) . self::EOL;
  402. // store as previous depth for next iteration
  403. $prevDepth = $depth;
  404. }
  405. if ($html) {
  406. // done iterating container; close open ul/li tags
  407. for ($i = $prevDepth+1; $i > 0; $i--) {
  408. $myIndent = $indent . str_repeat(' ', $i-1);
  409. $html .= $myIndent . ' </li>' . self::EOL
  410. . $myIndent . '</ul>' . self::EOL;
  411. }
  412. $html = rtrim($html, self::EOL);
  413. }
  414. return $html;
  415. }
  416. /**
  417. * Renders helper
  418. *
  419. * Renders a HTML 'ul' for the given $container. If $container is not given,
  420. * the container registered in the helper will be used.
  421. *
  422. * Available $options:
  423. *
  424. *
  425. * @param Zend_Navigation_Container $container [optional] container to
  426. * create menu from. Default
  427. * is to use the container
  428. * retrieved from
  429. * {@link getContainer()}.
  430. * @param array $options [optional] options for
  431. * controlling rendering
  432. * @return string rendered menu
  433. */
  434. public function renderMenu(Zend_Navigation_Container $container = null,
  435. array $options = array())
  436. {
  437. if (null === $container) {
  438. $container = $this->getContainer();
  439. }
  440. $options = $this->_normalizeOptions($options);
  441. if ($options['onlyActiveBranch'] && !$options['renderParents']) {
  442. $html = $this->_renderDeepestMenu($container,
  443. $options['ulClass'],
  444. $options['indent'],
  445. $options['minDepth'],
  446. $options['maxDepth']);
  447. } else {
  448. $html = $this->_renderMenu($container,
  449. $options['ulClass'],
  450. $options['indent'],
  451. $options['minDepth'],
  452. $options['maxDepth'],
  453. $options['onlyActiveBranch']);
  454. }
  455. return $html;
  456. }
  457. /**
  458. * Renders the inner-most sub menu for the active page in the $container
  459. *
  460. * This is a convenience method which is equivalent to the following call:
  461. * <code>
  462. * renderMenu($container, array(
  463. * 'indent' => $indent,
  464. * 'ulClass' => $ulClass,
  465. * 'minDepth' => null,
  466. * 'maxDepth' => null,
  467. * 'onlyActiveBranch' => true,
  468. * 'renderParents' => false
  469. * ));
  470. * </code>
  471. *
  472. * @param Zend_Navigation_Container $container [optional] container to
  473. * render. Default is to render
  474. * the container registered in
  475. * the helper.
  476. * @param string $ulClass [optional] CSS class to
  477. * use for UL element. Default
  478. * is to use the value from
  479. * {@link getUlClass()}.
  480. * @param string|int $indent [optional] indentation as
  481. * a string or number of
  482. * spaces. Default is to use
  483. * the value retrieved from
  484. * {@link getIndent()}.
  485. * @return string rendered content
  486. */
  487. public function renderSubMenu(Zend_Navigation_Container $container = null,
  488. $ulClass = null,
  489. $indent = null)
  490. {
  491. return $this->renderMenu($container, array(
  492. 'indent' => $indent,
  493. 'ulClass' => $ulClass,
  494. 'minDepth' => null,
  495. 'maxDepth' => null,
  496. 'onlyActiveBranch' => true,
  497. 'renderParents' => false
  498. ));
  499. }
  500. /**
  501. * Renders the given $container by invoking the partial view helper
  502. *
  503. * The container will simply be passed on as a model to the view script
  504. * as-is, and will be available in the partial script as 'container', e.g.
  505. * <code>echo 'Number of pages: ', count($this->container);</code>.
  506. *
  507. * @param Zend_Navigation_Container $container [optional] container to
  508. * pass to view script. Default
  509. * is to use the container
  510. * registered in the helper.
  511. * @param string|array $partial [optional] partial view
  512. * script to use. Default is to
  513. * use the partial registered
  514. * in the helper. If an array
  515. * is given, it is expected to
  516. * contain two values; the
  517. * partial view script to use,
  518. * and the module where the
  519. * script can be found.
  520. * @return string helper output
  521. */
  522. public function renderPartial(Zend_Navigation_Container $container = null,
  523. $partial = null)
  524. {
  525. if (null === $container) {
  526. $container = $this->getContainer();
  527. }
  528. if (null === $partial) {
  529. $partial = $this->getPartial();
  530. }
  531. if (empty($partial)) {
  532. require_once 'Zend/View/Exception.php';
  533. $e = new Zend_View_Exception(
  534. 'Unable to render menu: No partial view script provided'
  535. );
  536. $e->setView($this->view);
  537. throw $e;
  538. }
  539. $model = array(
  540. 'container' => $container
  541. );
  542. if (is_array($partial)) {
  543. if (count($partial) != 2) {
  544. require_once 'Zend/View/Exception.php';
  545. $e = new Zend_View_Exception(
  546. 'Unable to render menu: A view partial supplied as '
  547. . 'an array must contain two values: partial view '
  548. . 'script and module where script can be found'
  549. );
  550. $e->setView($this->view);
  551. throw $e;
  552. }
  553. return $this->view->partial($partial[0], $partial[1], $model);
  554. }
  555. return $this->view->partial($partial, null, $model);
  556. }
  557. // Zend_View_Helper_Navigation_Helper:
  558. /**
  559. * Renders menu
  560. *
  561. * Implements {@link Zend_View_Helper_Navigation_Helper::render()}.
  562. *
  563. * If a partial view is registered in the helper, the menu will be rendered
  564. * using the given partial script. If no partial is registered, the menu
  565. * will be rendered as an 'ul' element by the helper's internal method.
  566. *
  567. * @see renderPartial()
  568. * @see renderMenu()
  569. *
  570. * @param Zend_Navigation_Container $container [optional] container to
  571. * render. Default is to
  572. * render the container
  573. * registered in the helper.
  574. * @return string helper output
  575. */
  576. public function render(Zend_Navigation_Container $container = null)
  577. {
  578. if ($partial = $this->getPartial()) {
  579. return $this->renderPartial($container, $partial);
  580. } else {
  581. return $this->renderMenu($container);
  582. }
  583. }
  584. }