From ff7fe969e7c14b4a3e3bc234f9b78f32527f8a43 Mon Sep 17 00:00:00 2001 From: Christophe Coevoet Date: Tue, 17 Apr 2012 22:54:57 +0200 Subject: [PATCH 1/2] Added a first implementation of a BreadcrumbRenderer --- src/Knp/Menu/Renderer/BreadcrumbRenderer.php | 142 +++++++++++++++++++ 1 file changed, 142 insertions(+) create mode 100644 src/Knp/Menu/Renderer/BreadcrumbRenderer.php diff --git a/src/Knp/Menu/Renderer/BreadcrumbRenderer.php b/src/Knp/Menu/Renderer/BreadcrumbRenderer.php new file mode 100644 index 00000000..4568066c --- /dev/null +++ b/src/Knp/Menu/Renderer/BreadcrumbRenderer.php @@ -0,0 +1,142 @@ +defaultOptions = array_merge(array( + 'additional_path' => null, + 'compressed' => false, + 'root_attributes' => array(), + ), $defaultOptions); + + parent::__construct($charset); + } + + /** + * Renders a menu with the specified renderer. + * + * @param \Knp\Menu\ItemInterface $item + * @param array $options + * @return string + */ + public function render(ItemInterface $item, array $options = array()) + { + $options = array_merge($this->defaultOptions, $options); + + $breadcrumb = $item->getBreadcrumbsArray($options['additional_path']); + + if (empty($breadcrumb)) { + return ''; + } + + return $this->renderBreadcrumb($breadcrumb, $options); + } + + /** + * Renders the breadcrumb + * + * @param array $breadcrumb + * @param array $options + * @return string + */ + protected function renderBreadcrumb(array $breadcrumb, array $options) + { + $html = $this->format('renderHtmlAttributes($options['root_attributes']).'>', 'ul', 0, $options); + $html .= $this->renderList($breadcrumb, $options); + $html .= $this->format('', 'ul', 0, $options); + + return $html; + } + + /** + * Renders the breadcrumb list + * + * @param array $breadcrumb + * @param array $options + * @return string + */ + protected function renderList(array $breadcrumb, array $options) + { + $html = ''; + foreach ($breadcrumb as $label => $uri) { + $html .= $this->renderItem($label, $uri, $options); + } + + return $html; + } + + /** + * @param string $label + * @param string $uri + * @param array $options + * @return string + */ + protected function renderItem($label, $uri, array $options) + { + // opening li tag + $html = $this->format('
  • ', 'li', 1, $options); + + // render the text/link inside the li tag + if (null === $uri) { + $content = $this->renderLabel($label, $options); + } else { + $content = sprintf('%s', $this->escape($uri), $this->renderLabel($label, $options)); + } + $html .= $this->format($content, 'link', 1, $options); + + // closing li tag + $html .= $this->format('
  • ', 'li', 1, $options); + + return $html; + } + + protected function renderLabel($label, array $options) + { + return $this->escape($label); + } + + /** + * If $this->renderCompressed is on, this will apply the necessary + * spacing and line-breaking so that the particular thing being rendered + * makes up its part in a fully-rendered and spaced menu. + * + * @param string $html The html to render in an (un)formatted way + * @param string $type The type [ul,link,li] of thing being rendered + * @param integer $level + * @param array $options + * @return string + */ + protected function format($html, $type, $level, array $options) + { + if ($options['compressed']) { + return $html; + } + + switch ($type) { + case 'ul': + case 'link': + $spacing = $level * 4; + break; + + case 'li': + $spacing = $level * 4 - 2; + break; + } + + return str_repeat(' ', $spacing).$html."\n"; + } +} From bffbbacd435b75cc7d7f51e95c0266ff6c32d8d2 Mon Sep 17 00:00:00 2001 From: Christophe Coevoet Date: Thu, 17 May 2012 16:05:55 +0200 Subject: [PATCH 2/2] Updated the BreadcrumbRenderer for the new format, added options and tests --- src/Knp/Menu/Renderer/BreadcrumbRenderer.php | 36 ++++-- .../Tests/Renderer/BreadcrumbRendererTest.php | 115 ++++++++++++++++++ 2 files changed, 142 insertions(+), 9 deletions(-) create mode 100644 tests/Knp/Menu/Tests/Renderer/BreadcrumbRendererTest.php diff --git a/src/Knp/Menu/Renderer/BreadcrumbRenderer.php b/src/Knp/Menu/Renderer/BreadcrumbRenderer.php index 4568066c..a7aab600 100644 --- a/src/Knp/Menu/Renderer/BreadcrumbRenderer.php +++ b/src/Knp/Menu/Renderer/BreadcrumbRenderer.php @@ -2,7 +2,7 @@ namespace Knp\Menu\Renderer; -use \Knp\Menu\ItemInterface; +use Knp\Menu\ItemInterface; /** * Renders MenuItem tree as a breadcrumb @@ -18,8 +18,11 @@ class BreadcrumbRenderer extends Renderer implements RendererInterface public function __construct(array $defaultOptions = array(), $charset = null) { $this->defaultOptions = array_merge(array( + 'current_as_link' => true, + 'current_class' => 'current', 'additional_path' => null, 'compressed' => false, + 'allow_safe_labels' => false, 'root_attributes' => array(), ), $defaultOptions); @@ -72,8 +75,9 @@ protected function renderBreadcrumb(array $breadcrumb, array $options) protected function renderList(array $breadcrumb, array $options) { $html = ''; - foreach ($breadcrumb as $label => $uri) { - $html .= $this->renderItem($label, $uri, $options); + foreach ($breadcrumb as $element) { + $element = array_replace(array('label' => null, 'uri' => null, 'item' => null), $element); + $html .= $this->renderItem($element['label'], $element['uri'], $options, $element['item']); } return $html; @@ -83,18 +87,22 @@ protected function renderList(array $breadcrumb, array $options) * @param string $label * @param string $uri * @param array $options + * @param \Knp\Menu\ItemInterface|null $item * @return string */ - protected function renderItem($label, $uri, array $options) + protected function renderItem($label, $uri, array $options, ItemInterface $item = null) { + $isCurrent = null !== $item && $item->isCurrent(); + $attributes = $isCurrent ? array('class' => $options['current_class']) : array(); + // opening li tag - $html = $this->format('
  • ', 'li', 1, $options); + $html = $this->format('renderHtmlAttributes($attributes).'>', 'li', 1, $options); // render the text/link inside the li tag - if (null === $uri) { - $content = $this->renderLabel($label, $options); + if (null === $uri || ($isCurrent && !$options['current_as_link'])) { + $content = $this->renderLabel($label, $options, $item); } else { - $content = sprintf('%s', $this->escape($uri), $this->renderLabel($label, $options)); + $content = sprintf('%s', $this->escape($uri), $this->renderLabel($label, $options, $item)); } $html .= $this->format($content, 'link', 1, $options); @@ -104,8 +112,18 @@ protected function renderItem($label, $uri, array $options) return $html; } - protected function renderLabel($label, array $options) + /** + * @param string $label + * @param array $options + * @param \Knp\Menu\ItemInterface|null $item + * @return string + */ + protected function renderLabel($label, array $options, ItemInterface $item = null) { + if ($options['allow_safe_labels'] && null !== $item && $item->getExtra('safe_label', false)) { + return $item->getLabel(); + } + return $this->escape($label); } diff --git a/tests/Knp/Menu/Tests/Renderer/BreadcrumbRendererTest.php b/tests/Knp/Menu/Tests/Renderer/BreadcrumbRendererTest.php new file mode 100644 index 00000000..f01b5f24 --- /dev/null +++ b/tests/Knp/Menu/Tests/Renderer/BreadcrumbRendererTest.php @@ -0,0 +1,115 @@ + true)); + + $expected = '
    • Root li
    • Parent 1
    • Child 1
    '; + + $this->assertEquals($expected, $renderer->render($this->ch1)); + } + + public function testAdditionalPath() + { + $renderer = new BreadcrumbRenderer(array('compressed' => true)); + + $expected = '
    • Root li
    • Parent 1
    • Child 1
    • Foo
    '; + + $this->assertEquals($expected, $renderer->render($this->ch1, array('additional_path' => array('Foo' => 'http://example.com')))); + } + + public function testCurrentLink() + { + $this->pt1->setUri('foobar')->setCurrent(true); + + $renderer = new BreadcrumbRenderer(array('compressed' => true)); + + $expected = ''; + + $this->assertEquals($expected, $renderer->render($this->ch1)); + } + + public function testCurrentNoLink() + { + $this->pt1->setUri('foobar')->setCurrent(true); + + $renderer = new BreadcrumbRenderer(array('compressed' => true, 'current_as_link' => false)); + + $expected = '
    • Root li
    • Parent 1
    • Child 1
    '; + + $this->assertEquals($expected, $renderer->render($this->ch1)); + } + + public function testCurrentCustomClass() + { + $this->pt1->setCurrent(true); + + $renderer = new BreadcrumbRenderer(array('compressed' => true, 'current_class' => 'foo')); + + $expected = '
    • Root li
    • Parent 1
    • Child 1
    '; + + $this->assertEquals($expected, $renderer->render($this->ch1)); + } + + public function testEscapedLabel() + { + $this->pt1->setExtra('safe_label', true)->setLabel('Foo'); + + $renderer = new BreadcrumbRenderer(array('compressed' => true)); + + $expected = '
    • Root li
    • <strong>Foo</strong>
    • Child 1
    '; + + $this->assertEquals($expected, $renderer->render($this->ch1)); + } + + public function testUnsafeLabel() + { + $this->pt1->setLabel('Foo'); + + $renderer = new BreadcrumbRenderer(array('compressed' => true, 'allow_safe_labels' => true)); + + $expected = '
    • Root li
    • <strong>Foo</strong>
    • Child 1
    '; + + $this->assertEquals($expected, $renderer->render($this->ch1)); + } + + public function testSafeLabel() + { + $this->pt1->setExtra('safe_label', true)->setLabel('Foo'); + + $renderer = new BreadcrumbRenderer(array('compressed' => true, 'allow_safe_labels' => true)); + + $expected = '
    • Root li
    • Foo
    • Child 1
    '; + + $this->assertEquals($expected, $renderer->render($this->ch1)); + } + + public function testPrettyRendering() + { + $renderer = new BreadcrumbRenderer(); + + $rendered = << +
  • + Root li +
  • +
  • + Parent 1 +
  • +
  • + Child 1 +
  • + + +HTML; + + $this->assertEquals($rendered, $renderer->render($this->ch1)); + } +}