From 4cb3efe9c5ebaf1f3e11c536a5fd6349161bffed Mon Sep 17 00:00:00 2001 From: "boris.popovschi@yopeso.com" Date: Tue, 21 Jul 2015 16:20:53 +0300 Subject: [PATCH] Finished feature for passing parameters into navigation-partial view model.Added tests. --- src/Helper/Navigation/Breadcrumbs.php | 257 ++++++---- src/Helper/Navigation/Menu.php | 448 +++++++++--------- test/Helper/Navigation/BreadcrumbsTest.php | 29 +- test/Helper/Navigation/MenuTest.php | 61 ++- .../expected/bc/partial_with_params.html | 2 + .../expected/menu/partial_with_params.html | 3 + .../mvc/views/bc_with_partial_params.phtml | 5 + .../mvc/views/menu_with_partial_params.phtml | 13 + 8 files changed, 454 insertions(+), 364 deletions(-) create mode 100644 test/Helper/Navigation/_files/expected/bc/partial_with_params.html create mode 100644 test/Helper/Navigation/_files/expected/menu/partial_with_params.html create mode 100644 test/Helper/Navigation/_files/mvc/views/bc_with_partial_params.phtml create mode 100644 test/Helper/Navigation/_files/mvc/views/menu_with_partial_params.phtml diff --git a/src/Helper/Navigation/Breadcrumbs.php b/src/Helper/Navigation/Breadcrumbs.php index d72c9ecc..3b7d2fe7 100644 --- a/src/Helper/Navigation/Breadcrumbs.php +++ b/src/Helper/Navigation/Breadcrumbs.php @@ -1,12 +1,13 @@ htmlify($parent) - . $this->getSeparator() - . $html; + .$this->getSeparator() + .$html; } if ($parent === $container) { @@ -131,103 +135,82 @@ public function renderStraight($container = null) $active = $parent; } - return strlen($html) ? $this->getIndent() . $html : ''; + return strlen($html) ? $this->getIndent().$html : ''; } /** - * Renders the given $container by invoking the partial view helper - * - * The container will simply be passed on as a model to the view script, - * so in the script it will be available in $this->container. - * - * @param AbstractContainer $container [optional] container to pass to view script. - * Default is to use the container registered - * in the helper. - * @param string|array $partial [optional] partial view script to use. - * Default is to use the partial registered - * in the helper. If an array is given, it - * is expected to contain two values; the - * partial view script to use, and the module - * where the script can be found. - * @throws Exception\RuntimeException if no partial provided + * Renders the given $container by invoking the partial view helper. + * + * The container will simply be passed on as a model to the view script + * as-is, and will be available in the partial script as 'container', e.g. + * echo 'Number of pages: ', count($this->container);. + * + * @param null|AbstractContainer $container [optional] container to pass to view + * script. Default is to use the container + * registered in the helper. + * @param null|string|array $partial [optional] partial view script to use. + * Default is to use the partial + * registered in the helper. If an array + * is given, it is expected to contain two + * values; the partial view script to use, + * and the module where the script can be + * found. + * + * @return string + * + * @throws Exception\RuntimeException if no partial provided * @throws Exception\InvalidArgumentException if partial is invalid array - * @return string helper output */ public function renderPartial($container = null, $partial = null) { - $this->parseContainer($container); - if (null === $container) { - $container = $this->getContainer(); - } - - if (null === $partial) { - $partial = $this->getPartial(); - } - - if (empty($partial)) { - throw new Exception\RuntimeException( - 'Unable to render menu: No partial view script provided' - ); - } - - // put breadcrumb pages in model - $model = [ - 'pages' => [], - 'separator' => $this->getSeparator() - ]; - $active = $this->findActive($container); - if ($active) { - $active = $active['page']; - $model['pages'][] = $active; - while ($parent = $active->getParent()) { - if ($parent instanceof AbstractPage) { - $model['pages'][] = $parent; - } else { - break; - } - - if ($parent === $container) { - // break if at the root of the given container - break; - } - - $active = $parent; - } - $model['pages'] = array_reverse($model['pages']); - } - - /** @var \Zend\View\Helper\Partial $partialHelper */ - $partialHelper = $this->view->plugin('partial'); - - if (is_array($partial)) { - if (count($partial) != 2) { - throw new Exception\InvalidArgumentException( - 'Unable to render menu: A view partial supplied as ' - . 'an array must contain two values: partial view ' - . 'script and module where script can be found' - ); - } - - return $partialHelper($partial[0], $model); - } - - return $partialHelper($partial, $model); + return $this->renderPartialModel([], $container, $partial); + } + /** + * Renders the given $container by invoking the partial view helper with the given parameters as the model. + * + * The container will simply be passed on as a model to the view script + * as-is, and will be available in the partial script as 'container', e.g. + * echo 'Number of pages: ', count($this->container);. + * + * Any parameters provided will be passed to the partial via the view model. + * + * @param null|AbstractContainer $container [optional] container to pass to view + * script. Default is to use the container + * registered in the helper. + * @param null|string|array $partial [optional] partial view script to use. + * Default is to use the partial + * registered in the helper. If an array + * is given, it is expected to contain two + * values; the partial view script to use, + * and the module where the script can be + * found. + * + * @return string + * + * @throws Exception\RuntimeException if no partial provided + * @throws Exception\InvalidArgumentException if partial is invalid array + */ + public function renderPartialWithParams(array $params = [], $container = null, $partial = null) + { + return $this->renderPartialModel($params, $container, $partial); } /** - * Sets whether last page in breadcrumbs should be hyperlinked + * Sets whether last page in breadcrumbs should be hyperlinked. + * + * @param bool $linkLast whether last page should be hyperlinked * - * @param bool $linkLast whether last page should be hyperlinked * @return Breadcrumbs */ public function setLinkLast($linkLast) { $this->linkLast = (bool) $linkLast; + return $this; } /** - * Returns whether last page in breadcrumbs should be hyperlinked + * Returns whether last page in breadcrumbs should be hyperlinked. * * @return bool */ @@ -237,13 +220,14 @@ public function getLinkLast() } /** - * Sets which partial view script to use for rendering menu + * Sets which partial view script to use for rendering menu. + * + * @param string|array $partial partial view script or null. If an array is + * given, it is expected to contain two + * values; the partial view script to use, + * and the module where the script can be + * found. * - * @param string|array $partial partial view script or null. If an array is - * given, it is expected to contain two - * values; the partial view script to use, - * and the module where the script can be - * found. * @return Breadcrumbs */ public function setPartial($partial) @@ -256,7 +240,7 @@ public function setPartial($partial) } /** - * Returns partial view script to use for rendering menu + * Returns partial view script to use for rendering menu. * * @return string|array|null */ @@ -266,9 +250,10 @@ public function getPartial() } /** - * Sets breadcrumb separator + * Sets breadcrumb separator. + * + * @param string $separator separator string * - * @param string $separator separator string * @return Breadcrumbs */ public function setSeparator($separator) @@ -281,12 +266,74 @@ public function setSeparator($separator) } /** - * Returns breadcrumb separator + * Returns breadcrumb separator. * - * @return string breadcrumb separator + * @return string breadcrumb separator */ public function getSeparator() { return $this->separator; } + + /** + * Render a partial with the given "model". + * + * @param array $params + * @param null|AbstractContainer $container + * @param null|string|array $partial + * + * @return string + * + * @throws Exception\RuntimeException if no partial provided + * @throws Exception\InvalidArgumentException if partial is invalid array + */ + protected function renderPartialModel(array $params, $container, $partial) + { + $this->parseContainer($container); + if (null === $container) { + $container = $this->getContainer(); + } + if (null === $partial) { + $partial = $this->getPartial(); + } + if (empty($partial)) { + throw new Exception\RuntimeException( + 'Unable to render breadcrumbs: No partial view script provided' + ); + } + $model = array_merge($params, ['pages' => []], ['separator' => $this->getSeparator()]); + $active = $this->findActive($container); + if ($active) { + $active = $active['page']; + $model['pages'][] = $active; + while ($parent = $active->getParent()) { + if ($parent instanceof AbstractPage) { + $model['pages'][] = $parent; + } else { + break; + } + if ($parent === $container) { + // break if at the root of the given container + break; + } + $active = $parent; + } + $model['pages'] = array_reverse($model['pages']); + } + /** @var \Zend\View\Helper\Partial $partialHelper */ + $partialHelper = $this->view->plugin('partial'); + if (is_array($partial)) { + if (count($partial) != 2) { + throw new Exception\InvalidArgumentException( + 'Unable to render breadcrumbs: A view partial supplied as ' + .'an array must contain two values: partial view ' + .'script and module where script can be found' + ); + } + + return $partialHelper($partial[0], $model); + } + + return $partialHelper($partial, $model); + } } diff --git a/src/Helper/Navigation/Menu.php b/src/Helper/Navigation/Menu.php index 90b053ea..88e3113d 100644 --- a/src/Helper/Navigation/Menu.php +++ b/src/Helper/Navigation/Menu.php @@ -1,12 +1,13 @@ element + * Whether page class should be applied to
  • element. * * @var bool */ protected $addClassToListItem = false; - /** - * Whether labels should be escaped + * Whether labels should be escaped. * * @var bool */ protected $escapeLabels = true; - /** - * Whether only active branch should be rendered + * Whether only active branch should be rendered. * * @var bool */ protected $onlyActiveBranch = false; - /** - * Partial view script to use for rendering menu + * Partial view script to use for rendering menu. * * @var string|array */ protected $partial = null; - /** - * Whether parents should be rendered when only rendering active branch + * Whether parents should be rendered when only rendering active branch. * * @var bool */ protected $renderParents = true; - /** - * CSS class to use for the ul element + * CSS class to use for the ul element. * * @var string */ protected $ulClass = 'navigation'; - /** - * CSS class to use for the active li element + * CSS class to use for the active li element. * * @var string */ protected $liActiveClass = 'active'; - /** * View helper entry point: - * Retrieves helper and optionally sets container to operate on + * Retrieves helper and optionally sets container to operate on. + * + * @param AbstractContainer $container [optional] container to operate on * - * @param AbstractContainer $container [optional] container to operate on * @return self */ public function __invoke($container = null) @@ -83,9 +78,8 @@ public function __invoke($container = null) return $this; } - /** - * Renders menu + * Renders menu. * * Implements {@link HelperInterface::render()}. * @@ -96,8 +90,9 @@ public function __invoke($container = null) * @see renderPartial() * @see renderMenu() * - * @param AbstractContainer $container [optional] container to render. Default is - * to render the container registered in the helper. + * @param AbstractContainer $container [optional] container to render. Default is + * to render the container registered in the helper. + * * @return string */ public function render($container = null) @@ -109,19 +104,19 @@ public function render($container = null) return $this->renderMenu($container); } - /** * Renders the deepest active menu within [$minDepth, $maxDepth], (called - * from {@link renderMenu()}) - * - * @param AbstractContainer $container container to render - * @param string $ulClass CSS class for first UL - * @param string $indent initial indentation - * @param int|null $minDepth minimum depth - * @param int|null $maxDepth maximum depth - * @param bool $escapeLabels Whether or not to escape the labels - * @param bool $addClassToListItem Whether or not page class applied to
  • element - * @param string $liActiveClass CSS class for active LI + * from {@link renderMenu()}). + * + * @param AbstractContainer $container container to render + * @param string $ulClass CSS class for first UL + * @param string $indent initial indentation + * @param int|null $minDepth minimum depth + * @param int|null $maxDepth maximum depth + * @param bool $escapeLabels Whether or not to escape the labels + * @param bool $addClassToListItem Whether or not page class applied to
  • element + * @param string $liActiveClass CSS class for active LI + * * @return string */ protected function renderDeepestMenu( @@ -137,7 +132,6 @@ protected function renderDeepestMenu( if (!$active = $this->findActive($container, $minDepth - 1, $maxDepth)) { return ''; } - // special case if active page is one below minDepth if ($active['depth'] < $minDepth) { if (!$active['page']->hasPages(!$this->renderInvisible)) { @@ -146,21 +140,18 @@ protected function renderDeepestMenu( } elseif (!$active['page']->hasPages(!$this->renderInvisible)) { // found pages has no children; render siblings $active['page'] = $active['page']->getParent(); - } elseif (is_int($maxDepth) && $active['depth'] +1 > $maxDepth) { + } elseif (is_int($maxDepth) && $active['depth'] + 1 > $maxDepth) { // children are below max depth; render siblings $active['page'] = $active['page']->getParent(); } - /* @var $escaper \Zend\View\Helper\EscapeHtmlAttr */ $escaper = $this->view->plugin('escapeHtmlAttr'); - $ulClass = $ulClass ? ' class="' . $escaper($ulClass) . '"' : ''; - $html = $indent . '' . PHP_EOL; - + $ulClass = $ulClass ? ' class="'.$escaper($ulClass).'"' : ''; + $html = $indent.''.PHP_EOL; foreach ($active['page'] as $subPage) { if (!$this->accept($subPage)) { continue; } - // render li tag and page $liClasses = []; // Is page active? @@ -171,20 +162,17 @@ protected function renderDeepestMenu( if ($addClassToListItem && $subPage->getClass()) { $liClasses[] = $subPage->getClass(); } - $liClass = empty($liClasses) ? '' : ' class="' . $escaper(implode(' ', $liClasses)) . '"'; - - $html .= $indent . ' ' . PHP_EOL; - $html .= $indent . ' ' . $this->htmlify($subPage, $escapeLabels, $addClassToListItem) . PHP_EOL; - $html .= $indent . '
  • ' . PHP_EOL; + $liClass = empty($liClasses) ? '' : ' class="'.$escaper(implode(' ', $liClasses)).'"'; + $html .= $indent.' '.PHP_EOL; + $html .= $indent.' '.$this->htmlify($subPage, $escapeLabels, $addClassToListItem).PHP_EOL; + $html .= $indent.' '.PHP_EOL; } - - $html .= $indent . ''; + $html .= $indent.''; return $html; } - /** - * Renders helper + * Renders helper. * * Renders a HTML 'ul' for the given $container. If $container is not given, * the container registered in the helper will be used. @@ -192,10 +180,11 @@ protected function renderDeepestMenu( * Available $options: * * - * @param AbstractContainer $container [optional] container to create menu from. - * Default is to use the container retrieved - * from {@link getContainer()}. - * @param array $options [optional] options for controlling rendering + * @param AbstractContainer $container [optional] container to create menu from. + * Default is to use the container retrieved + * from {@link getContainer()}. + * @param array $options [optional] options for controlling rendering + * * @return string */ public function renderMenu($container = null, array $options = []) @@ -204,10 +193,7 @@ public function renderMenu($container = null, array $options = []) if (null === $container) { $container = $this->getContainer(); } - - $options = $this->normalizeOptions($options); - if ($options['onlyActiveBranch'] && !$options['renderParents']) { $html = $this->renderDeepestMenu( $container, @@ -235,19 +221,19 @@ public function renderMenu($container = null, array $options = []) return $html; } - /** - * Renders a normal menu (called from {@link renderMenu()}) - * - * @param AbstractContainer $container container to render - * @param string $ulClass CSS class for first UL - * @param string $indent initial indentation - * @param int|null $minDepth minimum depth - * @param int|null $maxDepth maximum depth - * @param bool $onlyActive render only active branch? - * @param bool $escapeLabels Whether or not to escape the labels - * @param bool $addClassToListItem Whether or not page class applied to
  • element - * @param string $liActiveClass CSS class for active LI + * Renders a normal menu (called from {@link renderMenu()}). + * + * @param AbstractContainer $container container to render + * @param string $ulClass CSS class for first UL + * @param string $indent initial indentation + * @param int|null $minDepth minimum depth + * @param int|null $maxDepth maximum depth + * @param bool $onlyActive render only active branch? + * @param bool $escapeLabels Whether or not to escape the labels + * @param bool $addClassToListItem Whether or not page class applied to
  • element + * @param string $liActiveClass CSS class for active LI + * * @return string */ protected function renderNormalMenu( @@ -262,19 +248,16 @@ protected function renderNormalMenu( $liActiveClass ) { $html = ''; - // find deepest active $found = $this->findActive($container, $minDepth, $maxDepth); /* @var $escaper \Zend\View\Helper\EscapeHtmlAttr */ $escaper = $this->view->plugin('escapeHtmlAttr'); - if ($found) { $foundPage = $found['page']; $foundDepth = $found['depth']; } else { $foundPage = null; } - // create iterator $iterator = new RecursiveIteratorIterator( $container, @@ -283,7 +266,6 @@ protected function renderNormalMenu( if (is_int($maxDepth)) { $iterator->setMaxDepth($maxDepth); } - // iterate container $prevDepth = -1; foreach ($iterator as $page) { @@ -309,38 +291,34 @@ protected function renderNormalMenu( } } } - if (!$accept) { continue; } } - // make sure indentation is correct $depth -= $minDepth; - $myIndent = $indent . str_repeat(' ', $depth); - + $myIndent = $indent.str_repeat(' ', $depth); if ($depth > $prevDepth) { // start new ul tag if ($ulClass && $depth == 0) { - $ulClass = ' class="' . $escaper($ulClass) . '"'; + $ulClass = ' class="'.$escaper($ulClass).'"'; } else { $ulClass = ''; } - $html .= $myIndent . '' . PHP_EOL; + $html .= $myIndent.''.PHP_EOL; } elseif ($prevDepth > $depth) { // close li/ul tags until we're at current depth for ($i = $prevDepth; $i > $depth; $i--) { - $ind = $indent . str_repeat(' ', $i); - $html .= $ind . '
  • ' . PHP_EOL; - $html .= $ind . '' . PHP_EOL; + $ind = $indent.str_repeat(' ', $i); + $html .= $ind.' '.PHP_EOL; + $html .= $ind.''.PHP_EOL; } // close previous li tag - $html .= $myIndent . ' ' . PHP_EOL; + $html .= $myIndent.' '.PHP_EOL; } else { // close previous li tag - $html .= $myIndent . ' ' . PHP_EOL; + $html .= $myIndent.' '.PHP_EOL; } - // render li tag and page $liClasses = []; // Is page active? @@ -351,90 +329,82 @@ protected function renderNormalMenu( if ($addClassToListItem && $page->getClass()) { $liClasses[] = $page->getClass(); } - $liClass = empty($liClasses) ? '' : ' class="' . $escaper(implode(' ', $liClasses)) . '"'; - - $html .= $myIndent . ' ' . PHP_EOL - . $myIndent . ' ' . $this->htmlify($page, $escapeLabels, $addClassToListItem) . PHP_EOL; - + $liClass = empty($liClasses) ? '' : ' class="'.$escaper(implode(' ', $liClasses)).'"'; + $html .= $myIndent.' '.PHP_EOL + .$myIndent.' '.$this->htmlify($page, $escapeLabels, $addClassToListItem).PHP_EOL; // store as previous depth for next iteration $prevDepth = $depth; } - if ($html) { // done iterating container; close open ul/li tags - for ($i = $prevDepth+1; $i > 0; $i--) { - $myIndent = $indent . str_repeat(' ', $i-1); - $html .= $myIndent . ' ' . PHP_EOL - . $myIndent . '' . PHP_EOL; + for ($i = $prevDepth + 1; $i > 0; $i--) { + $myIndent = $indent.str_repeat(' ', $i - 1); + $html .= $myIndent.' '.PHP_EOL + .$myIndent.''.PHP_EOL; } $html = rtrim($html, PHP_EOL); } return $html; } - /** - * Renders the given $container by invoking the partial view helper + * Renders the given $container by invoking the partial view helper. * * The container will simply be passed on as a model to the view script * as-is, and will be available in the partial script as 'container', e.g. * echo 'Number of pages: ', count($this->container);. * - * @param AbstractContainer $container [optional] container to pass to view - * script. Default is to use the container - * registered in the helper. - * @param string|array $partial [optional] partial view script to use. - * Default is to use the partial - * registered in the helper. If an array - * is given, it is expected to contain two - * values; the partial view script to use, - * and the module where the script can be - * found. + * @param null|AbstractContainer $container [optional] container to pass to view + * script. Default is to use the container + * registered in the helper. + * @param null|string|array $partial [optional] partial view script to use. + * Default is to use the partial + * registered in the helper. If an array + * is given, it is expected to contain two + * values; the partial view script to use, + * and the module where the script can be + * found. + * * @return string - * @throws Exception\RuntimeException if no partial provided + * + * @throws Exception\RuntimeException if no partial provided * @throws Exception\InvalidArgumentException if partial is invalid array */ public function renderPartial($container = null, $partial = null) { - $this->parseContainer($container); - if (null === $container) { - $container = $this->getContainer(); - } - - if (null === $partial) { - $partial = $this->getPartial(); - } - - if (empty($partial)) { - throw new Exception\RuntimeException( - 'Unable to render menu: No partial view script provided' - ); - } - - $model = [ - 'container' => $container - ]; - - /** @var \Zend\View\Helper\Partial $partialHelper */ - $partialHelper = $this->view->plugin('partial'); - - if (is_array($partial)) { - if (count($partial) != 2) { - throw new Exception\InvalidArgumentException( - 'Unable to render menu: A view partial supplied as ' - . 'an array must contain two values: partial view ' - . 'script and module where script can be found' - ); - } - - return $partialHelper($partial[0], $model); - } - - return $partialHelper($partial, $model); + return $this->renderPartialModel([], $container, $partial); + } + /** + * Renders the given $container by invoking the partial view helper with the given parameters as the model. + * + * The container will simply be passed on as a model to the view script + * as-is, and will be available in the partial script as 'container', e.g. + * echo 'Number of pages: ', count($this->container);. + * + * Any parameters provided will be passed to the partial via the view model. + * + * @param null|AbstractContainer $container [optional] container to pass to view + * script. Default is to use the container + * registered in the helper. + * @param null|string|array $partial [optional] partial view script to use. + * Default is to use the partial + * registered in the helper. If an array + * is given, it is expected to contain two + * values; the partial view script to use, + * and the module where the script can be + * found. + * + * @return string + * + * @throws Exception\RuntimeException if no partial provided + * @throws Exception\InvalidArgumentException if partial is invalid array + */ + public function renderPartialWithParams(array $params = [], $container = null, $partial = null) + { + return $this->renderPartialModel($params, $container, $partial); } - /** - * Renders the inner-most sub menu for the active page in the $container + * Renders the inner-most sub menu for the active page in the $container. * * This is a convenience method which is equivalent to the following call: * @@ -449,23 +419,24 @@ public function renderPartial($container = null, $partial = null) * )); * * - * @param AbstractContainer $container [optional] container to - * render. Default is to render - * the container registered in - * the helper. - * @param string $ulClass [optional] CSS class to - * use for UL element. Default - * is to use the value from - * {@link getUlClass()}. - * @param string|int $indent [optional] indentation as - * a string or number of - * spaces. Default is to use - * the value retrieved from - * {@link getIndent()}. - * @param string $liActiveClass [optional] CSS class to - * use for UL element. Default - * is to use the value from - * {@link getUlClass()}. + * @param AbstractContainer $container [optional] container to + * render. Default is to render + * the container registered in + * the helper. + * @param string $ulClass [optional] CSS class to + * use for UL element. Default + * is to use the value from + * {@link getUlClass()}. + * @param string|int $indent [optional] indentation as + * a string or number of + * spaces. Default is to use + * the value retrieved from + * {@link getIndent()}. + * @param string $liActiveClass [optional] CSS class to + * use for UL element. Default + * is to use the value from + * {@link getUlClass()}. + * * @return string */ public function renderSubMenu( @@ -483,19 +454,19 @@ public function renderSubMenu( 'renderParents' => false, 'escapeLabels' => true, 'addClassToListItem' => false, - 'liActiveClass' => $liActiveClass + 'liActiveClass' => $liActiveClass, ]); } - /** * Returns an HTML string containing an 'a' element for the given page if - * the page's href is not empty, and a 'span' element if it is empty + * the page's href is not empty, and a 'span' element if it is empty. * * Overrides {@link AbstractHelper::htmlify()}. * - * @param AbstractPage $page page to generate HTML for - * @param bool $escapeLabel Whether or not to escape the label - * @param bool $addClassToListItem Whether or not to add the page class to the list item + * @param AbstractPage $page page to generate HTML for + * @param bool $escapeLabel Whether or not to escape the label + * @param bool $addClassToListItem Whether or not to add the page class to the list item + * * @return string */ public function htmlify(AbstractPage $page, $escapeLabel = true, $addClassToListItem = false) @@ -505,11 +476,9 @@ public function htmlify(AbstractPage $page, $escapeLabel = true, $addClassToList 'id' => $page->getId(), 'title' => $this->translate($page->getTitle(), $page->getTextDomain()), ]; - if ($addClassToListItem === false) { $attribs['class'] = $page->getClass(); } - // does page have a href? $href = $page->getHref(); if ($href) { @@ -519,8 +488,7 @@ public function htmlify(AbstractPage $page, $escapeLabel = true, $addClassToList } else { $element = 'span'; } - - $html = '<' . $element . $this->htmlAttribs($attribs) . '>'; + $html = '<'.$element.$this->htmlAttribs($attribs).'>'; $label = $this->translate($page->getLabel(), $page->getTextDomain()); if ($escapeLabel === true) { /** @var \Zend\View\Helper\EscapeHtml $escaper */ @@ -529,15 +497,15 @@ public function htmlify(AbstractPage $page, $escapeLabel = true, $addClassToList } else { $html .= $label; } - $html .= ''; + $html .= ''; return $html; } - /** - * Normalizes given render options + * Normalizes given render options. + * + * @param array $options [optional] options to normalize * - * @param array $options [optional] options to normalize * @return array */ protected function normalizeOptions(array $options = []) @@ -547,13 +515,11 @@ protected function normalizeOptions(array $options = []) } else { $options['indent'] = $this->getIndent(); } - if (isset($options['ulClass']) && $options['ulClass'] !== null) { $options['ulClass'] = (string) $options['ulClass']; } else { $options['ulClass'] = $this->getUlClass(); } - if (array_key_exists('minDepth', $options)) { if (null !== $options['minDepth']) { $options['minDepth'] = (int) $options['minDepth']; @@ -561,11 +527,9 @@ protected function normalizeOptions(array $options = []) } else { $options['minDepth'] = $this->getMinDepth(); } - if ($options['minDepth'] < 0 || $options['minDepth'] === null) { $options['minDepth'] = 0; } - if (array_key_exists('maxDepth', $options)) { if (null !== $options['maxDepth']) { $options['maxDepth'] = (int) $options['maxDepth']; @@ -573,23 +537,18 @@ protected function normalizeOptions(array $options = []) } else { $options['maxDepth'] = $this->getMaxDepth(); } - if (!isset($options['onlyActiveBranch'])) { $options['onlyActiveBranch'] = $this->getOnlyActiveBranch(); } - if (!isset($options['escapeLabels'])) { $options['escapeLabels'] = $this->escapeLabels; } - if (!isset($options['renderParents'])) { $options['renderParents'] = $this->getRenderParents(); } - if (!isset($options['addClassToListItem'])) { $options['addClassToListItem'] = $this->getAddClassToListItem(); } - if (isset($options['liActiveClass']) && $options['liActiveClass'] !== null) { $options['liActiveClass'] = (string) $options['liActiveClass']; } else { @@ -598,58 +557,59 @@ protected function normalizeOptions(array $options = []) return $options; } - /** - * Sets a flag indicating whether labels should be escaped + * Sets a flag indicating whether labels should be escaped. * * @param bool $flag [optional] escape labels + * * @return self */ public function escapeLabels($flag = true) { $this->escapeLabels = (bool) $flag; + return $this; } - /** - * Enables/disables page class applied to
  • element + * Enables/disables page class applied to
  • element. + * + * @param bool $flag [optional] page class applied to
  • element + * Default is true. * - * @param bool $flag [optional] page class applied to
  • element - * Default is true. - * @return self fluent interface, returns self + * @return self fluent interface, returns self */ public function setAddClassToListItem($flag = true) { $this->addClassToListItem = (bool) $flag; + return $this; } - /** - * Returns flag indicating whether page class should be applied to
  • element + * Returns flag indicating whether page class should be applied to
  • element. * * By default, this value is false. * - * @return bool whether parents should be rendered + * @return bool whether parents should be rendered */ public function getAddClassToListItem() { return $this->addClassToListItem; } - /** - * Sets a flag indicating whether only active branch should be rendered + * Sets a flag indicating whether only active branch should be rendered. + * + * @param bool $flag [optional] render only active branch. * - * @param bool $flag [optional] render only active branch. * @return self */ public function setOnlyActiveBranch($flag = true) { $this->onlyActiveBranch = (bool) $flag; + return $this; } - /** - * Returns a flag indicating whether only active branch should be rendered + * Returns a flag indicating whether only active branch should be rendered. * * By default, this value is false, meaning the entire menu will be * be rendered. @@ -660,15 +620,15 @@ public function getOnlyActiveBranch() { return $this->onlyActiveBranch; } - /** - * Sets which partial view script to use for rendering menu + * Sets which partial view script to use for rendering menu. + * + * @param string|array $partial partial view script or null. If an array is + * given, it is expected to contain two + * values; the partial view script to use, + * and the module where the script can be + * found. * - * @param string|array $partial partial view script or null. If an array is - * given, it is expected to contain two - * values; the partial view script to use, - * and the module where the script can be - * found. * @return self */ public function setPartial($partial) @@ -679,9 +639,8 @@ public function setPartial($partial) return $this; } - /** - * Returns partial view script to use for rendering menu + * Returns partial view script to use for rendering menu. * * @return string|array|null */ @@ -689,24 +648,24 @@ public function getPartial() { return $this->partial; } - /** - * Enables/disables rendering of parents when only rendering active branch + * Enables/disables rendering of parents when only rendering active branch. * * See {@link setOnlyActiveBranch()} for more information. * - * @param bool $flag [optional] render parents when rendering active branch. + * @param bool $flag [optional] render parents when rendering active branch. + * * @return self */ public function setRenderParents($flag = true) { $this->renderParents = (bool) $flag; + return $this; } - /** * Returns flag indicating whether parents should be rendered when rendering - * only the active branch + * only the active branch. * * By default, this value is true. * @@ -716,11 +675,11 @@ public function getRenderParents() { return $this->renderParents; } - /** - * Sets CSS class to use for the first 'ul' element when rendering + * Sets CSS class to use for the first 'ul' element when rendering. + * + * @param string $ulClass CSS class to set * - * @param string $ulClass CSS class to set * @return self */ public function setUlClass($ulClass) @@ -731,9 +690,8 @@ public function setUlClass($ulClass) return $this; } - /** - * Returns CSS class to use for the first 'ul' element when rendering + * Returns CSS class to use for the first 'ul' element when rendering. * * @return string */ @@ -741,11 +699,11 @@ public function getUlClass() { return $this->ulClass; } - /** - * Sets CSS class to use for the active 'li' element when rendering + * Sets CSS class to use for the active 'li' element when rendering. + * + * @param string $liActiveClass CSS class to set * - * @param string $liActiveClass CSS class to set * @return self */ public function setLiActiveClass($liActiveClass) @@ -756,9 +714,8 @@ public function setLiActiveClass($liActiveClass) return $this; } - /** - * Returns CSS class to use for the active 'li' element when rendering + * Returns CSS class to use for the active 'li' element when rendering. * * @return string */ @@ -766,4 +723,47 @@ public function getLiActiveClass() { return $this->liActiveClass; } + /** + * Render a partial with the given "model". + * + * @param array $params + * @param null|AbstractContainer $container + * @param null|string|array $partial + * + * @return string + * + * @throws Exception\RuntimeException if no partial provided + * @throws Exception\InvalidArgumentException if partial is invalid array + */ + protected function renderPartialModel(array $params, $container, $partial) + { + $this->parseContainer($container); + if (null === $container) { + $container = $this->getContainer(); + } + if (null === $partial) { + $partial = $this->getPartial(); + } + if (empty($partial)) { + throw new Exception\RuntimeException( + 'Unable to render menu: No partial view script provided' + ); + } + $model = array_merge($params, ['container' => $container]); + /** @var \Zend\View\Helper\Partial $partialHelper */ + $partialHelper = $this->view->plugin('partial'); + if (is_array($partial)) { + if (count($partial) != 2) { + throw new Exception\InvalidArgumentException( + 'Unable to render menu: A view partial supplied as ' + .'an array must contain two values: partial view ' + .'script and module where script can be found' + ); + } + + return $partialHelper($partial[0], $model); + } + + return $partialHelper($partial, $model); + } } diff --git a/test/Helper/Navigation/BreadcrumbsTest.php b/test/Helper/Navigation/BreadcrumbsTest.php index ab29c5ca..3001ea65 100644 --- a/test/Helper/Navigation/BreadcrumbsTest.php +++ b/test/Helper/Navigation/BreadcrumbsTest.php @@ -1,19 +1,20 @@ setServiceLocator($this->serviceManager); $this->_helper->setServiceLocator($pm); @@ -137,13 +138,13 @@ public function testRenderSuppliedContainerWithoutInterfering() $expected = [ 'registered' => $rendered1, 'supplied' => $rendered2, - 'registered_again' => $rendered1 + 'registered_again' => $rendered1, ]; $actual = [ 'registered' => $this->_helper->render(), 'supplied' => $this->_helper->render($this->_nav2), - 'registered_again' => $this->_helper->render() + 'registered_again' => $this->_helper->render(), ]; $this->assertEquals($expected, $actual); @@ -244,14 +245,22 @@ public function testRenderingPartialShouldFailOnInvalidPartialArray() } } + public function testRenderingPartialWithParams() + { + $this->_helper->setPartial('bc_with_partial_params.phtml')->setSeparator(' / '); + $expected = $this->_getExpected('bc/partial_with_params.html'); + $actual = $this->_helper->renderPartialWithParams(['variable' => 'test value']); + $this->assertEquals($expected, $actual); + } + public function testLastBreadcrumbShouldBeEscaped() { $container = new Navigation([ [ 'label' => 'Live & Learn', 'uri' => '#', - 'active' => true - ] + 'active' => true, + ], ]); $expected = 'Live & Learn'; diff --git a/test/Helper/Navigation/MenuTest.php b/test/Helper/Navigation/MenuTest.php index a2876942..36796a48 100644 --- a/test/Helper/Navigation/MenuTest.php +++ b/test/Helper/Navigation/MenuTest.php @@ -1,16 +1,17 @@ $this->_getExpected('menu/indent4.html'), - 'indent8' => $this->_getExpected('menu/indent8.html') + 'indent8' => $this->_getExpected('menu/indent8.html'), ]; $renderOptions = [ - 'indent' => 4 + 'indent' => 4, ]; $actual = [ 'indent4' => rtrim($this->_helper->renderMenu(null, $renderOptions), PHP_EOL), - 'indent8' => rtrim($this->_helper->renderMenu(), PHP_EOL) + 'indent8' => rtrim($this->_helper->renderMenu(), PHP_EOL), ]; $this->assertEquals($expected, $actual); @@ -96,13 +97,13 @@ public function testRenderSuppliedContainerWithoutInterfering() $expected = [ 'registered' => $rendered1, 'supplied' => $rendered2, - 'registered_again' => $rendered1 + 'registered_again' => $rendered1, ]; $actual = [ 'registered' => $this->_helper->render(), 'supplied' => $this->_helper->render($this->_nav2), - 'registered_again' => $this->_helper->render() + 'registered_again' => $this->_helper->render(), ]; $this->assertEquals($expected, $actual); @@ -180,13 +181,13 @@ public function testSetLiActiveCssClass() public function testOptionEscapeLabelsAsTrue() { $options = [ - 'escapeLabels' => true + 'escapeLabels' => true, ]; $container = new \Zend\Navigation\Navigation($this->_nav2->toArray()); $container->addPage([ 'label' => 'Badges 1', - 'uri' => 'badges' + 'uri' => 'badges', ]); $expected = $this->_getExpected('menu/escapelabels_as_true.html'); @@ -198,13 +199,13 @@ public function testOptionEscapeLabelsAsTrue() public function testOptionEscapeLabelsAsFalse() { $options = [ - 'escapeLabels' => false + 'escapeLabels' => false, ]; $container = new \Zend\Navigation\Navigation($this->_nav2->toArray()); $container->addPage([ 'label' => 'Badges 1', - 'uri' => 'badges' + 'uri' => 'badges', ]); $expected = $this->_getExpected('menu/escapelabels_as_false.html'); @@ -283,6 +284,14 @@ public function testRenderingPartialBySpecifyingAnArrayAsPartial() $this->assertEquals($expected, $actual); } + public function testRenderingPartialWithParams() + { + $this->_helper->setPartial(['menu_with_partial_params.phtml', 'application']); + $expected = $this->_getExpected('menu/partial_with_params.html'); + $actual = $this->_helper->renderPartialWithParams(['variable' => 'test value']); + $this->assertEquals($expected, $actual); + } + public function testRenderingPartialShouldFailOnInvalidPartialArray() { $this->_helper->setPartial(['menu.phtml']); @@ -431,7 +440,7 @@ public function testRenderSubMenuShouldOverrideOptions() public function testOptionMaxDepth() { $options = [ - 'maxDepth' => 1 + 'maxDepth' => 1, ]; $expected = $this->_getExpected('menu/maxdepth.html'); @@ -443,7 +452,7 @@ public function testOptionMaxDepth() public function testOptionMinDepth() { $options = [ - 'minDepth' => 1 + 'minDepth' => 1, ]; $expected = $this->_getExpected('menu/mindepth.html'); @@ -456,7 +465,7 @@ public function testOptionBothDepts() { $options = [ 'minDepth' => 1, - 'maxDepth' => 2 + 'maxDepth' => 2, ]; $expected = $this->_getExpected('menu/bothdepts.html'); @@ -468,7 +477,7 @@ public function testOptionBothDepts() public function testOptionOnlyActiveBranch() { $options = [ - 'onlyActiveBranch' => true + 'onlyActiveBranch' => true, ]; $expected = $this->_getExpected('menu/onlyactivebranch.html'); @@ -481,7 +490,7 @@ public function testOptionOnlyActiveBranchNoParents() { $options = [ 'onlyActiveBranch' => true, - 'renderParents' => false + 'renderParents' => false, ]; $expected = $this->_getExpected('menu/onlyactivebranch_noparents.html'); @@ -494,7 +503,7 @@ public function testOptionOnlyActiveBranchAndMinDepth() { $options = [ 'minDepth' => 1, - 'onlyActiveBranch' => true + 'onlyActiveBranch' => true, ]; $expected = $this->_getExpected('menu/onlyactivebranch_mindepth.html'); @@ -507,7 +516,7 @@ public function testOptionOnlyActiveBranchAndMaxDepth() { $options = [ 'maxDepth' => 2, - 'onlyActiveBranch' => true + 'onlyActiveBranch' => true, ]; $expected = $this->_getExpected('menu/onlyactivebranch_maxdepth.html'); @@ -521,7 +530,7 @@ public function testOptionOnlyActiveBranchAndBothDepthsSpecified() $options = [ 'minDepth' => 1, 'maxDepth' => 2, - 'onlyActiveBranch' => true + 'onlyActiveBranch' => true, ]; $expected = $this->_getExpected('menu/onlyactivebranch_bothdepts.html'); @@ -536,7 +545,7 @@ public function testOptionOnlyActiveBranchNoParentsAndBothDepthsSpecified() 'minDepth' => 2, 'maxDepth' => 2, 'onlyActiveBranch' => true, - 'renderParents' => false + 'renderParents' => false, ]; $expected = $this->_getExpected('menu/onlyactivebranch_np_bd.html'); @@ -598,8 +607,10 @@ public function testRenderDeepestMenuWithPageClassToLi() } /** - * Returns the contens of the expected $file, normalizes newlines - * @param string $file + * Returns the contens of the expected $file, normalizes newlines. + * + * @param string $file + * * @return string */ protected function _getExpected($file) diff --git a/test/Helper/Navigation/_files/expected/bc/partial_with_params.html b/test/Helper/Navigation/_files/expected/bc/partial_with_params.html new file mode 100644 index 00000000..7f33c62e --- /dev/null +++ b/test/Helper/Navigation/_files/expected/bc/partial_with_params.html @@ -0,0 +1,2 @@ +test value +Page 2 / Page 2.3 / Page 2.3.3 / Page 2.3.3.1 \ No newline at end of file diff --git a/test/Helper/Navigation/_files/expected/menu/partial_with_params.html b/test/Helper/Navigation/_files/expected/menu/partial_with_params.html new file mode 100644 index 00000000..9edc0b02 --- /dev/null +++ b/test/Helper/Navigation/_files/expected/menu/partial_with_params.html @@ -0,0 +1,3 @@ +test value +Is a container: yes +Pages: Home, Page 1, Page 2, Page 3, Zym \ No newline at end of file diff --git a/test/Helper/Navigation/_files/mvc/views/bc_with_partial_params.phtml b/test/Helper/Navigation/_files/mvc/views/bc_with_partial_params.phtml new file mode 100644 index 00000000..1a34cbf4 --- /dev/null +++ b/test/Helper/Navigation/_files/mvc/views/bc_with_partial_params.phtml @@ -0,0 +1,5 @@ +variable . PHP_EOL; +echo implode($this->vars()->separator, array_map( + create_function('$a', 'return $a->getLabel();'), + $this->vars()->pages)); \ No newline at end of file diff --git a/test/Helper/Navigation/_files/mvc/views/menu_with_partial_params.phtml b/test/Helper/Navigation/_files/mvc/views/menu_with_partial_params.phtml new file mode 100644 index 00000000..d3a12af6 --- /dev/null +++ b/test/Helper/Navigation/_files/mvc/views/menu_with_partial_params.phtml @@ -0,0 +1,13 @@ +vars('container') instanceof \Zend\Navigation\AbstractContainer + ? 'yes' + : 'no'; +echo $this->variable . PHP_EOL; +$pages = array(); +foreach ($this->vars('container') as $page) { + $pages[] = $page->getLabel(); +} +$pages = implode(', ', $pages); +?> +Is a container: +Pages: