Links.php 25 KB

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