PageRenderTime 32ms CodeModel.GetById 19ms app.highlight 8ms RepoModel.GetById 1ms app.codeStats 0ms

/library/Zend/Controller/Action.php

https://bitbucket.org/rtsukui/jelly2
PHP | 688 lines | 258 code | 70 blank | 360 comment | 39 complexity | 5d62c2166b19f15628b059b1e1cbbc7f MD5 | raw file
  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 * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
 18 * @license    http://framework.zend.com/license/new-bsd     New BSD License
 19 * @version    $Id: Action.php 23775 2011-03-01 17:25:24Z ralph $
 20 */
 21
 22/**
 23 * @see Zend_Controller_Action_HelperBroker
 24 */
 25require_once 'Zend/Controller/Action/HelperBroker.php';
 26
 27/**
 28 * @see Zend_Controller_Action_Interface
 29 */
 30require_once 'Zend/Controller/Action/Interface.php';
 31
 32/**
 33 * @see Zend_Controller_Front
 34 */
 35require_once 'Zend/Controller/Front.php';
 36
 37/**
 38 * @category   Zend
 39 * @package    Zend_Controller
 40 * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
 41 * @license    http://framework.zend.com/license/new-bsd     New BSD License
 42 */
 43abstract class Zend_Controller_Action implements Zend_Controller_Action_Interface
 44{
 45    /**
 46     * @var array of existing class methods
 47     */
 48    protected $_classMethods;
 49
 50    /**
 51     * Word delimiters (used for normalizing view script paths)
 52     * @var array
 53     */
 54    protected $_delimiters;
 55
 56    /**
 57     * Array of arguments provided to the constructor, minus the
 58     * {@link $_request Request object}.
 59     * @var array
 60     */
 61    protected $_invokeArgs = array();
 62
 63    /**
 64     * Front controller instance
 65     * @var Zend_Controller_Front
 66     */
 67    protected $_frontController;
 68
 69    /**
 70     * Zend_Controller_Request_Abstract object wrapping the request environment
 71     * @var Zend_Controller_Request_Abstract
 72     */
 73    protected $_request = null;
 74
 75    /**
 76     * Zend_Controller_Response_Abstract object wrapping the response
 77     * @var Zend_Controller_Response_Abstract
 78     */
 79    protected $_response = null;
 80
 81    /**
 82     * View script suffix; defaults to 'phtml'
 83     * @see {render()}
 84     * @var string
 85     */
 86    public $viewSuffix = 'phtml';
 87
 88    /**
 89     * View object
 90     * @var Zend_View_Interface
 91     */
 92    public $view;
 93
 94    /**
 95     * Helper Broker to assist in routing help requests to the proper object
 96     *
 97     * @var Zend_Controller_Action_HelperBroker
 98     */
 99    protected $_helper = null;
100
101    /**
102     * Class constructor
103     *
104     * The request and response objects should be registered with the
105     * controller, as should be any additional optional arguments; these will be
106     * available via {@link getRequest()}, {@link getResponse()}, and
107     * {@link getInvokeArgs()}, respectively.
108     *
109     * When overriding the constructor, please consider this usage as a best
110     * practice and ensure that each is registered appropriately; the easiest
111     * way to do so is to simply call parent::__construct($request, $response,
112     * $invokeArgs).
113     *
114     * After the request, response, and invokeArgs are set, the
115     * {@link $_helper helper broker} is initialized.
116     *
117     * Finally, {@link init()} is called as the final action of
118     * instantiation, and may be safely overridden to perform initialization
119     * tasks; as a general rule, override {@link init()} instead of the
120     * constructor to customize an action controller's instantiation.
121     *
122     * @param Zend_Controller_Request_Abstract $request
123     * @param Zend_Controller_Response_Abstract $response
124     * @param array $invokeArgs Any additional invocation arguments
125     * @return void
126     */
127    public function __construct(Zend_Controller_Request_Abstract $request, Zend_Controller_Response_Abstract $response, array $invokeArgs = array())
128    {
129        $this->setRequest($request)
130             ->setResponse($response)
131             ->_setInvokeArgs($invokeArgs);
132        $this->_helper = new Zend_Controller_Action_HelperBroker($this);
133        $this->init();
134    }
135
136    /**
137     * Initialize object
138     *
139     * Called from {@link __construct()} as final step of object instantiation.
140     *
141     * @return void
142     */
143    public function init()
144    {
145    }
146
147    /**
148     * Initialize View object
149     *
150     * Initializes {@link $view} if not otherwise a Zend_View_Interface.
151     *
152     * If {@link $view} is not otherwise set, instantiates a new Zend_View
153     * object, using the 'views' subdirectory at the same level as the
154     * controller directory for the current module as the base directory.
155     * It uses this to set the following:
156     * - script path = views/scripts/
157     * - helper path = views/helpers/
158     * - filter path = views/filters/
159     *
160     * @return Zend_View_Interface
161     * @throws Zend_Controller_Exception if base view directory does not exist
162     */
163    public function initView()
164    {
165        if (!$this->getInvokeArg('noViewRenderer') && $this->_helper->hasHelper('viewRenderer')) {
166            return $this->view;
167        }
168
169        require_once 'Zend/View/Interface.php';
170        if (isset($this->view) && ($this->view instanceof Zend_View_Interface)) {
171            return $this->view;
172        }
173
174        $request = $this->getRequest();
175        $module  = $request->getModuleName();
176        $dirs    = $this->getFrontController()->getControllerDirectory();
177        if (empty($module) || !isset($dirs[$module])) {
178            $module = $this->getFrontController()->getDispatcher()->getDefaultModule();
179        }
180        $baseDir = dirname($dirs[$module]) . DIRECTORY_SEPARATOR . 'views';
181        if (!file_exists($baseDir) || !is_dir($baseDir)) {
182            require_once 'Zend/Controller/Exception.php';
183            throw new Zend_Controller_Exception('Missing base view directory ("' . $baseDir . '")');
184        }
185
186        require_once 'Zend/View.php';
187        $this->view = new Zend_View(array('basePath' => $baseDir));
188
189        return $this->view;
190    }
191
192    /**
193     * Render a view
194     *
195     * Renders a view. By default, views are found in the view script path as
196     * <controller>/<action>.phtml. You may change the script suffix by
197     * resetting {@link $viewSuffix}. You may omit the controller directory
198     * prefix by specifying boolean true for $noController.
199     *
200     * By default, the rendered contents are appended to the response. You may
201     * specify the named body content segment to set by specifying a $name.
202     *
203     * @see Zend_Controller_Response_Abstract::appendBody()
204     * @param  string|null $action Defaults to action registered in request object
205     * @param  string|null $name Response object named path segment to use; defaults to null
206     * @param  bool $noController  Defaults to false; i.e. use controller name as subdir in which to search for view script
207     * @return void
208     */
209    public function render($action = null, $name = null, $noController = false)
210    {
211        if (!$this->getInvokeArg('noViewRenderer') && $this->_helper->hasHelper('viewRenderer')) {
212            return $this->_helper->viewRenderer->render($action, $name, $noController);
213        }
214
215        $view   = $this->initView();
216        $script = $this->getViewScript($action, $noController);
217
218        $this->getResponse()->appendBody(
219            $view->render($script),
220            $name
221        );
222    }
223
224    /**
225     * Render a given view script
226     *
227     * Similar to {@link render()}, this method renders a view script. Unlike render(),
228     * however, it does not autodetermine the view script via {@link getViewScript()},
229     * but instead renders the script passed to it. Use this if you know the
230     * exact view script name and path you wish to use, or if using paths that do not
231     * conform to the spec defined with getViewScript().
232     *
233     * By default, the rendered contents are appended to the response. You may
234     * specify the named body content segment to set by specifying a $name.
235     *
236     * @param  string $script
237     * @param  string $name
238     * @return void
239     */
240    public function renderScript($script, $name = null)
241    {
242        if (!$this->getInvokeArg('noViewRenderer') && $this->_helper->hasHelper('viewRenderer')) {
243            return $this->_helper->viewRenderer->renderScript($script, $name);
244        }
245
246        $view = $this->initView();
247        $this->getResponse()->appendBody(
248            $view->render($script),
249            $name
250        );
251    }
252
253    /**
254     * Construct view script path
255     *
256     * Used by render() to determine the path to the view script.
257     *
258     * @param  string $action Defaults to action registered in request object
259     * @param  bool $noController  Defaults to false; i.e. use controller name as subdir in which to search for view script
260     * @return string
261     * @throws Zend_Controller_Exception with bad $action
262     */
263    public function getViewScript($action = null, $noController = null)
264    {
265        if (!$this->getInvokeArg('noViewRenderer') && $this->_helper->hasHelper('viewRenderer')) {
266            $viewRenderer = $this->_helper->getHelper('viewRenderer');
267            if (null !== $noController) {
268                $viewRenderer->setNoController($noController);
269            }
270            return $viewRenderer->getViewScript($action);
271        }
272
273        $request = $this->getRequest();
274        if (null === $action) {
275            $action = $request->getActionName();
276        } elseif (!is_string($action)) {
277            require_once 'Zend/Controller/Exception.php';
278            throw new Zend_Controller_Exception('Invalid action specifier for view render');
279        }
280
281        if (null === $this->_delimiters) {
282            $dispatcher = Zend_Controller_Front::getInstance()->getDispatcher();
283            $wordDelimiters = $dispatcher->getWordDelimiter();
284            $pathDelimiters = $dispatcher->getPathDelimiter();
285            $this->_delimiters = array_unique(array_merge($wordDelimiters, (array) $pathDelimiters));
286        }
287
288        $action = str_replace($this->_delimiters, '-', $action);
289        $script = $action . '.' . $this->viewSuffix;
290
291        if (!$noController) {
292            $controller = $request->getControllerName();
293            $controller = str_replace($this->_delimiters, '-', $controller);
294            $script = $controller . DIRECTORY_SEPARATOR . $script;
295        }
296
297        return $script;
298    }
299
300    /**
301     * Return the Request object
302     *
303     * @return Zend_Controller_Request_Abstract
304     */
305    public function getRequest()
306    {
307        return $this->_request;
308    }
309
310    /**
311     * Set the Request object
312     *
313     * @param Zend_Controller_Request_Abstract $request
314     * @return Zend_Controller_Action
315     */
316    public function setRequest(Zend_Controller_Request_Abstract $request)
317    {
318        $this->_request = $request;
319        return $this;
320    }
321
322    /**
323     * Return the Response object
324     *
325     * @return Zend_Controller_Response_Abstract
326     */
327    public function getResponse()
328    {
329        return $this->_response;
330    }
331
332    /**
333     * Set the Response object
334     *
335     * @param Zend_Controller_Response_Abstract $response
336     * @return Zend_Controller_Action
337     */
338    public function setResponse(Zend_Controller_Response_Abstract $response)
339    {
340        $this->_response = $response;
341        return $this;
342    }
343
344    /**
345     * Set invocation arguments
346     *
347     * @param array $args
348     * @return Zend_Controller_Action
349     */
350    protected function _setInvokeArgs(array $args = array())
351    {
352        $this->_invokeArgs = $args;
353        return $this;
354    }
355
356    /**
357     * Return the array of constructor arguments (minus the Request object)
358     *
359     * @return array
360     */
361    public function getInvokeArgs()
362    {
363        return $this->_invokeArgs;
364    }
365
366    /**
367     * Return a single invocation argument
368     *
369     * @param string $key
370     * @return mixed
371     */
372    public function getInvokeArg($key)
373    {
374        if (isset($this->_invokeArgs[$key])) {
375            return $this->_invokeArgs[$key];
376        }
377
378        return null;
379    }
380
381    /**
382     * Get a helper by name
383     *
384     * @param  string $helperName
385     * @return Zend_Controller_Action_Helper_Abstract
386     */
387    public function getHelper($helperName)
388    {
389        return $this->_helper->{$helperName};
390    }
391
392    /**
393     * Get a clone of a helper by name
394     *
395     * @param  string $helperName
396     * @return Zend_Controller_Action_Helper_Abstract
397     */
398    public function getHelperCopy($helperName)
399    {
400        return clone $this->_helper->{$helperName};
401    }
402
403    /**
404     * Set the front controller instance
405     *
406     * @param Zend_Controller_Front $front
407     * @return Zend_Controller_Action
408     */
409    public function setFrontController(Zend_Controller_Front $front)
410    {
411        $this->_frontController = $front;
412        return $this;
413    }
414
415    /**
416     * Retrieve Front Controller
417     *
418     * @return Zend_Controller_Front
419     */
420    public function getFrontController()
421    {
422        // Used cache version if found
423        if (null !== $this->_frontController) {
424            return $this->_frontController;
425        }
426
427        // Grab singleton instance, if class has been loaded
428        if (class_exists('Zend_Controller_Front')) {
429            $this->_frontController = Zend_Controller_Front::getInstance();
430            return $this->_frontController;
431        }
432
433        // Throw exception in all other cases
434        require_once 'Zend/Controller/Exception.php';
435        throw new Zend_Controller_Exception('Front controller class has not been loaded');
436    }
437
438    /**
439     * Pre-dispatch routines
440     *
441     * Called before action method. If using class with
442     * {@link Zend_Controller_Front}, it may modify the
443     * {@link $_request Request object} and reset its dispatched flag in order
444     * to skip processing the current action.
445     *
446     * @return void
447     */
448    public function preDispatch()
449    {
450    }
451
452    /**
453     * Post-dispatch routines
454     *
455     * Called after action method execution. If using class with
456     * {@link Zend_Controller_Front}, it may modify the
457     * {@link $_request Request object} and reset its dispatched flag in order
458     * to process an additional action.
459     *
460     * Common usages for postDispatch() include rendering content in a sitewide
461     * template, link url correction, setting headers, etc.
462     *
463     * @return void
464     */
465    public function postDispatch()
466    {
467    }
468
469    /**
470     * Proxy for undefined methods.  Default behavior is to throw an
471     * exception on undefined methods, however this function can be
472     * overridden to implement magic (dynamic) actions, or provide run-time
473     * dispatching.
474     *
475     * @param  string $methodName
476     * @param  array $args
477     * @return void
478     * @throws Zend_Controller_Action_Exception
479     */
480    public function __call($methodName, $args)
481    {
482        require_once 'Zend/Controller/Action/Exception.php';
483        if ('Action' == substr($methodName, -6)) {
484            $action = substr($methodName, 0, strlen($methodName) - 6);
485            throw new Zend_Controller_Action_Exception(sprintf('Action "%s" does not exist and was not trapped in __call()', $action), 404);
486        }
487
488        throw new Zend_Controller_Action_Exception(sprintf('Method "%s" does not exist and was not trapped in __call()', $methodName), 500);
489    }
490
491    /**
492     * Dispatch the requested action
493     *
494     * @param string $action Method name of action
495     * @return void
496     */
497    public function dispatch($action)
498    {
499        // Notify helpers of action preDispatch state
500        $this->_helper->notifyPreDispatch();
501
502        $this->preDispatch();
503        if ($this->getRequest()->isDispatched()) {
504            if (null === $this->_classMethods) {
505                $this->_classMethods = get_class_methods($this);
506            }
507
508            // preDispatch() didn't change the action, so we can continue
509            if ($this->getInvokeArg('useCaseSensitiveActions') || in_array($action, $this->_classMethods)) {
510                if ($this->getInvokeArg('useCaseSensitiveActions')) {
511                    trigger_error('Using case sensitive actions without word separators is deprecated; please do not rely on this "feature"');
512                }
513                $this->$action();
514            } else {
515                $this->__call($action, array());
516            }
517            $this->postDispatch();
518        }
519
520        // whats actually important here is that this action controller is
521        // shutting down, regardless of dispatching; notify the helpers of this
522        // state
523        $this->_helper->notifyPostDispatch();
524    }
525
526    /**
527     * Call the action specified in the request object, and return a response
528     *
529     * Not used in the Action Controller implementation, but left for usage in
530     * Page Controller implementations. Dispatches a method based on the
531     * request.
532     *
533     * Returns a Zend_Controller_Response_Abstract object, instantiating one
534     * prior to execution if none exists in the controller.
535     *
536     * {@link preDispatch()} is called prior to the action,
537     * {@link postDispatch()} is called following it.
538     *
539     * @param null|Zend_Controller_Request_Abstract $request Optional request
540     * object to use
541     * @param null|Zend_Controller_Response_Abstract $response Optional response
542     * object to use
543     * @return Zend_Controller_Response_Abstract
544     */
545    public function run(Zend_Controller_Request_Abstract $request = null, Zend_Controller_Response_Abstract $response = null)
546    {
547        if (null !== $request) {
548            $this->setRequest($request);
549        } else {
550            $request = $this->getRequest();
551        }
552
553        if (null !== $response) {
554            $this->setResponse($response);
555        }
556
557        $action = $request->getActionName();
558        if (empty($action)) {
559            $action = 'index';
560        }
561        $action = $action . 'Action';
562
563        $request->setDispatched(true);
564        $this->dispatch($action);
565
566        return $this->getResponse();
567    }
568
569    /**
570     * Gets a parameter from the {@link $_request Request object}.  If the
571     * parameter does not exist, NULL will be returned.
572     *
573     * If the parameter does not exist and $default is set, then
574     * $default will be returned instead of NULL.
575     *
576     * @param string $paramName
577     * @param mixed $default
578     * @return mixed
579     */
580    protected function _getParam($paramName, $default = null)
581    {
582        $value = $this->getRequest()->getParam($paramName);
583         if ((null === $value || '' === $value) && (null !== $default)) {
584            $value = $default;
585        }
586
587        return $value;
588    }
589
590    /**
591     * Set a parameter in the {@link $_request Request object}.
592     *
593     * @param string $paramName
594     * @param mixed $value
595     * @return Zend_Controller_Action
596     */
597    protected function _setParam($paramName, $value)
598    {
599        $this->getRequest()->setParam($paramName, $value);
600
601        return $this;
602    }
603
604    /**
605     * Determine whether a given parameter exists in the
606     * {@link $_request Request object}.
607     *
608     * @param string $paramName
609     * @return boolean
610     */
611    protected function _hasParam($paramName)
612    {
613        return null !== $this->getRequest()->getParam($paramName);
614    }
615
616    /**
617     * Return all parameters in the {@link $_request Request object}
618     * as an associative array.
619     *
620     * @return array
621     */
622    protected function _getAllParams()
623    {
624        return $this->getRequest()->getParams();
625    }
626
627
628    /**
629     * Forward to another controller/action.
630     *
631     * It is important to supply the unformatted names, i.e. "article"
632     * rather than "ArticleController".  The dispatcher will do the
633     * appropriate formatting when the request is received.
634     *
635     * If only an action name is provided, forwards to that action in this
636     * controller.
637     *
638     * If an action and controller are specified, forwards to that action and
639     * controller in this module.
640     *
641     * Specifying an action, controller, and module is the most specific way to
642     * forward.
643     *
644     * A fourth argument, $params, will be used to set the request parameters.
645     * If either the controller or module are unnecessary for forwarding,
646     * simply pass null values for them before specifying the parameters.
647     *
648     * @param string $action
649     * @param string $controller
650     * @param string $module
651     * @param array $params
652     * @return void
653     */
654    final protected function _forward($action, $controller = null, $module = null, array $params = null)
655    {
656        $request = $this->getRequest();
657
658        if (null !== $params) {
659            $request->setParams($params);
660        }
661
662        if (null !== $controller) {
663            $request->setControllerName($controller);
664
665            // Module should only be reset if controller has been specified
666            if (null !== $module) {
667                $request->setModuleName($module);
668            }
669        }
670
671        $request->setActionName($action)
672                ->setDispatched(false);
673    }
674
675    /**
676     * Redirect to another URL
677     *
678     * Proxies to {@link Zend_Controller_Action_Helper_Redirector::gotoUrl()}.
679     *
680     * @param string $url
681     * @param array $options Options to be used when redirecting
682     * @return void
683     */
684    protected function _redirect($url, array $options = array())
685    {
686        $this->_helper->redirector->gotoUrl($url, $options);
687    }
688}