PageRenderTime 46ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/library/Zend/View/Helper/Navigation/Links.php

https://bitbucket.org/rtsukui/jelly2
PHP | 783 lines | 381 code | 74 blank | 328 comment | 56 complexity | 618f837cd8f12a003099fe005b05aebd MD5 | raw file
Possible License(s): BSD-3-Clause
  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: Links.php 23775 2011-03-01 17:25:24Z ralph $
  21. */
  22. /**
  23. * @see Zend_View_Helper_Navigation_HelperAbstract
  24. */
  25. require_once 'Zend/View/Helper/Navigation/HelperAbstract.php';
  26. /**
  27. * Helper for printing <link> elements
  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_Links
  36. extends Zend_View_Helper_Navigation_HelperAbstract
  37. {
  38. /**#@+
  39. * Constants used for specifying which link types to find and render
  40. *
  41. * @var int
  42. */
  43. const RENDER_ALTERNATE = 0x0001;
  44. const RENDER_STYLESHEET = 0x0002;
  45. const RENDER_START = 0x0004;
  46. const RENDER_NEXT = 0x0008;
  47. const RENDER_PREV = 0x0010;
  48. const RENDER_CONTENTS = 0x0020;
  49. const RENDER_INDEX = 0x0040;
  50. const RENDER_GLOSSARY = 0x0080;
  51. const RENDER_COPYRIGHT = 0x0100;
  52. const RENDER_CHAPTER = 0x0200;
  53. const RENDER_SECTION = 0x0400;
  54. const RENDER_SUBSECTION = 0x0800;
  55. const RENDER_APPENDIX = 0x1000;
  56. const RENDER_HELP = 0x2000;
  57. const RENDER_BOOKMARK = 0x4000;
  58. const RENDER_CUSTOM = 0x8000;
  59. const RENDER_ALL = 0xffff;
  60. /**#@+**/
  61. /**
  62. * Maps render constants to W3C link types
  63. *
  64. * @var array
  65. */
  66. protected static $_RELATIONS = array(
  67. self::RENDER_ALTERNATE => 'alternate',
  68. self::RENDER_STYLESHEET => 'stylesheet',
  69. self::RENDER_START => 'start',
  70. self::RENDER_NEXT => 'next',
  71. self::RENDER_PREV => 'prev',
  72. self::RENDER_CONTENTS => 'contents',
  73. self::RENDER_INDEX => 'index',
  74. self::RENDER_GLOSSARY => 'glossary',
  75. self::RENDER_COPYRIGHT => 'copyright',
  76. self::RENDER_CHAPTER => 'chapter',
  77. self::RENDER_SECTION => 'section',
  78. self::RENDER_SUBSECTION => 'subsection',
  79. self::RENDER_APPENDIX => 'appendix',
  80. self::RENDER_HELP => 'help',
  81. self::RENDER_BOOKMARK => 'bookmark'
  82. );
  83. /**
  84. * The helper's render flag
  85. *
  86. * @see render()
  87. * @see setRenderFlag()
  88. * @var int
  89. */
  90. protected $_renderFlag = self::RENDER_ALL;
  91. /**
  92. * Root container
  93. *
  94. * Used for preventing methods to traverse above the container given to
  95. * the {@link render()} method.
  96. *
  97. * @see _findRoot()
  98. *
  99. * @var Zend_Navigation_Container
  100. */
  101. protected $_root;
  102. /**
  103. * View helper entry point:
  104. * Retrieves helper and optionally sets container to operate on
  105. *
  106. * @param Zend_Navigation_Container $container [optional] container to
  107. * operate on
  108. * @return Zend_View_Helper_Navigation_Links fluent interface, returns
  109. * self
  110. */
  111. public function links(Zend_Navigation_Container $container = null)
  112. {
  113. if (null !== $container) {
  114. $this->setContainer($container);
  115. }
  116. return $this;
  117. }
  118. /**
  119. * Magic overload: Proxy calls to {@link findRelation()} or container
  120. *
  121. * Examples of finder calls:
  122. * <code>
  123. * // METHOD // SAME AS
  124. * $h->findRelNext($page); // $h->findRelation($page, 'rel', 'next')
  125. * $h->findRevSection($page); // $h->findRelation($page, 'rev', 'section');
  126. * $h->findRelFoo($page); // $h->findRelation($page, 'rel', 'foo');
  127. * </code>
  128. *
  129. * @param string $method method name
  130. * @param array $arguments method arguments
  131. * @throws Zend_Navigation_Exception if method does not exist in container
  132. */
  133. public function __call($method, array $arguments = array())
  134. {
  135. if (@preg_match('/find(Rel|Rev)(.+)/', $method, $match)) {
  136. return $this->findRelation($arguments[0],
  137. strtolower($match[1]),
  138. strtolower($match[2]));
  139. }
  140. return parent::__call($method, $arguments);
  141. }
  142. // Accessors:
  143. /**
  144. * Sets the helper's render flag
  145. *
  146. * The helper uses the bitwise '&' operator against the hex values of the
  147. * render constants. This means that the flag can is "bitwised" value of
  148. * the render constants. Examples:
  149. * <code>
  150. * // render all links except glossary
  151. * $flag = Zend_View_Helper_Navigation_Links:RENDER_ALL ^
  152. * Zend_View_Helper_Navigation_Links:RENDER_GLOSSARY;
  153. * $helper->setRenderFlag($flag);
  154. *
  155. * // render only chapters and sections
  156. * $flag = Zend_View_Helper_Navigation_Links:RENDER_CHAPTER |
  157. * Zend_View_Helper_Navigation_Links:RENDER_SECTION;
  158. * $helper->setRenderFlag($flag);
  159. *
  160. * // render only relations that are not native W3C relations
  161. * $helper->setRenderFlag(Zend_View_Helper_Navigation_Links:RENDER_CUSTOM);
  162. *
  163. * // render all relations (default)
  164. * $helper->setRenderFlag(Zend_View_Helper_Navigation_Links:RENDER_ALL);
  165. * </code>
  166. *
  167. * Note that custom relations can also be rendered directly using the
  168. * {@link renderLink()} method.
  169. *
  170. * @param int $renderFlag render flag
  171. * @return Zend_View_Helper_Navigation_Links fluent interface, returns self
  172. */
  173. public function setRenderFlag($renderFlag)
  174. {
  175. $this->_renderFlag = (int) $renderFlag;
  176. return $this;
  177. }
  178. /**
  179. * Returns the helper's render flag
  180. *
  181. * @return int render flag
  182. */
  183. public function getRenderFlag()
  184. {
  185. return $this->_renderFlag;
  186. }
  187. // Finder methods:
  188. /**
  189. * Finds all relations (forward and reverse) for the given $page
  190. *
  191. * The form of the returned array:
  192. * <code>
  193. * // $page denotes an instance of Zend_Navigation_Page
  194. * $returned = array(
  195. * 'rel' => array(
  196. * 'alternate' => array($page, $page, $page),
  197. * 'start' => array($page),
  198. * 'next' => array($page),
  199. * 'prev' => array($page),
  200. * 'canonical' => array($page)
  201. * ),
  202. * 'rev' => array(
  203. * 'section' => array($page)
  204. * )
  205. * );
  206. * </code>
  207. *
  208. * @param Zend_Navigation_Page $page page to find links for
  209. * @return array related pages
  210. */
  211. public function findAllRelations(Zend_Navigation_Page $page,
  212. $flag = null)
  213. {
  214. if (!is_int($flag)) {
  215. $flag = self::RENDER_ALL;
  216. }
  217. $result = array('rel' => array(), 'rev' => array());
  218. $native = array_values(self::$_RELATIONS);
  219. foreach (array_keys($result) as $rel) {
  220. $meth = 'getDefined' . ucfirst($rel);
  221. $types = array_merge($native, array_diff($page->$meth(), $native));
  222. foreach ($types as $type) {
  223. if (!$relFlag = array_search($type, self::$_RELATIONS)) {
  224. $relFlag = self::RENDER_CUSTOM;
  225. }
  226. if (!($flag & $relFlag)) {
  227. continue;
  228. }
  229. if ($found = $this->findRelation($page, $rel, $type)) {
  230. if (!is_array($found)) {
  231. $found = array($found);
  232. }
  233. $result[$rel][$type] = $found;
  234. }
  235. }
  236. }
  237. return $result;
  238. }
  239. /**
  240. * Finds relations of the given $rel=$type from $page
  241. *
  242. * This method will first look for relations in the page instance, then
  243. * by searching the root container if nothing was found in the page.
  244. *
  245. * @param Zend_Navigation_Page $page page to find relations for
  246. * @param string $rel relation, "rel" or "rev"
  247. * @param string $type link type, e.g. 'start', 'next'
  248. * @return Zend_Navigaiton_Page|array|null page(s), or null if not found
  249. * @throws Zend_View_Exception if $rel is not "rel" or "rev"
  250. */
  251. public function findRelation(Zend_Navigation_Page $page, $rel, $type)
  252. {
  253. if (!in_array($rel, array('rel', 'rev'))) {
  254. require_once 'Zend/View/Exception.php';
  255. $e = new Zend_View_Exception(sprintf(
  256. 'Invalid argument: $rel must be "rel" or "rev"; "%s" given',
  257. $rel));
  258. $e->setView($this->view);
  259. throw $e;
  260. }
  261. if (!$result = $this->_findFromProperty($page, $rel, $type)) {
  262. $result = $this->_findFromSearch($page, $rel, $type);
  263. }
  264. return $result;
  265. }
  266. /**
  267. * Finds relations of given $type for $page by checking if the
  268. * relation is specified as a property of $page
  269. *
  270. * @param Zend_Navigation_Page $page page to find relations for
  271. * @param string $rel relation, 'rel' or 'rev'
  272. * @param string $type link type, e.g. 'start', 'next'
  273. * @return Zend_Navigation_Page|array|null page(s), or null if not found
  274. */
  275. protected function _findFromProperty(Zend_Navigation_Page $page, $rel, $type)
  276. {
  277. $method = 'get' . ucfirst($rel);
  278. if ($result = $page->$method($type)) {
  279. if ($result = $this->_convertToPages($result)) {
  280. if (!is_array($result)) {
  281. $result = array($result);
  282. }
  283. foreach ($result as $key => $page) {
  284. if (!$this->accept($page)) {
  285. unset($result[$key]);
  286. }
  287. }
  288. return count($result) == 1 ? $result[0] : $result;
  289. }
  290. }
  291. return null;
  292. }
  293. /**
  294. * Finds relations of given $rel=$type for $page by using the helper to
  295. * search for the relation in the root container
  296. *
  297. * @param Zend_Navigation_Page $page page to find relations for
  298. * @param string $rel relation, 'rel' or 'rev'
  299. * @param string $type link type, e.g. 'start', 'next', etc
  300. * @return array|null array of pages, or null if not found
  301. */
  302. protected function _findFromSearch(Zend_Navigation_Page $page, $rel, $type)
  303. {
  304. $found = null;
  305. $method = 'search' . ucfirst($rel) . ucfirst($type);
  306. if (method_exists($this, $method)) {
  307. $found = $this->$method($page);
  308. }
  309. return $found;
  310. }
  311. // Search methods:
  312. /**
  313. * Searches the root container for the forward 'start' relation of the given
  314. * $page
  315. *
  316. * From {@link http://www.w3.org/TR/html4/types.html#type-links}:
  317. * Refers to the first document in a collection of documents. This link type
  318. * tells search engines which document is considered by the author to be the
  319. * starting point of the collection.
  320. *
  321. * @param Zend_Navigation_Page $page page to find relation for
  322. * @return Zend_Navigation_Page|null page or null
  323. */
  324. public function searchRelStart(Zend_Navigation_Page $page)
  325. {
  326. $found = $this->_findRoot($page);
  327. if (!$found instanceof Zend_Navigation_Page) {
  328. $found->rewind();
  329. $found = $found->current();
  330. }
  331. if ($found === $page || !$this->accept($found)) {
  332. $found = null;
  333. }
  334. return $found;
  335. }
  336. /**
  337. * Searches the root container for the forward 'next' relation of the given
  338. * $page
  339. *
  340. * From {@link http://www.w3.org/TR/html4/types.html#type-links}:
  341. * Refers to the next document in a linear sequence of documents. User
  342. * agents may choose to preload the "next" document, to reduce the perceived
  343. * load time.
  344. *
  345. * @param Zend_Navigation_Page $page page to find relation for
  346. * @return Zend_Navigation_Page|null page(s) or null
  347. */
  348. public function searchRelNext(Zend_Navigation_Page $page)
  349. {
  350. $found = null;
  351. $break = false;
  352. $iterator = new RecursiveIteratorIterator($this->_findRoot($page),
  353. RecursiveIteratorIterator::SELF_FIRST);
  354. foreach ($iterator as $intermediate) {
  355. if ($intermediate === $page) {
  356. // current page; break at next accepted page
  357. $break = true;
  358. continue;
  359. }
  360. if ($break && $this->accept($intermediate)) {
  361. $found = $intermediate;
  362. break;
  363. }
  364. }
  365. return $found;
  366. }
  367. /**
  368. * Searches the root container for the forward 'prev' relation of the given
  369. * $page
  370. *
  371. * From {@link http://www.w3.org/TR/html4/types.html#type-links}:
  372. * Refers to the previous document in an ordered series of documents. Some
  373. * user agents also support the synonym "Previous".
  374. *
  375. * @param Zend_Navigation_Page $page page to find relation for
  376. * @return Zend_Navigation_Page|null page or null
  377. */
  378. public function searchRelPrev(Zend_Navigation_Page $page)
  379. {
  380. $found = null;
  381. $prev = null;
  382. $iterator = new RecursiveIteratorIterator(
  383. $this->_findRoot($page),
  384. RecursiveIteratorIterator::SELF_FIRST);
  385. foreach ($iterator as $intermediate) {
  386. if (!$this->accept($intermediate)) {
  387. continue;
  388. }
  389. if ($intermediate === $page) {
  390. $found = $prev;
  391. break;
  392. }
  393. $prev = $intermediate;
  394. }
  395. return $found;
  396. }
  397. /**
  398. * Searches the root container for forward 'chapter' relations of the given
  399. * $page
  400. *
  401. * From {@link http://www.w3.org/TR/html4/types.html#type-links}:
  402. * Refers to a document serving as a chapter in a collection of documents.
  403. *
  404. * @param Zend_Navigation_Page $page page to find relation for
  405. * @return Zend_Navigation_Page|array|null page(s) or null
  406. */
  407. public function searchRelChapter(Zend_Navigation_Page $page)
  408. {
  409. $found = array();
  410. // find first level of pages
  411. $root = $this->_findRoot($page);
  412. // find start page(s)
  413. $start = $this->findRelation($page, 'rel', 'start');
  414. if (!is_array($start)) {
  415. $start = array($start);
  416. }
  417. foreach ($root as $chapter) {
  418. // exclude self and start page from chapters
  419. if ($chapter !== $page &&
  420. !in_array($chapter, $start) &&
  421. $this->accept($chapter)) {
  422. $found[] = $chapter;
  423. }
  424. }
  425. switch (count($found)) {
  426. case 0:
  427. return null;
  428. case 1:
  429. return $found[0];
  430. default:
  431. return $found;
  432. }
  433. }
  434. /**
  435. * Searches the root container for forward 'section' relations of the given
  436. * $page
  437. *
  438. * From {@link http://www.w3.org/TR/html4/types.html#type-links}:
  439. * Refers to a document serving as a section in a collection of documents.
  440. *
  441. * @param Zend_Navigation_Page $page page to find relation for
  442. * @return Zend_Navigation_Page|array|null page(s) or null
  443. */
  444. public function searchRelSection(Zend_Navigation_Page $page)
  445. {
  446. $found = array();
  447. // check if given page has pages and is a chapter page
  448. if ($page->hasPages() && $this->_findRoot($page)->hasPage($page)) {
  449. foreach ($page as $section) {
  450. if ($this->accept($section)) {
  451. $found[] = $section;
  452. }
  453. }
  454. }
  455. switch (count($found)) {
  456. case 0:
  457. return null;
  458. case 1:
  459. return $found[0];
  460. default:
  461. return $found;
  462. }
  463. }
  464. /**
  465. * Searches the root container for forward 'subsection' relations of the
  466. * given $page
  467. *
  468. * From {@link http://www.w3.org/TR/html4/types.html#type-links}:
  469. * Refers to a document serving as a subsection in a collection of
  470. * documents.
  471. *
  472. * @param Zend_Navigation_Page $page page to find relation for
  473. * @return Zend_Navigation_Page|array|null page(s) or null
  474. */
  475. public function searchRelSubsection(Zend_Navigation_Page $page)
  476. {
  477. $found = array();
  478. if ($page->hasPages()) {
  479. // given page has child pages, loop chapters
  480. foreach ($this->_findRoot($page) as $chapter) {
  481. // is page a section?
  482. if ($chapter->hasPage($page)) {
  483. foreach ($page as $subsection) {
  484. if ($this->accept($subsection)) {
  485. $found[] = $subsection;
  486. }
  487. }
  488. }
  489. }
  490. }
  491. switch (count($found)) {
  492. case 0:
  493. return null;
  494. case 1:
  495. return $found[0];
  496. default:
  497. return $found;
  498. }
  499. }
  500. /**
  501. * Searches the root container for the reverse 'section' relation of the
  502. * given $page
  503. *
  504. * From {@link http://www.w3.org/TR/html4/types.html#type-links}:
  505. * Refers to a document serving as a section in a collection of documents.
  506. *
  507. * @param Zend_Navigation_Page $page page to find relation for
  508. * @return Zend_Navigation_Page|null page(s) or null
  509. */
  510. public function searchRevSection(Zend_Navigation_Page $page)
  511. {
  512. $found = null;
  513. if ($parent = $page->getParent()) {
  514. if ($parent instanceof Zend_Navigation_Page &&
  515. $this->_findRoot($page)->hasPage($parent)) {
  516. $found = $parent;
  517. }
  518. }
  519. return $found;
  520. }
  521. /**
  522. * Searches the root container for the reverse 'section' relation of the
  523. * given $page
  524. *
  525. * From {@link http://www.w3.org/TR/html4/types.html#type-links}:
  526. * Refers to a document serving as a subsection in a collection of
  527. * documents.
  528. *
  529. * @param Zend_Navigation_Page $page page to find relation for
  530. * @return Zend_Navigation_Page|null page(s) or null
  531. */
  532. public function searchRevSubsection(Zend_Navigation_Page $page)
  533. {
  534. $found = null;
  535. if ($parent = $page->getParent()) {
  536. if ($parent instanceof Zend_Navigation_Page) {
  537. $root = $this->_findRoot($page);
  538. foreach ($root as $chapter) {
  539. if ($chapter->hasPage($parent)) {
  540. $found = $parent;
  541. break;
  542. }
  543. }
  544. }
  545. }
  546. return $found;
  547. }
  548. // Util methods:
  549. /**
  550. * Returns the root container of the given page
  551. *
  552. * When rendering a container, the render method still store the given
  553. * container as the root container, and unset it when done rendering. This
  554. * makes sure finder methods will not traverse above the container given
  555. * to the render method.
  556. *
  557. * @param Zend_Navigaiton_Page $page page to find root for
  558. * @return Zend_Navigation_Container the root container of the given page
  559. */
  560. protected function _findRoot(Zend_Navigation_Page $page)
  561. {
  562. if ($this->_root) {
  563. return $this->_root;
  564. }
  565. $root = $page;
  566. while ($parent = $page->getParent()) {
  567. $root = $parent;
  568. if ($parent instanceof Zend_Navigation_Page) {
  569. $page = $parent;
  570. } else {
  571. break;
  572. }
  573. }
  574. return $root;
  575. }
  576. /**
  577. * Converts a $mixed value to an array of pages
  578. *
  579. * @param mixed $mixed mixed value to get page(s) from
  580. * @param bool $recursive whether $value should be looped
  581. * if it is an array or a config
  582. * @return Zend_Navigation_Page|array|null empty if unable to convert
  583. */
  584. protected function _convertToPages($mixed, $recursive = true)
  585. {
  586. if (is_object($mixed)) {
  587. if ($mixed instanceof Zend_Navigation_Page) {
  588. // value is a page instance; return directly
  589. return $mixed;
  590. } elseif ($mixed instanceof Zend_Navigation_Container) {
  591. // value is a container; return pages in it
  592. $pages = array();
  593. foreach ($mixed as $page) {
  594. $pages[] = $page;
  595. }
  596. return $pages;
  597. } elseif ($mixed instanceof Zend_Config) {
  598. // convert config object to array and extract
  599. return $this->_convertToPages($mixed->toArray(), $recursive);
  600. }
  601. } elseif (is_string($mixed)) {
  602. // value is a string; make an URI page
  603. return Zend_Navigation_Page::factory(array(
  604. 'type' => 'uri',
  605. 'uri' => $mixed
  606. ));
  607. } elseif (is_array($mixed) && !empty($mixed)) {
  608. if ($recursive && is_numeric(key($mixed))) {
  609. // first key is numeric; assume several pages
  610. $pages = array();
  611. foreach ($mixed as $value) {
  612. if ($value = $this->_convertToPages($value, false)) {
  613. $pages[] = $value;
  614. }
  615. }
  616. return $pages;
  617. } else {
  618. // pass array to factory directly
  619. try {
  620. $page = Zend_Navigation_Page::factory($mixed);
  621. return $page;
  622. } catch (Exception $e) {
  623. }
  624. }
  625. }
  626. // nothing found
  627. return null;
  628. }
  629. // Render methods:
  630. /**
  631. * Renders the given $page as a link element, with $attrib = $relation
  632. *
  633. * @param Zend_Navigation_Page $page the page to render the link for
  634. * @param string $attrib the attribute to use for $type,
  635. * either 'rel' or 'rev'
  636. * @param string $relation relation type, muse be one of;
  637. * alternate, appendix, bookmark,
  638. * chapter, contents, copyright,
  639. * glossary, help, home, index, next,
  640. * prev, section, start, stylesheet,
  641. * subsection
  642. * @return string rendered link element
  643. * @throws Zend_View_Exception if $attrib is invalid
  644. */
  645. public function renderLink(Zend_Navigation_Page $page, $attrib, $relation)
  646. {
  647. if (!in_array($attrib, array('rel', 'rev'))) {
  648. require_once 'Zend/View/Exception.php';
  649. $e = new Zend_View_Exception(sprintf(
  650. 'Invalid relation attribute "%s", must be "rel" or "rev"',
  651. $attrib));
  652. $e->setView($this->view);
  653. throw $e;
  654. }
  655. if (!$href = $page->getHref()) {
  656. return '';
  657. }
  658. // TODO: add more attribs
  659. // http://www.w3.org/TR/html401/struct/links.html#h-12.2
  660. $attribs = array(
  661. $attrib => $relation,
  662. 'href' => $href,
  663. 'title' => $page->getLabel()
  664. );
  665. return '<link' .
  666. $this->_htmlAttribs($attribs) .
  667. $this->getClosingBracket();
  668. }
  669. // Zend_View_Helper_Navigation_Helper:
  670. /**
  671. * Renders helper
  672. *
  673. * Implements {@link Zend_View_Helper_Navigation_Helper::render()}.
  674. *
  675. * @param Zend_Navigation_Container $container [optional] container to
  676. * render. Default is to
  677. * render the container
  678. * registered in the helper.
  679. * @return string helper output
  680. */
  681. public function render(Zend_Navigation_Container $container = null)
  682. {
  683. if (null === $container) {
  684. $container = $this->getContainer();
  685. }
  686. if ($active = $this->findActive($container)) {
  687. $active = $active['page'];
  688. } else {
  689. // no active page
  690. return '';
  691. }
  692. $output = '';
  693. $indent = $this->getIndent();
  694. $this->_root = $container;
  695. $result = $this->findAllRelations($active, $this->getRenderFlag());
  696. foreach ($result as $attrib => $types) {
  697. foreach ($types as $relation => $pages) {
  698. foreach ($pages as $page) {
  699. if ($r = $this->renderLink($page, $attrib, $relation)) {
  700. $output .= $indent . $r . self::EOL;
  701. }
  702. }
  703. }
  704. }
  705. $this->_root = null;
  706. // return output (trim last newline by spec)
  707. return strlen($output) ? rtrim($output, self::EOL) : '';
  708. }
  709. }