2
0

Links.php 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779
  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-2009 Zend Technologies USA Inc. (http://www.zend.com)
  19. * @license http://framework.zend.com/license/new-bsd New BSD License
  20. * @version $Id$
  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-2009 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. throw new Zend_View_Exception(sprintf(
  256. 'Invalid argument: $rel must be "rel" or "rev"; "%s" given',
  257. $rel));
  258. }
  259. if (!$result = $this->_findFromProperty($page, $rel, $type)) {
  260. $result = $this->_findFromSearch($page, $rel, $type);
  261. }
  262. return $result;
  263. }
  264. /**
  265. * Finds relations of given $type for $page by checking if the
  266. * relation is specified as a property of $page
  267. *
  268. * @param Zend_Navigation_Page $page page to find relations for
  269. * @param string $rel relation, 'rel' or 'rev'
  270. * @param string $type link type, e.g. 'start', 'next'
  271. * @return Zend_Navigation_Page|array|null page(s), or null if not found
  272. */
  273. protected function _findFromProperty(Zend_Navigation_Page $page, $rel, $type)
  274. {
  275. $method = 'get' . ucfirst($rel);
  276. if ($result = $page->$method($type)) {
  277. if ($result = $this->_convertToPages($result)) {
  278. if (!is_array($result)) {
  279. $result = array($result);
  280. }
  281. foreach ($result as $key => $page) {
  282. if (!$this->accept($page)) {
  283. unset($result[$key]);
  284. }
  285. }
  286. return count($result) == 1 ? $result[0] : $result;
  287. }
  288. }
  289. return null;
  290. }
  291. /**
  292. * Finds relations of given $rel=$type for $page by using the helper to
  293. * search for the relation in the root container
  294. *
  295. * @param Zend_Navigation_Page $page page to find relations for
  296. * @param string $rel relation, 'rel' or 'rev'
  297. * @param string $type link type, e.g. 'start', 'next', etc
  298. * @return array|null array of pages, or null if not found
  299. */
  300. protected function _findFromSearch(Zend_Navigation_Page $page, $rel, $type)
  301. {
  302. $found = null;
  303. $method = 'search' . ucfirst($rel) . ucfirst($type);
  304. if (method_exists($this, $method)) {
  305. $found = $this->$method($page);
  306. }
  307. return $found;
  308. }
  309. // Search methods:
  310. /**
  311. * Searches the root container for the forward 'start' relation of the given
  312. * $page
  313. *
  314. * From {@link http://www.w3.org/TR/html4/types.html#type-links}:
  315. * Refers to the first document in a collection of documents. This link type
  316. * tells search engines which document is considered by the author to be the
  317. * starting point of the collection.
  318. *
  319. * @param Zend_Navigation_Page $page page to find relation for
  320. * @return Zend_Navigation_Page|null page or null
  321. */
  322. public function searchRelStart(Zend_Navigation_Page $page)
  323. {
  324. $found = $this->_findRoot($page);
  325. if (!$found instanceof Zend_Navigation_Page) {
  326. $found->rewind();
  327. $found = $found->current();
  328. }
  329. if ($found === $page || !$this->accept($found)) {
  330. $found = null;
  331. }
  332. return $found;
  333. }
  334. /**
  335. * Searches the root container for the forward 'next' relation of the given
  336. * $page
  337. *
  338. * From {@link http://www.w3.org/TR/html4/types.html#type-links}:
  339. * Refers to the next document in a linear sequence of documents. User
  340. * agents may choose to preload the "next" document, to reduce the perceived
  341. * load time.
  342. *
  343. * @param Zend_Navigation_Page $page page to find relation for
  344. * @return Zend_Navigation_Page|null page(s) or null
  345. */
  346. public function searchRelNext(Zend_Navigation_Page $page)
  347. {
  348. $found = null;
  349. $break = false;
  350. $iterator = new RecursiveIteratorIterator($this->_findRoot($page),
  351. RecursiveIteratorIterator::SELF_FIRST);
  352. foreach ($iterator as $intermediate) {
  353. if ($intermediate === $page) {
  354. // current page; break at next accepted page
  355. $break = true;
  356. continue;
  357. }
  358. if ($break && $this->accept($intermediate)) {
  359. $found = $intermediate;
  360. break;
  361. }
  362. }
  363. return $found;
  364. }
  365. /**
  366. * Searches the root container for the forward 'prev' relation of the given
  367. * $page
  368. *
  369. * From {@link http://www.w3.org/TR/html4/types.html#type-links}:
  370. * Refers to the previous document in an ordered series of documents. Some
  371. * user agents also support the synonym "Previous".
  372. *
  373. * @param Zend_Navigation_Page $page page to find relation for
  374. * @return Zend_Navigation_Page|null page or null
  375. */
  376. public function searchRelPrev(Zend_Navigation_Page $page)
  377. {
  378. $found = null;
  379. $prev = null;
  380. $iterator = new RecursiveIteratorIterator(
  381. $this->_findRoot($page),
  382. RecursiveIteratorIterator::SELF_FIRST);
  383. foreach ($iterator as $intermediate) {
  384. if (!$this->accept($intermediate)) {
  385. continue;
  386. }
  387. if ($intermediate === $page) {
  388. $found = $prev;
  389. break;
  390. }
  391. $prev = $intermediate;
  392. }
  393. return $found;
  394. }
  395. /**
  396. * Searches the root container for forward 'chapter' relations of the given
  397. * $page
  398. *
  399. * From {@link http://www.w3.org/TR/html4/types.html#type-links}:
  400. * Refers to a document serving as a chapter in a collection of documents.
  401. *
  402. * @param Zend_Navigation_Page $page page to find relation for
  403. * @return Zend_Navigation_Page|array|null page(s) or null
  404. */
  405. public function searchRelChapter(Zend_Navigation_Page $page)
  406. {
  407. $found = array();
  408. // find first level of pages
  409. $root = $this->_findRoot($page);
  410. // find start page(s)
  411. $start = $this->findRelation($page, 'rel', 'start');
  412. if (!is_array($start)) {
  413. $start = array($start);
  414. }
  415. foreach ($root as $chapter) {
  416. // exclude self and start page from chapters
  417. if ($chapter !== $page &&
  418. !in_array($chapter, $start) &&
  419. $this->accept($chapter)) {
  420. $found[] = $chapter;
  421. }
  422. }
  423. switch (count($found)) {
  424. case 0:
  425. return null;
  426. case 1:
  427. return $found[0];
  428. default:
  429. return $found;
  430. }
  431. }
  432. /**
  433. * Searches the root container for forward 'section' relations of the given
  434. * $page
  435. *
  436. * From {@link http://www.w3.org/TR/html4/types.html#type-links}:
  437. * Refers to a document serving as a section in a collection of documents.
  438. *
  439. * @param Zend_Navigation_Page $page page to find relation for
  440. * @return Zend_Navigation_Page|array|null page(s) or null
  441. */
  442. public function searchRelSection(Zend_Navigation_Page $page)
  443. {
  444. $found = array();
  445. // check if given page has pages and is a chapter page
  446. if ($page->hasPages() && $this->_findRoot($page)->hasPage($page)) {
  447. foreach ($page as $section) {
  448. if ($this->accept($section)) {
  449. $found[] = $section;
  450. }
  451. }
  452. }
  453. switch (count($found)) {
  454. case 0:
  455. return null;
  456. case 1:
  457. return $found[0];
  458. default:
  459. return $found;
  460. }
  461. }
  462. /**
  463. * Searches the root container for forward 'subsection' relations of the
  464. * given $page
  465. *
  466. * From {@link http://www.w3.org/TR/html4/types.html#type-links}:
  467. * Refers to a document serving as a subsection in a collection of
  468. * documents.
  469. *
  470. * @param Zend_Navigation_Page $page page to find relation for
  471. * @return Zend_Navigation_Page|array|null page(s) or null
  472. */
  473. public function searchRelSubsection(Zend_Navigation_Page $page)
  474. {
  475. $found = array();
  476. if ($page->hasPages()) {
  477. // given page has child pages, loop chapters
  478. foreach ($this->_findRoot($page) as $chapter) {
  479. // is page a section?
  480. if ($chapter->hasPage($page)) {
  481. foreach ($page as $subsection) {
  482. if ($this->accept($subsection)) {
  483. $found[] = $subsection;
  484. }
  485. }
  486. }
  487. }
  488. }
  489. switch (count($found)) {
  490. case 0:
  491. return null;
  492. case 1:
  493. return $found[0];
  494. default:
  495. return $found;
  496. }
  497. }
  498. /**
  499. * Searches the root container for the reverse 'section' relation of the
  500. * given $page
  501. *
  502. * From {@link http://www.w3.org/TR/html4/types.html#type-links}:
  503. * Refers to a document serving as a section in a collection of documents.
  504. *
  505. * @param Zend_Navigation_Page $page page to find relation for
  506. * @return Zend_Navigation_Page|null page(s) or null
  507. */
  508. public function searchRevSection(Zend_Navigation_Page $page)
  509. {
  510. $found = null;
  511. if ($parent = $page->getParent()) {
  512. if ($parent instanceof Zend_Navigation_Page &&
  513. $this->_findRoot($page)->hasPage($parent)) {
  514. $found = $parent;
  515. }
  516. }
  517. return $found;
  518. }
  519. /**
  520. * Searches the root container for the reverse 'section' relation of the
  521. * given $page
  522. *
  523. * From {@link http://www.w3.org/TR/html4/types.html#type-links}:
  524. * Refers to a document serving as a subsection in a collection of
  525. * documents.
  526. *
  527. * @param Zend_Navigation_Page $page page to find relation for
  528. * @return Zend_Navigation_Page|null page(s) or null
  529. */
  530. public function searchRevSubsection(Zend_Navigation_Page $page)
  531. {
  532. $found = null;
  533. if ($parent = $page->getParent()) {
  534. if ($parent instanceof Zend_Navigation_Page) {
  535. $root = $this->_findRoot($page);
  536. foreach ($root as $chapter) {
  537. if ($chapter->hasPage($parent)) {
  538. $found = $parent;
  539. break;
  540. }
  541. }
  542. }
  543. }
  544. return $found;
  545. }
  546. // Util methods:
  547. /**
  548. * Returns the root container of the given page
  549. *
  550. * When rendering a container, the render method still store the given
  551. * container as the root container, and unset it when done rendering. This
  552. * makes sure finder methods will not traverse above the container given
  553. * to the render method.
  554. *
  555. * @param Zend_Navigaiton_Page $page page to find root for
  556. * @return Zend_Navigation_Container the root container of the given page
  557. */
  558. protected function _findRoot(Zend_Navigation_Page $page)
  559. {
  560. if ($this->_root) {
  561. return $this->_root;
  562. }
  563. $root = $page;
  564. while ($parent = $page->getParent()) {
  565. $root = $parent;
  566. if ($parent instanceof Zend_Navigation_Page) {
  567. $page = $parent;
  568. } else {
  569. break;
  570. }
  571. }
  572. return $root;
  573. }
  574. /**
  575. * Converts a $mixed value to an array of pages
  576. *
  577. * @param mixed $mixed mixed value to get page(s) from
  578. * @param bool $recursive whether $value should be looped
  579. * if it is an array or a config
  580. * @return Zend_Navigation_Page|array|null empty if unable to convert
  581. */
  582. protected function _convertToPages($mixed, $recursive = true)
  583. {
  584. if (is_object($mixed)) {
  585. if ($mixed instanceof Zend_Navigation_Page) {
  586. // value is a page instance; return directly
  587. return $mixed;
  588. } elseif ($mixed instanceof Zend_Navigation_Container) {
  589. // value is a container; return pages in it
  590. $pages = array();
  591. foreach ($mixed as $page) {
  592. $pages[] = $page;
  593. }
  594. return $pages;
  595. } elseif ($mixed instanceof Zend_Config) {
  596. // convert config object to array and extract
  597. return $this->_convertToPages($mixed->toArray(), $recursive);
  598. }
  599. } elseif (is_string($mixed)) {
  600. // value is a string; make an URI page
  601. return Zend_Navigation_Page::factory(array(
  602. 'type' => 'uri',
  603. 'uri' => $mixed
  604. ));
  605. } elseif (is_array($mixed) && !empty($mixed)) {
  606. if ($recursive && is_numeric(key($mixed))) {
  607. // first key is numeric; assume several pages
  608. $pages = array();
  609. foreach ($mixed as $value) {
  610. if ($value = $this->_convertToPages($value, false)) {
  611. $pages[] = $value;
  612. }
  613. }
  614. return $pages;
  615. } else {
  616. // pass array to factory directly
  617. try {
  618. $page = Zend_Navigation_Page::factory($mixed);
  619. return $page;
  620. } catch (Exception $e) {
  621. }
  622. }
  623. }
  624. // nothing found
  625. return null;
  626. }
  627. // Render methods:
  628. /**
  629. * Renders the given $page as a link element, with $attrib = $relation
  630. *
  631. * @param Zend_Navigation_Page $page the page to render the link for
  632. * @param string $attrib the attribute to use for $type,
  633. * either 'rel' or 'rev'
  634. * @param string $relation relation type, muse be one of;
  635. * alternate, appendix, bookmark,
  636. * chapter, contents, copyright,
  637. * glossary, help, home, index, next,
  638. * prev, section, start, stylesheet,
  639. * subsection
  640. * @return string rendered link element
  641. * @throws Zend_View_Exception if $attrib is invalid
  642. */
  643. public function renderLink(Zend_Navigation_Page $page, $attrib, $relation)
  644. {
  645. if (!in_array($attrib, array('rel', 'rev'))) {
  646. require_once 'Zend/View/Exception.php';
  647. throw new Zend_View_Exception(sprintf(
  648. 'Invalid relation attribute "%s", must be "rel" or "rev"',
  649. $attrib));
  650. }
  651. if (!$href = $page->getHref()) {
  652. return '';
  653. }
  654. // TODO: add more attribs
  655. // http://www.w3.org/TR/html401/struct/links.html#h-12.2
  656. $attribs = array(
  657. $attrib => $relation,
  658. 'href' => $href,
  659. 'title' => $page->getLabel()
  660. );
  661. return '<link' .
  662. $this->_htmlAttribs($attribs) .
  663. $this->getClosingBracket();
  664. }
  665. // Zend_View_Helper_Navigation_Helper:
  666. /**
  667. * Renders helper
  668. *
  669. * Implements {@link Zend_View_Helper_Navigation_Helper::render()}.
  670. *
  671. * @param Zend_Navigation_Container $container [optional] container to
  672. * render. Default is to
  673. * render the container
  674. * registered in the helper.
  675. * @return string helper output
  676. */
  677. public function render(Zend_Navigation_Container $container = null)
  678. {
  679. if (null === $container) {
  680. $container = $this->getContainer();
  681. }
  682. if ($active = $this->findActive($container)) {
  683. $active = $active['page'];
  684. } else {
  685. // no active page
  686. return '';
  687. }
  688. $output = '';
  689. $indent = $this->getIndent();
  690. $this->_root = $container;
  691. $result = $this->findAllRelations($active, $this->getRenderFlag());
  692. foreach ($result as $attrib => $types) {
  693. foreach ($types as $relation => $pages) {
  694. foreach ($pages as $page) {
  695. if ($r = $this->renderLink($page, $attrib, $relation)) {
  696. $output .= $indent . $r . self::EOL;
  697. }
  698. }
  699. }
  700. }
  701. $this->_root = null;
  702. // return output (trim last newline by spec)
  703. return strlen($output) ? rtrim($output, self::EOL) : '';
  704. }
  705. }