|
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-2010 Zend Technologies USA Inc. (http://www.zend.com) |
|
19 * @license http://framework.zend.com/license/new-bsd New BSD License |
|
20 * @version $Id: HelperAbstract.php 20096 2010-01-06 02:05:09Z bkarwin $ |
|
21 */ |
|
22 |
|
23 /** |
|
24 * @see Zend_View_Helper_Navigation_Helper |
|
25 */ |
|
26 require_once 'Zend/View/Helper/Navigation/Helper.php'; |
|
27 |
|
28 /** |
|
29 * @see Zend_View_Helper_HtmlElement |
|
30 */ |
|
31 require_once 'Zend/View/Helper/HtmlElement.php'; |
|
32 |
|
33 /** |
|
34 * Base class for navigational helpers |
|
35 * |
|
36 * @category Zend |
|
37 * @package Zend_View |
|
38 * @subpackage Helper |
|
39 * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) |
|
40 * @license http://framework.zend.com/license/new-bsd New BSD License |
|
41 */ |
|
42 abstract class Zend_View_Helper_Navigation_HelperAbstract |
|
43 extends Zend_View_Helper_HtmlElement |
|
44 implements Zend_View_Helper_Navigation_Helper |
|
45 { |
|
46 /** |
|
47 * Container to operate on by default |
|
48 * |
|
49 * @var Zend_Navigation_Container |
|
50 */ |
|
51 protected $_container; |
|
52 |
|
53 /** |
|
54 * The minimum depth a page must have to be included when rendering |
|
55 * |
|
56 * @var int |
|
57 */ |
|
58 protected $_minDepth; |
|
59 |
|
60 /** |
|
61 * The maximum depth a page can have to be included when rendering |
|
62 * |
|
63 * @var int |
|
64 */ |
|
65 protected $_maxDepth; |
|
66 |
|
67 /** |
|
68 * Indentation string |
|
69 * |
|
70 * @var string |
|
71 */ |
|
72 protected $_indent = ''; |
|
73 |
|
74 /** |
|
75 * Translator |
|
76 * |
|
77 * @var Zend_Translate_Adapter |
|
78 */ |
|
79 protected $_translator; |
|
80 |
|
81 /** |
|
82 * ACL to use when iterating pages |
|
83 * |
|
84 * @var Zend_Acl |
|
85 */ |
|
86 protected $_acl; |
|
87 |
|
88 /** |
|
89 * Wheter invisible items should be rendered by this helper |
|
90 * |
|
91 * @var bool |
|
92 */ |
|
93 protected $_renderInvisible = false; |
|
94 |
|
95 /** |
|
96 * ACL role to use when iterating pages |
|
97 * |
|
98 * @var string|Zend_Acl_Role_Interface |
|
99 */ |
|
100 protected $_role; |
|
101 |
|
102 /** |
|
103 * Whether translator should be used for page labels and titles |
|
104 * |
|
105 * @var bool |
|
106 */ |
|
107 protected $_useTranslator = true; |
|
108 |
|
109 /** |
|
110 * Whether ACL should be used for filtering out pages |
|
111 * |
|
112 * @var bool |
|
113 */ |
|
114 protected $_useAcl = true; |
|
115 |
|
116 /** |
|
117 * Default ACL to use when iterating pages if not explicitly set in the |
|
118 * instance by calling {@link setAcl()} |
|
119 * |
|
120 * @var Zend_Acl |
|
121 */ |
|
122 protected static $_defaultAcl; |
|
123 |
|
124 /** |
|
125 * Default ACL role to use when iterating pages if not explicitly set in the |
|
126 * instance by calling {@link setRole()} |
|
127 * |
|
128 * @var string|Zend_Acl_Role_Interface |
|
129 */ |
|
130 protected static $_defaultRole; |
|
131 |
|
132 // Accessors: |
|
133 |
|
134 /** |
|
135 * Sets navigation container the helper operates on by default |
|
136 * |
|
137 * Implements {@link Zend_View_Helper_Navigation_Interface::setContainer()}. |
|
138 * |
|
139 * @param Zend_Navigation_Container $container [optional] container |
|
140 * to operate on. |
|
141 * Default is null, |
|
142 * meaning container |
|
143 * will be reset. |
|
144 * @return Zend_View_Helper_Navigation_HelperAbstract fluent interface, |
|
145 * returns self |
|
146 */ |
|
147 public function setContainer(Zend_Navigation_Container $container = null) |
|
148 { |
|
149 $this->_container = $container; |
|
150 return $this; |
|
151 } |
|
152 |
|
153 /** |
|
154 * Returns the navigation container helper operates on by default |
|
155 * |
|
156 * Implements {@link Zend_View_Helper_Navigation_Interface::getContainer()}. |
|
157 * |
|
158 * If a helper is not explicitly set in this helper instance by calling |
|
159 * {@link setContainer()} or by passing it through the helper entry point, |
|
160 * this method will look in {@link Zend_Registry} for a container by using |
|
161 * the key 'Zend_Navigation'. |
|
162 * |
|
163 * If no container is set, and nothing is found in Zend_Registry, a new |
|
164 * container will be instantiated and stored in the helper. |
|
165 * |
|
166 * @return Zend_Navigation_Container navigation container |
|
167 */ |
|
168 public function getContainer() |
|
169 { |
|
170 if (null === $this->_container) { |
|
171 // try to fetch from registry first |
|
172 require_once 'Zend/Registry.php'; |
|
173 if (Zend_Registry::isRegistered('Zend_Navigation')) { |
|
174 $nav = Zend_Registry::get('Zend_Navigation'); |
|
175 if ($nav instanceof Zend_Navigation_Container) { |
|
176 return $this->_container = $nav; |
|
177 } |
|
178 } |
|
179 |
|
180 // nothing found in registry, create new container |
|
181 require_once 'Zend/Navigation.php'; |
|
182 $this->_container = new Zend_Navigation(); |
|
183 } |
|
184 |
|
185 return $this->_container; |
|
186 } |
|
187 |
|
188 /** |
|
189 * Sets the minimum depth a page must have to be included when rendering |
|
190 * |
|
191 * @param int $minDepth [optional] minimum |
|
192 * depth. Default is |
|
193 * null, which sets |
|
194 * no minimum depth. |
|
195 * @return Zend_View_Helper_Navigation_HelperAbstract fluent interface, |
|
196 * returns self |
|
197 */ |
|
198 public function setMinDepth($minDepth = null) |
|
199 { |
|
200 if (null === $minDepth || is_int($minDepth)) { |
|
201 $this->_minDepth = $minDepth; |
|
202 } else { |
|
203 $this->_minDepth = (int) $minDepth; |
|
204 } |
|
205 return $this; |
|
206 } |
|
207 |
|
208 /** |
|
209 * Returns minimum depth a page must have to be included when rendering |
|
210 * |
|
211 * @return int|null minimum depth or null |
|
212 */ |
|
213 public function getMinDepth() |
|
214 { |
|
215 if (!is_int($this->_minDepth) || $this->_minDepth < 0) { |
|
216 return 0; |
|
217 } |
|
218 return $this->_minDepth; |
|
219 } |
|
220 |
|
221 /** |
|
222 * Sets the maximum depth a page can have to be included when rendering |
|
223 * |
|
224 * @param int $maxDepth [optional] maximum |
|
225 * depth. Default is |
|
226 * null, which sets no |
|
227 * maximum depth. |
|
228 * @return Zend_View_Helper_Navigation_HelperAbstract fluent interface, |
|
229 * returns self |
|
230 */ |
|
231 public function setMaxDepth($maxDepth = null) |
|
232 { |
|
233 if (null === $maxDepth || is_int($maxDepth)) { |
|
234 $this->_maxDepth = $maxDepth; |
|
235 } else { |
|
236 $this->_maxDepth = (int) $maxDepth; |
|
237 } |
|
238 return $this; |
|
239 } |
|
240 |
|
241 /** |
|
242 * Returns maximum depth a page can have to be included when rendering |
|
243 * |
|
244 * @return int|null maximum depth or null |
|
245 */ |
|
246 public function getMaxDepth() |
|
247 { |
|
248 return $this->_maxDepth; |
|
249 } |
|
250 |
|
251 /** |
|
252 * Set the indentation string for using in {@link render()}, optionally a |
|
253 * number of spaces to indent with |
|
254 * |
|
255 * @param string|int $indent indentation string or |
|
256 * number of spaces |
|
257 * @return Zend_View_Helper_Navigation_HelperAbstract fluent interface, |
|
258 * returns self |
|
259 */ |
|
260 public function setIndent($indent) |
|
261 { |
|
262 $this->_indent = $this->_getWhitespace($indent); |
|
263 return $this; |
|
264 } |
|
265 |
|
266 /** |
|
267 * Returns indentation |
|
268 * |
|
269 * @return string |
|
270 */ |
|
271 public function getIndent() |
|
272 { |
|
273 return $this->_indent; |
|
274 } |
|
275 |
|
276 /** |
|
277 * Sets translator to use in helper |
|
278 * |
|
279 * Implements {@link Zend_View_Helper_Navigation_Helper::setTranslator()}. |
|
280 * |
|
281 * @param mixed $translator [optional] translator. |
|
282 * Expects an object of |
|
283 * type |
|
284 * {@link Zend_Translate_Adapter} |
|
285 * or {@link Zend_Translate}, |
|
286 * or null. Default is |
|
287 * null, which sets no |
|
288 * translator. |
|
289 * @return Zend_View_Helper_Navigation_HelperAbstract fluent interface, |
|
290 * returns self |
|
291 */ |
|
292 public function setTranslator($translator = null) |
|
293 { |
|
294 if (null == $translator || |
|
295 $translator instanceof Zend_Translate_Adapter) { |
|
296 $this->_translator = $translator; |
|
297 } elseif ($translator instanceof Zend_Translate) { |
|
298 $this->_translator = $translator->getAdapter(); |
|
299 } |
|
300 |
|
301 return $this; |
|
302 } |
|
303 |
|
304 /** |
|
305 * Returns translator used in helper |
|
306 * |
|
307 * Implements {@link Zend_View_Helper_Navigation_Helper::getTranslator()}. |
|
308 * |
|
309 * @return Zend_Translate_Adapter|null translator or null |
|
310 */ |
|
311 public function getTranslator() |
|
312 { |
|
313 if (null === $this->_translator) { |
|
314 require_once 'Zend/Registry.php'; |
|
315 if (Zend_Registry::isRegistered('Zend_Translate')) { |
|
316 $this->setTranslator(Zend_Registry::get('Zend_Translate')); |
|
317 } |
|
318 } |
|
319 |
|
320 return $this->_translator; |
|
321 } |
|
322 |
|
323 /** |
|
324 * Sets ACL to use when iterating pages |
|
325 * |
|
326 * Implements {@link Zend_View_Helper_Navigation_Helper::setAcl()}. |
|
327 * |
|
328 * @param Zend_Acl $acl [optional] ACL object. |
|
329 * Default is null. |
|
330 * @return Zend_View_Helper_Navigation_HelperAbstract fluent interface, |
|
331 * returns self |
|
332 */ |
|
333 public function setAcl(Zend_Acl $acl = null) |
|
334 { |
|
335 $this->_acl = $acl; |
|
336 return $this; |
|
337 } |
|
338 |
|
339 /** |
|
340 * Returns ACL or null if it isn't set using {@link setAcl()} or |
|
341 * {@link setDefaultAcl()} |
|
342 * |
|
343 * Implements {@link Zend_View_Helper_Navigation_Helper::getAcl()}. |
|
344 * |
|
345 * @return Zend_Acl|null ACL object or null |
|
346 */ |
|
347 public function getAcl() |
|
348 { |
|
349 if ($this->_acl === null && self::$_defaultAcl !== null) { |
|
350 return self::$_defaultAcl; |
|
351 } |
|
352 |
|
353 return $this->_acl; |
|
354 } |
|
355 |
|
356 /** |
|
357 * Sets ACL role(s) to use when iterating pages |
|
358 * |
|
359 * Implements {@link Zend_View_Helper_Navigation_Helper::setRole()}. |
|
360 * |
|
361 * @param mixed $role [optional] role to |
|
362 * set. Expects a string, |
|
363 * an instance of type |
|
364 * {@link Zend_Acl_Role_Interface}, |
|
365 * or null. Default is |
|
366 * null, which will set |
|
367 * no role. |
|
368 * @throws Zend_View_Exception if $role is invalid |
|
369 * @return Zend_View_Helper_Navigation_HelperAbstract fluent interface, |
|
370 * returns self |
|
371 */ |
|
372 public function setRole($role = null) |
|
373 { |
|
374 if (null === $role || is_string($role) || |
|
375 $role instanceof Zend_Acl_Role_Interface) { |
|
376 $this->_role = $role; |
|
377 } else { |
|
378 require_once 'Zend/View/Exception.php'; |
|
379 $e = new Zend_View_Exception(sprintf( |
|
380 '$role must be a string, null, or an instance of ' |
|
381 . 'Zend_Acl_Role_Interface; %s given', |
|
382 gettype($role) |
|
383 )); |
|
384 $e->setView($this->view); |
|
385 throw $e; |
|
386 } |
|
387 |
|
388 return $this; |
|
389 } |
|
390 |
|
391 /** |
|
392 * Returns ACL role to use when iterating pages, or null if it isn't set |
|
393 * using {@link setRole()} or {@link setDefaultRole()} |
|
394 * |
|
395 * Implements {@link Zend_View_Helper_Navigation_Helper::getRole()}. |
|
396 * |
|
397 * @return string|Zend_Acl_Role_Interface|null role or null |
|
398 */ |
|
399 public function getRole() |
|
400 { |
|
401 if ($this->_role === null && self::$_defaultRole !== null) { |
|
402 return self::$_defaultRole; |
|
403 } |
|
404 |
|
405 return $this->_role; |
|
406 } |
|
407 |
|
408 /** |
|
409 * Sets whether ACL should be used |
|
410 * |
|
411 * Implements {@link Zend_View_Helper_Navigation_Helper::setUseAcl()}. |
|
412 * |
|
413 * @param bool $useAcl [optional] whether ACL |
|
414 * should be used. |
|
415 * Default is true. |
|
416 * @return Zend_View_Helper_Navigation_HelperAbstract fluent interface, |
|
417 * returns self |
|
418 */ |
|
419 public function setUseAcl($useAcl = true) |
|
420 { |
|
421 $this->_useAcl = (bool) $useAcl; |
|
422 return $this; |
|
423 } |
|
424 |
|
425 /** |
|
426 * Returns whether ACL should be used |
|
427 * |
|
428 * Implements {@link Zend_View_Helper_Navigation_Helper::getUseAcl()}. |
|
429 * |
|
430 * @return bool whether ACL should be used |
|
431 */ |
|
432 public function getUseAcl() |
|
433 { |
|
434 return $this->_useAcl; |
|
435 } |
|
436 |
|
437 /** |
|
438 * Return renderInvisible flag |
|
439 * |
|
440 * @return bool |
|
441 */ |
|
442 public function getRenderInvisible() |
|
443 { |
|
444 return $this->_renderInvisible; |
|
445 } |
|
446 |
|
447 /** |
|
448 * Render invisible items? |
|
449 * |
|
450 * @param bool $renderInvisible [optional] boolean flag |
|
451 * @return Zend_View_Helper_Navigation_HelperAbstract fluent interface |
|
452 * returns self |
|
453 */ |
|
454 public function setRenderInvisible($renderInvisible = true) |
|
455 { |
|
456 $this->_renderInvisible = (bool) $renderInvisible; |
|
457 return $this; |
|
458 } |
|
459 |
|
460 /** |
|
461 * Sets whether translator should be used |
|
462 * |
|
463 * Implements {@link Zend_View_Helper_Navigation_Helper::setUseTranslator()}. |
|
464 * |
|
465 * @param bool $useTranslator [optional] whether |
|
466 * translator should be |
|
467 * used. Default is true. |
|
468 * @return Zend_View_Helper_Navigation_HelperAbstract fluent interface, |
|
469 * returns self |
|
470 */ |
|
471 public function setUseTranslator($useTranslator = true) |
|
472 { |
|
473 $this->_useTranslator = (bool) $useTranslator; |
|
474 return $this; |
|
475 } |
|
476 |
|
477 /** |
|
478 * Returns whether translator should be used |
|
479 * |
|
480 * Implements {@link Zend_View_Helper_Navigation_Helper::getUseTranslator()}. |
|
481 * |
|
482 * @return bool whether translator should be used |
|
483 */ |
|
484 public function getUseTranslator() |
|
485 { |
|
486 return $this->_useTranslator; |
|
487 } |
|
488 |
|
489 // Magic overloads: |
|
490 |
|
491 /** |
|
492 * Magic overload: Proxy calls to the navigation container |
|
493 * |
|
494 * @param string $method method name in container |
|
495 * @param array $arguments [optional] arguments to pass |
|
496 * @return mixed returns what the container returns |
|
497 * @throws Zend_Navigation_Exception if method does not exist in container |
|
498 */ |
|
499 public function __call($method, array $arguments = array()) |
|
500 { |
|
501 return call_user_func_array( |
|
502 array($this->getContainer(), $method), |
|
503 $arguments); |
|
504 } |
|
505 |
|
506 /** |
|
507 * Magic overload: Proxy to {@link render()}. |
|
508 * |
|
509 * This method will trigger an E_USER_ERROR if rendering the helper causes |
|
510 * an exception to be thrown. |
|
511 * |
|
512 * Implements {@link Zend_View_Helper_Navigation_Helper::__toString()}. |
|
513 * |
|
514 * @return string |
|
515 */ |
|
516 public function __toString() |
|
517 { |
|
518 try { |
|
519 return $this->render(); |
|
520 } catch (Exception $e) { |
|
521 $msg = get_class($e) . ': ' . $e->getMessage(); |
|
522 trigger_error($msg, E_USER_ERROR); |
|
523 return ''; |
|
524 } |
|
525 } |
|
526 |
|
527 // Public methods: |
|
528 |
|
529 /** |
|
530 * Finds the deepest active page in the given container |
|
531 * |
|
532 * @param Zend_Navigation_Container $container container to search |
|
533 * @param int|null $minDepth [optional] minimum depth |
|
534 * required for page to be |
|
535 * valid. Default is to use |
|
536 * {@link getMinDepth()}. A |
|
537 * null value means no minimum |
|
538 * depth required. |
|
539 * @param int|null $minDepth [optional] maximum depth |
|
540 * a page can have to be |
|
541 * valid. Default is to use |
|
542 * {@link getMaxDepth()}. A |
|
543 * null value means no maximum |
|
544 * depth required. |
|
545 * @return array an associative array with |
|
546 * the values 'depth' and |
|
547 * 'page', or an empty array |
|
548 * if not found |
|
549 */ |
|
550 public function findActive(Zend_Navigation_Container $container, |
|
551 $minDepth = null, |
|
552 $maxDepth = -1) |
|
553 { |
|
554 if (!is_int($minDepth)) { |
|
555 $minDepth = $this->getMinDepth(); |
|
556 } |
|
557 if ((!is_int($maxDepth) || $maxDepth < 0) && null !== $maxDepth) { |
|
558 $maxDepth = $this->getMaxDepth(); |
|
559 } |
|
560 |
|
561 $found = null; |
|
562 $foundDepth = -1; |
|
563 $iterator = new RecursiveIteratorIterator($container, |
|
564 RecursiveIteratorIterator::CHILD_FIRST); |
|
565 |
|
566 foreach ($iterator as $page) { |
|
567 $currDepth = $iterator->getDepth(); |
|
568 if ($currDepth < $minDepth || !$this->accept($page)) { |
|
569 // page is not accepted |
|
570 continue; |
|
571 } |
|
572 |
|
573 if ($page->isActive(false) && $currDepth > $foundDepth) { |
|
574 // found an active page at a deeper level than before |
|
575 $found = $page; |
|
576 $foundDepth = $currDepth; |
|
577 } |
|
578 } |
|
579 |
|
580 if (is_int($maxDepth) && $foundDepth > $maxDepth) { |
|
581 while ($foundDepth > $maxDepth) { |
|
582 if (--$foundDepth < $minDepth) { |
|
583 $found = null; |
|
584 break; |
|
585 } |
|
586 |
|
587 $found = $found->getParent(); |
|
588 if (!$found instanceof Zend_Navigation_Page) { |
|
589 $found = null; |
|
590 break; |
|
591 } |
|
592 } |
|
593 } |
|
594 |
|
595 if ($found) { |
|
596 return array('page' => $found, 'depth' => $foundDepth); |
|
597 } else { |
|
598 return array(); |
|
599 } |
|
600 } |
|
601 |
|
602 /** |
|
603 * Checks if the helper has a container |
|
604 * |
|
605 * Implements {@link Zend_View_Helper_Navigation_Helper::hasContainer()}. |
|
606 * |
|
607 * @return bool whether the helper has a container or not |
|
608 */ |
|
609 public function hasContainer() |
|
610 { |
|
611 return null !== $this->_container; |
|
612 } |
|
613 |
|
614 /** |
|
615 * Checks if the helper has an ACL instance |
|
616 * |
|
617 * Implements {@link Zend_View_Helper_Navigation_Helper::hasAcl()}. |
|
618 * |
|
619 * @return bool whether the helper has a an ACL instance or not |
|
620 */ |
|
621 public function hasAcl() |
|
622 { |
|
623 return null !== $this->_acl; |
|
624 } |
|
625 |
|
626 /** |
|
627 * Checks if the helper has an ACL role |
|
628 * |
|
629 * Implements {@link Zend_View_Helper_Navigation_Helper::hasRole()}. |
|
630 * |
|
631 * @return bool whether the helper has a an ACL role or not |
|
632 */ |
|
633 public function hasRole() |
|
634 { |
|
635 return null !== $this->_role; |
|
636 } |
|
637 |
|
638 /** |
|
639 * Checks if the helper has a translator |
|
640 * |
|
641 * Implements {@link Zend_View_Helper_Navigation_Helper::hasTranslator()}. |
|
642 * |
|
643 * @return bool whether the helper has a translator or not |
|
644 */ |
|
645 public function hasTranslator() |
|
646 { |
|
647 return null !== $this->_translator; |
|
648 } |
|
649 |
|
650 /** |
|
651 * Returns an HTML string containing an 'a' element for the given page |
|
652 * |
|
653 * @param Zend_Navigation_Page $page page to generate HTML for |
|
654 * @return string HTML string for the given page |
|
655 */ |
|
656 public function htmlify(Zend_Navigation_Page $page) |
|
657 { |
|
658 // get label and title for translating |
|
659 $label = $page->getLabel(); |
|
660 $title = $page->getTitle(); |
|
661 |
|
662 if ($this->getUseTranslator() && $t = $this->getTranslator()) { |
|
663 if (is_string($label) && !empty($label)) { |
|
664 $label = $t->translate($label); |
|
665 } |
|
666 if (is_string($title) && !empty($title)) { |
|
667 $title = $t->translate($title); |
|
668 } |
|
669 } |
|
670 |
|
671 // get attribs for anchor element |
|
672 $attribs = array( |
|
673 'id' => $page->getId(), |
|
674 'title' => $title, |
|
675 'class' => $page->getClass(), |
|
676 'href' => $page->getHref(), |
|
677 'target' => $page->getTarget() |
|
678 ); |
|
679 |
|
680 return '<a' . $this->_htmlAttribs($attribs) . '>' |
|
681 . $this->view->escape($label) |
|
682 . '</a>'; |
|
683 } |
|
684 |
|
685 // Iterator filter methods: |
|
686 |
|
687 /** |
|
688 * Determines whether a page should be accepted when iterating |
|
689 * |
|
690 * Rules: |
|
691 * - If a page is not visible it is not accepted, unless RenderInvisible has |
|
692 * been set to true. |
|
693 * - If helper has no ACL, page is accepted |
|
694 * - If helper has ACL, but no role, page is not accepted |
|
695 * - If helper has ACL and role: |
|
696 * - Page is accepted if it has no resource or privilege |
|
697 * - Page is accepted if ACL allows page's resource or privilege |
|
698 * - If page is accepted by the rules above and $recursive is true, the page |
|
699 * will not be accepted if it is the descendant of a non-accepted page. |
|
700 * |
|
701 * @param Zend_Navigation_Page $page page to check |
|
702 * @param bool $recursive [optional] if true, page will not |
|
703 * be accepted if it is the |
|
704 * descendant of a page that is not |
|
705 * accepted. Default is true. |
|
706 * @return bool whether page should be accepted |
|
707 */ |
|
708 public function accept(Zend_Navigation_Page $page, $recursive = true) |
|
709 { |
|
710 // accept by default |
|
711 $accept = true; |
|
712 |
|
713 if (!$page->isVisible(false) && !$this->getRenderInvisible()) { |
|
714 // don't accept invisible pages |
|
715 $accept = false; |
|
716 } elseif ($this->getUseAcl() && !$this->_acceptAcl($page)) { |
|
717 // acl is not amused |
|
718 $accept = false; |
|
719 } |
|
720 |
|
721 if ($accept && $recursive) { |
|
722 $parent = $page->getParent(); |
|
723 if ($parent instanceof Zend_Navigation_Page) { |
|
724 $accept = $this->accept($parent, true); |
|
725 } |
|
726 } |
|
727 |
|
728 return $accept; |
|
729 } |
|
730 |
|
731 /** |
|
732 * Determines whether a page should be accepted by ACL when iterating |
|
733 * |
|
734 * Rules: |
|
735 * - If helper has no ACL, page is accepted |
|
736 * - If page has a resource or privilege defined, page is accepted |
|
737 * if the ACL allows access to it using the helper's role |
|
738 * - If page has no resource or privilege, page is accepted |
|
739 * |
|
740 * @param Zend_Navigation_Page $page page to check |
|
741 * @return bool whether page is accepted by ACL |
|
742 */ |
|
743 protected function _acceptAcl(Zend_Navigation_Page $page) |
|
744 { |
|
745 if (!$acl = $this->getAcl()) { |
|
746 // no acl registered means don't use acl |
|
747 return true; |
|
748 } |
|
749 |
|
750 $role = $this->getRole(); |
|
751 $resource = $page->getResource(); |
|
752 $privilege = $page->getPrivilege(); |
|
753 |
|
754 if ($resource || $privilege) { |
|
755 // determine using helper role and page resource/privilege |
|
756 return $acl->isAllowed($role, $resource, $privilege); |
|
757 } |
|
758 |
|
759 return true; |
|
760 } |
|
761 |
|
762 // Util methods: |
|
763 |
|
764 /** |
|
765 * Retrieve whitespace representation of $indent |
|
766 * |
|
767 * @param int|string $indent |
|
768 * @return string |
|
769 */ |
|
770 protected function _getWhitespace($indent) |
|
771 { |
|
772 if (is_int($indent)) { |
|
773 $indent = str_repeat(' ', $indent); |
|
774 } |
|
775 |
|
776 return (string) $indent; |
|
777 } |
|
778 |
|
779 /** |
|
780 * Converts an associative array to a string of tag attributes. |
|
781 * |
|
782 * Overloads {@link Zend_View_Helper_HtmlElement::_htmlAttribs()}. |
|
783 * |
|
784 * @param array $attribs an array where each key-value pair is converted |
|
785 * to an attribute name and value |
|
786 * @return string an attribute string |
|
787 */ |
|
788 protected function _htmlAttribs($attribs) |
|
789 { |
|
790 // filter out null values and empty string values |
|
791 foreach ($attribs as $key => $value) { |
|
792 if ($value === null || (is_string($value) && !strlen($value))) { |
|
793 unset($attribs[$key]); |
|
794 } |
|
795 } |
|
796 |
|
797 return parent::_htmlAttribs($attribs); |
|
798 } |
|
799 |
|
800 /** |
|
801 * Normalize an ID |
|
802 * |
|
803 * Overrides {@link Zend_View_Helper_HtmlElement::_normalizeId()}. |
|
804 * |
|
805 * @param string $value |
|
806 * @return string |
|
807 */ |
|
808 protected function _normalizeId($value) |
|
809 { |
|
810 $prefix = get_class($this); |
|
811 $prefix = strtolower(trim(substr($prefix, strrpos($prefix, '_')), '_')); |
|
812 |
|
813 return $prefix . '-' . $value; |
|
814 } |
|
815 |
|
816 // Static methods: |
|
817 |
|
818 /** |
|
819 * Sets default ACL to use if another ACL is not explicitly set |
|
820 * |
|
821 * @param Zend_Acl $acl [optional] ACL object. Default is null, which |
|
822 * sets no ACL object. |
|
823 * @return void |
|
824 */ |
|
825 public static function setDefaultAcl(Zend_Acl $acl = null) |
|
826 { |
|
827 self::$_defaultAcl = $acl; |
|
828 } |
|
829 |
|
830 /** |
|
831 * Sets default ACL role(s) to use when iterating pages if not explicitly |
|
832 * set later with {@link setRole()} |
|
833 * |
|
834 * @param midex $role [optional] role to set. Expects null, |
|
835 * string, or an instance of |
|
836 * {@link Zend_Acl_Role_Interface}. |
|
837 * Default is null, which sets no default |
|
838 * role. |
|
839 * @throws Zend_View_Exception if role is invalid |
|
840 * @return void |
|
841 */ |
|
842 public static function setDefaultRole($role = null) |
|
843 { |
|
844 if (null === $role || |
|
845 is_string($role) || |
|
846 $role instanceof Zend_Acl_Role_Interface) { |
|
847 self::$_defaultRole = $role; |
|
848 } else { |
|
849 require_once 'Zend/View/Exception.php'; |
|
850 throw new Zend_View_Exception( |
|
851 '$role must be null|string|Zend_Acl_Role_Interface' |
|
852 ); |
|
853 } |
|
854 } |
|
855 } |