/library/Zend/Controller/Action/Helper/ContextSwitch.php
PHP | 1394 lines | 739 code | 147 blank | 508 comment | 113 complexity | 3cc0438edf9c8b6b4b8cc1c761032e93 MD5 | raw file
Possible License(s): AGPL-1.0
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_Controller
17 * @subpackage Zend_Controller_Action_Helper
18 * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
19 * @license http://framework.zend.com/license/new-bsd New BSD License
20 * @version $Id: ContextSwitch.php 24594 2012-01-05 21:27:01Z matthew $
21 */
22
23/**
24 * @see Zend_Controller_Action_Helper_Abstract
25 */
26require_once 'Zend/Controller/Action/Helper/Abstract.php';
27
28/**
29 * Simplify context switching based on requested format
30 *
31 * @uses Zend_Controller_Action_Helper_Abstract
32 * @category Zend
33 * @package Zend_Controller
34 * @subpackage Zend_Controller_Action_Helper
35 * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
36 * @license http://framework.zend.com/license/new-bsd New BSD License
37 */
38class Zend_Controller_Action_Helper_ContextSwitch extends Zend_Controller_Action_Helper_Abstract
39{
40 /**
41 * Trigger type constants
42 */
43 const TRIGGER_INIT = 'TRIGGER_INIT';
44 const TRIGGER_POST = 'TRIGGER_POST';
45
46 /**
47 * Supported contexts
48 * @var array
49 */
50 protected $_contexts = array();
51
52 /**
53 * JSON auto-serialization flag
54 * @var boolean
55 */
56 protected $_autoJsonSerialization = true;
57
58 /**
59 * Controller property key to utilize for context switching
60 * @var string
61 */
62 protected $_contextKey = 'contexts';
63
64 /**
65 * Request parameter containing requested context
66 * @var string
67 */
68 protected $_contextParam = 'format';
69
70 /**
71 * Current context
72 * @var string
73 */
74 protected $_currentContext;
75
76 /**
77 * Default context (xml)
78 * @var string
79 */
80 protected $_defaultContext = 'xml';
81
82 /**
83 * Whether or not to disable layouts when switching contexts
84 * @var boolean
85 */
86 protected $_disableLayout = true;
87
88 /**
89 * Methods that require special configuration
90 * @var array
91 */
92 protected $_specialConfig = array(
93 'setSuffix',
94 'setHeaders',
95 'setCallbacks',
96 );
97
98 /**
99 * Methods that are not configurable via setOptions and setConfig
100 * @var array
101 */
102 protected $_unconfigurable = array(
103 'setOptions',
104 'setConfig',
105 'setHeader',
106 'setCallback',
107 'setContext',
108 'setActionContext',
109 'setActionContexts',
110 );
111
112 /**
113 * @var Zend_Controller_Action_Helper_ViewRenderer
114 */
115 protected $_viewRenderer;
116
117 /**
118 * Original view suffix prior to detecting context switch
119 * @var string
120 */
121 protected $_viewSuffixOrig;
122
123 /**
124 * Constructor
125 *
126 * @param array|Zend_Config $options
127 * @return void
128 */
129 public function __construct($options = null)
130 {
131 if ($options instanceof Zend_Config) {
132 $this->setConfig($options);
133 } elseif (is_array($options)) {
134 $this->setOptions($options);
135 }
136
137 if (empty($this->_contexts)) {
138 $this->addContexts(array(
139 'json' => array(
140 'suffix' => 'json',
141 'headers' => array('Content-Type' => 'application/json'),
142 'callbacks' => array(
143 'init' => 'initJsonContext',
144 'post' => 'postJsonContext'
145 )
146 ),
147 'xml' => array(
148 'suffix' => 'xml',
149 'headers' => array('Content-Type' => 'application/xml'),
150 )
151 ));
152 }
153
154 $this->init();
155 }
156
157 /**
158 * Initialize at start of action controller
159 *
160 * Reset the view script suffix to the original state, or store the
161 * original state.
162 *
163 * @return void
164 */
165 public function init()
166 {
167 if (null === $this->_viewSuffixOrig) {
168 $this->_viewSuffixOrig = $this->_getViewRenderer()->getViewSuffix();
169 } else {
170 $this->_getViewRenderer()->setViewSuffix($this->_viewSuffixOrig);
171 }
172 }
173
174 /**
175 * Configure object from array of options
176 *
177 * @param array $options
178 * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface
179 */
180 public function setOptions(array $options)
181 {
182 if (isset($options['contexts'])) {
183 $this->setContexts($options['contexts']);
184 unset($options['contexts']);
185 }
186
187 foreach ($options as $key => $value) {
188 $method = 'set' . ucfirst($key);
189 if (in_array($method, $this->_unconfigurable)) {
190 continue;
191 }
192
193 if (in_array($method, $this->_specialConfig)) {
194 $method = '_' . $method;
195 }
196
197 if (method_exists($this, $method)) {
198 $this->$method($value);
199 }
200 }
201 return $this;
202 }
203
204 /**
205 * Set object state from config object
206 *
207 * @param Zend_Config $config
208 * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface
209 */
210 public function setConfig(Zend_Config $config)
211 {
212 return $this->setOptions($config->toArray());
213 }
214
215 /**
216 * Strategy pattern: return object
217 *
218 * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface
219 */
220 public function direct()
221 {
222 return $this;
223 }
224
225 /**
226 * Initialize context detection and switching
227 *
228 * @param mixed $format
229 * @throws Zend_Controller_Action_Exception
230 * @return void
231 */
232 public function initContext($format = null)
233 {
234 $this->_currentContext = null;
235
236 $controller = $this->getActionController();
237 $request = $this->getRequest();
238 $action = $request->getActionName();
239
240 // Return if no context switching enabled, or no context switching
241 // enabled for this action
242 $contexts = $this->getActionContexts($action);
243 if (empty($contexts)) {
244 return;
245 }
246
247 // Return if no context parameter provided
248 if (!$context = $request->getParam($this->getContextParam())) {
249 if ($format === null) {
250 return;
251 }
252 $context = $format;
253 $format = null;
254 }
255
256 // Check if context allowed by action controller
257 if (!$this->hasActionContext($action, $context)) {
258 return;
259 }
260
261 // Return if invalid context parameter provided and no format or invalid
262 // format provided
263 if (!$this->hasContext($context)) {
264 if (empty($format) || !$this->hasContext($format)) {
265
266 return;
267 }
268 }
269
270 // Use provided format if passed
271 if (!empty($format) && $this->hasContext($format)) {
272 $context = $format;
273 }
274
275 $suffix = $this->getSuffix($context);
276
277 $this->_getViewRenderer()->setViewSuffix($suffix);
278
279 $headers = $this->getHeaders($context);
280 if (!empty($headers)) {
281 $response = $this->getResponse();
282 foreach ($headers as $header => $content) {
283 $response->setHeader($header, $content);
284 }
285 }
286
287 if ($this->getAutoDisableLayout()) {
288 /**
289 * @see Zend_Layout
290 */
291 require_once 'Zend/Layout.php';
292 $layout = Zend_Layout::getMvcInstance();
293 if (null !== $layout) {
294 $layout->disableLayout();
295 }
296 }
297
298 if (null !== ($callback = $this->getCallback($context, self::TRIGGER_INIT))) {
299 if (is_string($callback) && method_exists($this, $callback)) {
300 $this->$callback();
301 } elseif (is_string($callback) && function_exists($callback)) {
302 $callback();
303 } elseif (is_array($callback)) {
304 call_user_func($callback);
305 } else {
306 /**
307 * @see Zend_Controller_Action_Exception
308 */
309 require_once 'Zend/Controller/Action/Exception.php';
310 throw new Zend_Controller_Action_Exception(sprintf('Invalid context callback registered for context "%s"', $context));
311 }
312 }
313
314 $this->_currentContext = $context;
315 }
316
317 /**
318 * JSON context extra initialization
319 *
320 * Turns off viewRenderer auto-rendering
321 *
322 * @return void
323 */
324 public function initJsonContext()
325 {
326 if (!$this->getAutoJsonSerialization()) {
327 return;
328 }
329
330 $viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer');
331 $view = $viewRenderer->view;
332 if ($view instanceof Zend_View_Interface) {
333 $viewRenderer->setNoRender(true);
334 }
335 }
336
337 /**
338 * Should JSON contexts auto-serialize?
339 *
340 * @param boolean $flag
341 * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface
342 */
343 public function setAutoJsonSerialization($flag)
344 {
345 $this->_autoJsonSerialization = (bool) $flag;
346 return $this;
347 }
348
349 /**
350 * Get JSON context auto-serialization flag
351 *
352 * @return boolean
353 */
354 public function getAutoJsonSerialization()
355 {
356 return $this->_autoJsonSerialization;
357 }
358
359 /**
360 * Set suffix from array
361 *
362 * @param array $spec
363 * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface
364 */
365 protected function _setSuffix(array $spec)
366 {
367 foreach ($spec as $context => $suffixInfo) {
368 if (!is_string($context)) {
369 $context = null;
370 }
371
372 if (is_string($suffixInfo)) {
373 $this->setSuffix($context, $suffixInfo);
374 continue;
375 } elseif (is_array($suffixInfo)) {
376 if (isset($suffixInfo['suffix'])) {
377 $suffix = $suffixInfo['suffix'];
378 $prependViewRendererSuffix = true;
379
380 if ((null === $context) && isset($suffixInfo['context'])) {
381 $context = $suffixInfo['context'];
382 }
383
384 if (isset($suffixInfo['prependViewRendererSuffix'])) {
385 $prependViewRendererSuffix = $suffixInfo['prependViewRendererSuffix'];
386 }
387
388 $this->setSuffix($context, $suffix, $prependViewRendererSuffix);
389 continue;
390 }
391
392 $count = count($suffixInfo);
393 switch (true) {
394 case (($count < 2) && (null === $context)):
395 /**
396 * @see Zend_Controller_Action_Exception
397 */
398 require_once 'Zend/Controller/Action/Exception.php';
399 throw new Zend_Controller_Action_Exception('Invalid suffix information provided in config');
400 case ($count < 2):
401 $suffix = array_shift($suffixInfo);
402 $this->setSuffix($context, $suffix);
403 break;
404 case (($count < 3) && (null === $context)):
405 $context = array_shift($suffixInfo);
406 $suffix = array_shift($suffixInfo);
407 $this->setSuffix($context, $suffix);
408 break;
409 case (($count == 3) && (null === $context)):
410 $context = array_shift($suffixInfo);
411 $suffix = array_shift($suffixInfo);
412 $prependViewRendererSuffix = array_shift($suffixInfo);
413 $this->setSuffix($context, $suffix, $prependViewRendererSuffix);
414 break;
415 case ($count >= 2):
416 $suffix = array_shift($suffixInfo);
417 $prependViewRendererSuffix = array_shift($suffixInfo);
418 $this->setSuffix($context, $suffix, $prependViewRendererSuffix);
419 break;
420 }
421 }
422 }
423 return $this;
424 }
425
426 /**
427 * Customize view script suffix to use when switching context.
428 *
429 * Passing an empty suffix value to the setters disables the view script
430 * suffix change.
431 *
432 * @param string $context Context type for which to set suffix
433 * @param string $suffix Suffix to use
434 * @param boolean $prependViewRendererSuffix Whether or not to prepend the new suffix to the viewrenderer suffix
435 * @throws Zend_Controller_Action_Exception
436 * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface
437 */
438 public function setSuffix($context, $suffix, $prependViewRendererSuffix = true)
439 {
440 if (!isset($this->_contexts[$context])) {
441 /**
442 * @see Zend_Controller_Action_Exception
443 */
444 require_once 'Zend/Controller/Action/Exception.php';
445 throw new Zend_Controller_Action_Exception(sprintf('Cannot set suffix; invalid context type "%s"', $context));
446 }
447
448 if (empty($suffix)) {
449 $suffix = '';
450 }
451
452 if (is_array($suffix)) {
453 if (isset($suffix['prependViewRendererSuffix'])) {
454 $prependViewRendererSuffix = $suffix['prependViewRendererSuffix'];
455 }
456 if (isset($suffix['suffix'])) {
457 $suffix = $suffix['suffix'];
458 } else {
459 $suffix = '';
460 }
461 }
462
463 $suffix = (string) $suffix;
464
465 if ($prependViewRendererSuffix) {
466 if (empty($suffix)) {
467 $suffix = $this->_getViewRenderer()->getViewSuffix();
468 } else {
469 $suffix .= '.' . $this->_getViewRenderer()->getViewSuffix();
470 }
471 }
472
473 $this->_contexts[$context]['suffix'] = $suffix;
474 return $this;
475 }
476
477 /**
478 * Retrieve suffix for given context type
479 *
480 * @param string $type Context type
481 * @throws Zend_Controller_Action_Exception
482 * @return string
483 */
484 public function getSuffix($type)
485 {
486 if (!isset($this->_contexts[$type])) {
487 /**
488 * @see Zend_Controller_Action_Exception
489 */
490 require_once 'Zend/Controller/Action/Exception.php';
491 throw new Zend_Controller_Action_Exception(sprintf('Cannot retrieve suffix; invalid context type "%s"', $type));
492 }
493
494 return $this->_contexts[$type]['suffix'];
495 }
496
497 /**
498 * Does the given context exist?
499 *
500 * @param string $context
501 * @param boolean $throwException
502 * @throws Zend_Controller_Action_Exception if context does not exist and throwException is true
503 * @return bool
504 */
505 public function hasContext($context, $throwException = false)
506 {
507 if (is_string($context)) {
508 if (isset($this->_contexts[$context])) {
509 return true;
510 }
511 } elseif (is_array($context)) {
512 $error = false;
513 foreach ($context as $test) {
514 if (!isset($this->_contexts[$test])) {
515 $error = (string) $test;
516 break;
517 }
518 }
519 if (false === $error) {
520 return true;
521 }
522 $context = $error;
523 } elseif (true === $context) {
524 return true;
525 }
526
527 if ($throwException) {
528 /**
529 * @see Zend_Controller_Action_Exception
530 */
531 require_once 'Zend/Controller/Action/Exception.php';
532 throw new Zend_Controller_Action_Exception(sprintf('Context "%s" does not exist', $context));
533 }
534
535 return false;
536 }
537
538 /**
539 * Add header to context
540 *
541 * @param string $context
542 * @param string $header
543 * @param string $content
544 * @throws Zend_Controller_Action_Exception
545 * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface
546 */
547 public function addHeader($context, $header, $content)
548 {
549 $context = (string) $context;
550 $this->hasContext($context, true);
551
552 $header = (string) $header;
553 $content = (string) $content;
554
555 if (isset($this->_contexts[$context]['headers'][$header])) {
556 /**
557 * @see Zend_Controller_Action_Exception
558 */
559 require_once 'Zend/Controller/Action/Exception.php';
560 throw new Zend_Controller_Action_Exception(sprintf('Cannot add "%s" header to context "%s": already exists', $header, $context));
561 }
562
563 $this->_contexts[$context]['headers'][$header] = $content;
564 return $this;
565 }
566
567 /**
568 * Customize response header to use when switching context
569 *
570 * Passing an empty header value to the setters disables the response
571 * header.
572 *
573 * @param string $type Context type for which to set suffix
574 * @param string $header Header to set
575 * @param string $content Header content
576 * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface
577 */
578 public function setHeader($context, $header, $content)
579 {
580 $this->hasContext($context, true);
581 $context = (string) $context;
582 $header = (string) $header;
583 $content = (string) $content;
584
585 $this->_contexts[$context]['headers'][$header] = $content;
586 return $this;
587 }
588
589 /**
590 * Add multiple headers at once for a given context
591 *
592 * @param string $context
593 * @param array $headers
594 * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface
595 */
596 public function addHeaders($context, array $headers)
597 {
598 foreach ($headers as $header => $content) {
599 $this->addHeader($context, $header, $content);
600 }
601
602 return $this;
603 }
604
605 /**
606 * Set headers from context => headers pairs
607 *
608 * @param array $options
609 * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface
610 */
611 protected function _setHeaders(array $options)
612 {
613 foreach ($options as $context => $headers) {
614 if (!is_array($headers)) {
615 continue;
616 }
617 $this->setHeaders($context, $headers);
618 }
619
620 return $this;
621 }
622
623 /**
624 * Set multiple headers at once for a given context
625 *
626 * @param string $context
627 * @param array $headers
628 * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface
629 */
630 public function setHeaders($context, array $headers)
631 {
632 $this->clearHeaders($context);
633 foreach ($headers as $header => $content) {
634 $this->setHeader($context, $header, $content);
635 }
636
637 return $this;
638 }
639
640 /**
641 * Retrieve context header
642 *
643 * Returns the value of a given header for a given context type
644 *
645 * @param string $context
646 * @param string $header
647 * @return string|null
648 */
649 public function getHeader($context, $header)
650 {
651 $this->hasContext($context, true);
652 $context = (string) $context;
653 $header = (string) $header;
654 if (isset($this->_contexts[$context]['headers'][$header])) {
655 return $this->_contexts[$context]['headers'][$header];
656 }
657
658 return null;
659 }
660
661 /**
662 * Retrieve context headers
663 *
664 * Returns all headers for a context as key/value pairs
665 *
666 * @param string $context
667 * @return array
668 */
669 public function getHeaders($context)
670 {
671 $this->hasContext($context, true);
672 $context = (string) $context;
673 return $this->_contexts[$context]['headers'];
674 }
675
676 /**
677 * Remove a single header from a context
678 *
679 * @param string $context
680 * @param string $header
681 * @return boolean
682 */
683 public function removeHeader($context, $header)
684 {
685 $this->hasContext($context, true);
686 $context = (string) $context;
687 $header = (string) $header;
688 if (isset($this->_contexts[$context]['headers'][$header])) {
689 unset($this->_contexts[$context]['headers'][$header]);
690 return true;
691 }
692
693 return false;
694 }
695
696 /**
697 * Clear all headers for a given context
698 *
699 * @param string $context
700 * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface
701 */
702 public function clearHeaders($context)
703 {
704 $this->hasContext($context, true);
705 $context = (string) $context;
706 $this->_contexts[$context]['headers'] = array();
707 return $this;
708 }
709
710 /**
711 * Validate trigger and return in normalized form
712 *
713 * @param string $trigger
714 * @throws Zend_Controller_Action_Exception
715 * @return string
716 */
717 protected function _validateTrigger($trigger)
718 {
719 $trigger = strtoupper($trigger);
720 if ('TRIGGER_' !== substr($trigger, 0, 8)) {
721 $trigger = 'TRIGGER_' . $trigger;
722 }
723
724 if (!in_array($trigger, array(self::TRIGGER_INIT, self::TRIGGER_POST))) {
725 /**
726 * @see Zend_Controller_Action_Exception
727 */
728 require_once 'Zend/Controller/Action/Exception.php';
729 throw new Zend_Controller_Action_Exception(sprintf('Invalid trigger "%s"', $trigger));
730 }
731
732 return $trigger;
733 }
734
735 /**
736 * Set a callback for a given context and trigger
737 *
738 * @param string $context
739 * @param string $trigger
740 * @param string|array $callback
741 * @throws Zend_Controller_Action_Exception
742 * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface
743 */
744 public function setCallback($context, $trigger, $callback)
745 {
746 $this->hasContext($context, true);
747 $trigger = $this->_validateTrigger($trigger);
748
749 if (!is_string($callback)) {
750 if (!is_array($callback) || (2 != count($callback))) {
751 /**
752 * @see Zend_Controller_Action_Exception
753 */
754 require_once 'Zend/Controller/Action/Exception.php';
755 throw new Zend_Controller_Action_Exception('Invalid callback specified');
756 }
757 }
758
759 $this->_contexts[$context]['callbacks'][$trigger] = $callback;
760 return $this;
761 }
762
763 /**
764 * Set callbacks from array of context => callbacks pairs
765 *
766 * @param array $options
767 * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface
768 */
769 protected function _setCallbacks(array $options)
770 {
771 foreach ($options as $context => $callbacks) {
772 if (!is_array($callbacks)) {
773 continue;
774 }
775
776 $this->setCallbacks($context, $callbacks);
777 }
778 return $this;
779 }
780
781 /**
782 * Set callbacks for a given context
783 *
784 * Callbacks should be in trigger/callback pairs.
785 *
786 * @param string $context
787 * @param array $callbacks
788 * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface
789 */
790 public function setCallbacks($context, array $callbacks)
791 {
792 $this->hasContext($context, true);
793 $context = (string) $context;
794 if (!isset($this->_contexts[$context]['callbacks'])) {
795 $this->_contexts[$context]['callbacks'] = array();
796 }
797
798 foreach ($callbacks as $trigger => $callback) {
799 $this->setCallback($context, $trigger, $callback);
800 }
801 return $this;
802 }
803
804 /**
805 * Get a single callback for a given context and trigger
806 *
807 * @param string $context
808 * @param string $trigger
809 * @return string|array|null
810 */
811 public function getCallback($context, $trigger)
812 {
813 $this->hasContext($context, true);
814 $trigger = $this->_validateTrigger($trigger);
815 if (isset($this->_contexts[$context]['callbacks'][$trigger])) {
816 return $this->_contexts[$context]['callbacks'][$trigger];
817 }
818
819 return null;
820 }
821
822 /**
823 * Get all callbacks for a given context
824 *
825 * @param string $context
826 * @return array
827 */
828 public function getCallbacks($context)
829 {
830 $this->hasContext($context, true);
831 return $this->_contexts[$context]['callbacks'];
832 }
833
834 /**
835 * Clear a callback for a given context and trigger
836 *
837 * @param string $context
838 * @param string $trigger
839 * @return boolean
840 */
841 public function removeCallback($context, $trigger)
842 {
843 $this->hasContext($context, true);
844 $trigger = $this->_validateTrigger($trigger);
845 if (isset($this->_contexts[$context]['callbacks'][$trigger])) {
846 unset($this->_contexts[$context]['callbacks'][$trigger]);
847 return true;
848 }
849
850 return false;
851 }
852
853 /**
854 * Clear all callbacks for a given context
855 *
856 * @param string $context
857 * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface
858 */
859 public function clearCallbacks($context)
860 {
861 $this->hasContext($context, true);
862 $this->_contexts[$context]['callbacks'] = array();
863 return $this;
864 }
865
866 /**
867 * Set name of parameter to use when determining context format
868 *
869 * @param string $name
870 * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface
871 */
872 public function setContextParam($name)
873 {
874 $this->_contextParam = (string) $name;
875 return $this;
876 }
877
878 /**
879 * Return context format request parameter name
880 *
881 * @return string
882 */
883 public function getContextParam()
884 {
885 return $this->_contextParam;
886 }
887
888 /**
889 * Indicate default context to use when no context format provided
890 *
891 * @param string $type
892 * @throws Zend_Controller_Action_Exception
893 * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface
894 */
895 public function setDefaultContext($type)
896 {
897 if (!isset($this->_contexts[$type])) {
898 /**
899 * @see Zend_Controller_Action_Exception
900 */
901 require_once 'Zend/Controller/Action/Exception.php';
902 throw new Zend_Controller_Action_Exception(sprintf('Cannot set default context; invalid context type "%s"', $type));
903 }
904
905 $this->_defaultContext = $type;
906 return $this;
907 }
908
909 /**
910 * Return default context
911 *
912 * @return string
913 */
914 public function getDefaultContext()
915 {
916 return $this->_defaultContext;
917 }
918
919 /**
920 * Set flag indicating if layout should be disabled
921 *
922 * @param boolean $flag
923 * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface
924 */
925 public function setAutoDisableLayout($flag)
926 {
927 $this->_disableLayout = ($flag) ? true : false;
928 return $this;
929 }
930
931 /**
932 * Retrieve auto layout disable flag
933 *
934 * @return boolean
935 */
936 public function getAutoDisableLayout()
937 {
938 return $this->_disableLayout;
939 }
940
941 /**
942 * Add new context
943 *
944 * @param string $context Context type
945 * @param array $spec Context specification
946 * @throws Zend_Controller_Action_Exception
947 * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface
948 */
949 public function addContext($context, array $spec)
950 {
951 if ($this->hasContext($context)) {
952 /**
953 * @see Zend_Controller_Action_Exception
954 */
955 require_once 'Zend/Controller/Action/Exception.php';
956 throw new Zend_Controller_Action_Exception(sprintf('Cannot add context "%s"; already exists', $context));
957 }
958 $context = (string) $context;
959
960 $this->_contexts[$context] = array();
961
962 $this->setSuffix($context, (isset($spec['suffix']) ? $spec['suffix'] : ''))
963 ->setHeaders($context, (isset($spec['headers']) ? $spec['headers'] : array()))
964 ->setCallbacks($context, (isset($spec['callbacks']) ? $spec['callbacks'] : array()));
965 return $this;
966 }
967
968 /**
969 * Overwrite existing context
970 *
971 * @param string $context Context type
972 * @param array $spec Context specification
973 * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface
974 */
975 public function setContext($context, array $spec)
976 {
977 $this->removeContext($context);
978 return $this->addContext($context, $spec);
979 }
980
981 /**
982 * Add multiple contexts
983 *
984 * @param array $contexts
985 * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface
986 */
987 public function addContexts(array $contexts)
988 {
989 foreach ($contexts as $context => $spec) {
990 $this->addContext($context, $spec);
991 }
992 return $this;
993 }
994
995 /**
996 * Set multiple contexts, after first removing all
997 *
998 * @param array $contexts
999 * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface
1000 */
1001 public function setContexts(array $contexts)
1002 {
1003 $this->clearContexts();
1004 foreach ($contexts as $context => $spec) {
1005 $this->addContext($context, $spec);
1006 }
1007 return $this;
1008 }
1009
1010 /**
1011 * Retrieve context specification
1012 *
1013 * @param string $context
1014 * @return array|null
1015 */
1016 public function getContext($context)
1017 {
1018 if ($this->hasContext($context)) {
1019 return $this->_contexts[(string) $context];
1020 }
1021 return null;
1022 }
1023
1024 /**
1025 * Retrieve context definitions
1026 *
1027 * @return array
1028 */
1029 public function getContexts()
1030 {
1031 return $this->_contexts;
1032 }
1033
1034 /**
1035 * Remove a context
1036 *
1037 * @param string $context
1038 * @return boolean
1039 */
1040 public function removeContext($context)
1041 {
1042 if ($this->hasContext($context)) {
1043 unset($this->_contexts[(string) $context]);
1044 return true;
1045 }
1046 return false;
1047 }
1048
1049 /**
1050 * Remove all contexts
1051 *
1052 * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface
1053 */
1054 public function clearContexts()
1055 {
1056 $this->_contexts = array();
1057 return $this;
1058 }
1059
1060 /**
1061 * Return current context, if any
1062 *
1063 * @return null|string
1064 */
1065 public function getCurrentContext()
1066 {
1067 return $this->_currentContext;
1068 }
1069
1070 /**
1071 * Post dispatch processing
1072 *
1073 * Execute postDispatch callback for current context, if available
1074 *
1075 * @throws Zend_Controller_Action_Exception
1076 * @return void
1077 */
1078 public function postDispatch()
1079 {
1080 $context = $this->getCurrentContext();
1081 if (null !== $context) {
1082 if (null !== ($callback = $this->getCallback($context, self::TRIGGER_POST))) {
1083 if (is_string($callback) && method_exists($this, $callback)) {
1084 $this->$callback();
1085 } elseif (is_string($callback) && function_exists($callback)) {
1086 $callback();
1087 } elseif (is_array($callback)) {
1088 call_user_func($callback);
1089 } else {
1090 /**
1091 * @see Zend_Controller_Action_Exception
1092 */
1093 require_once 'Zend/Controller/Action/Exception.php';
1094 throw new Zend_Controller_Action_Exception(sprintf('Invalid postDispatch context callback registered for context "%s"', $context));
1095 }
1096 }
1097 }
1098 }
1099
1100 /**
1101 * JSON post processing
1102 *
1103 * JSON serialize view variables to response body
1104 *
1105 * @return void
1106 */
1107 public function postJsonContext()
1108 {
1109 if (!$this->getAutoJsonSerialization()) {
1110 return;
1111 }
1112
1113 $viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer');
1114 $view = $viewRenderer->view;
1115 if ($view instanceof Zend_View_Interface) {
1116 /**
1117 * @see Zend_Json
1118 */
1119 if(method_exists($view, 'getVars')) {
1120 require_once 'Zend/Json.php';
1121 $vars = Zend_Json::encode($view->getVars());
1122 $this->getResponse()->setBody($vars);
1123 } else {
1124 require_once 'Zend/Controller/Action/Exception.php';
1125 throw new Zend_Controller_Action_Exception('View does not implement the getVars() method needed to encode the view into JSON');
1126 }
1127 }
1128 }
1129
1130 /**
1131 * Add one or more contexts to an action
1132 *
1133 * @param string $action
1134 * @param string|array $context
1135 * @return Zend_Controller_Action_Helper_ContextSwitch|void Provides a fluent interface
1136 */
1137 public function addActionContext($action, $context)
1138 {
1139 $this->hasContext($context, true);
1140 $controller = $this->getActionController();
1141 if (null === $controller) {
1142 return;
1143 }
1144 $action = (string) $action;
1145 $contextKey = $this->_contextKey;
1146
1147 if (!isset($controller->$contextKey)) {
1148 $controller->$contextKey = array();
1149 }
1150
1151 if (true === $context) {
1152 $contexts = $this->getContexts();
1153 $controller->{$contextKey}[$action] = array_keys($contexts);
1154 return $this;
1155 }
1156
1157 $context = (array) $context;
1158 if (!isset($controller->{$contextKey}[$action])) {
1159 $controller->{$contextKey}[$action] = $context;
1160 } else {
1161 $controller->{$contextKey}[$action] = array_merge(
1162 $controller->{$contextKey}[$action],
1163 $context
1164 );
1165 }
1166
1167 return $this;
1168 }
1169
1170 /**
1171 * Set a context as available for a given controller action
1172 *
1173 * @param string $action
1174 * @param string|array $context
1175 * @return Zend_Controller_Action_Helper_ContextSwitch|void Provides a fluent interface
1176 */
1177 public function setActionContext($action, $context)
1178 {
1179 $this->hasContext($context, true);
1180 $controller = $this->getActionController();
1181 if (null === $controller) {
1182 return;
1183 }
1184 $action = (string) $action;
1185 $contextKey = $this->_contextKey;
1186
1187 if (!isset($controller->$contextKey)) {
1188 $controller->$contextKey = array();
1189 }
1190
1191 if (true === $context) {
1192 $contexts = $this->getContexts();
1193 $controller->{$contextKey}[$action] = array_keys($contexts);
1194 } else {
1195 $controller->{$contextKey}[$action] = (array) $context;
1196 }
1197
1198 return $this;
1199 }
1200
1201 /**
1202 * Add multiple action/context pairs at once
1203 *
1204 * @param array $contexts
1205 * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface
1206 */
1207 public function addActionContexts(array $contexts)
1208 {
1209 foreach ($contexts as $action => $context) {
1210 $this->addActionContext($action, $context);
1211 }
1212 return $this;
1213 }
1214
1215 /**
1216 * Overwrite and set multiple action contexts at once
1217 *
1218 * @param array $contexts
1219 * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface
1220 */
1221 public function setActionContexts(array $contexts)
1222 {
1223 foreach ($contexts as $action => $context) {
1224 $this->setActionContext($action, $context);
1225 }
1226 return $this;
1227 }
1228
1229 /**
1230 * Does a particular controller action have the given context(s)?
1231 *
1232 * @param string $action
1233 * @param string|array $context
1234 * @throws Zend_Controller_Action_Exception
1235 * @return boolean
1236 */
1237 public function hasActionContext($action, $context)
1238 {
1239 $this->hasContext($context, true);
1240 $controller = $this->getActionController();
1241 if (null === $controller) {
1242 return false;
1243 }
1244 $action = (string) $action;
1245 $contextKey = $this->_contextKey;
1246
1247 if (!isset($controller->{$contextKey})) {
1248 return false;
1249 }
1250
1251 $allContexts = $controller->{$contextKey};
1252
1253 if (!is_array($allContexts)) {
1254 /**
1255 * @see Zend_Controller_Action_Exception
1256 */
1257 require_once 'Zend/Controller/Action/Exception.php';
1258 throw new Zend_Controller_Action_Exception("Invalid contexts found for controller");
1259 }
1260
1261 if (!isset($allContexts[$action])) {
1262 return false;
1263 }
1264
1265 if (true === $allContexts[$action]) {
1266 return true;
1267 }
1268
1269 $contexts = $allContexts[$action];
1270
1271 if (!is_array($contexts)) {
1272 /**
1273 * @see Zend_Controller_Action_Exception
1274 */
1275 require_once 'Zend/Controller/Action/Exception.php';
1276 throw new Zend_Controller_Action_Exception(sprintf("Invalid contexts found for action '%s'", $action));
1277 }
1278
1279 if (is_string($context) && in_array($context, $contexts)) {
1280 return true;
1281 } elseif (is_array($context)) {
1282 $found = true;
1283 foreach ($context as $test) {
1284 if (!in_array($test, $contexts)) {
1285 $found = false;
1286 break;
1287 }
1288 }
1289 return $found;
1290 }
1291
1292 return false;
1293 }
1294
1295 /**
1296 * Get contexts for a given action or all actions in the controller
1297 *
1298 * @param string $action
1299 * @return array
1300 */
1301 public function getActionContexts($action = null)
1302 {
1303 $controller = $this->getActionController();
1304 if (null === $controller) {
1305 return array();
1306 }
1307 $action = (string) $action;
1308 $contextKey = $this->_contextKey;
1309
1310 if (!isset($controller->$contextKey)) {
1311 return array();
1312 }
1313
1314 if (null !== $action) {
1315 if (isset($controller->{$contextKey}[$action])) {
1316 return $controller->{$contextKey}[$action];
1317 } else {
1318 return array();
1319 }
1320 }
1321
1322 return $controller->$contextKey;
1323 }
1324
1325 /**
1326 * Remove one or more contexts for a given controller action
1327 *
1328 * @param string $action
1329 * @param string|array $context
1330 * @return boolean
1331 */
1332 public function removeActionContext($action, $context)
1333 {
1334 if ($this->hasActionContext($action, $context)) {
1335 $controller = $this->getActionController();
1336 $contextKey = $this->_contextKey;
1337 $action = (string) $action;
1338 $contexts = $controller->$contextKey;
1339 $actionContexts = $contexts[$action];
1340 $contexts = (array) $context;
1341 foreach ($contexts as $context) {
1342 $index = array_search($context, $actionContexts);
1343 if (false !== $index) {
1344 unset($controller->{$contextKey}[$action][$index]);
1345 }
1346 }
1347 return true;
1348 }
1349 return false;
1350 }
1351
1352 /**
1353 * Clear all contexts for a given controller action or all actions
1354 *
1355 * @param string $action
1356 * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface
1357 */
1358 public function clearActionContexts($action = null)
1359 {
1360 $controller = $this->getActionController();
1361 $contextKey = $this->_contextKey;
1362
1363 if (!isset($controller->$contextKey) || empty($controller->$contextKey)) {
1364 return $this;
1365 }
1366
1367 if (null === $action) {
1368 $controller->$contextKey = array();
1369 return $this;
1370 }
1371
1372 $action = (string) $action;
1373 if (isset($controller->{$contextKey}[$action])) {
1374 unset($controller->{$contextKey}[$action]);
1375 }
1376
1377 return $this;
1378 }
1379
1380 /**
1381 * Retrieve ViewRenderer
1382 *
1383 * @return Zend_Controller_Action_Helper_ViewRenderer Provides a fluent interface
1384 */
1385 protected function _getViewRenderer()
1386 {
1387 if (null === $this->_viewRenderer) {
1388 $this->_viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer');
1389 }
1390
1391 return $this->_viewRenderer;
1392 }
1393}
1394