Das Beispiel in diesem Artikel beschreibt die Basisklasse Zend_Controller_Action von Aktionen im Zend Framework-Tutorial. Teilen Sie es wie folgt mit allen:
Implementierung von Zend_Controller_Action
Der Aktionscontroller von Zend Framework muss Zend_Controller_Action erben. Bitte beachten Sie Folgendes Code für Details:
Zend_Controller_Action_Interface
<?php interface Zend_Controller_Action_Interface { /** * Class constructor * * The request and response objects should be registered with the * controller, as should be any additional optional arguments; these will be * available via {@link getRequest()}, {@link getResponse()}, and * {@link getInvokeArgs()}, respectively. * * When overriding the constructor, please consider this usage as a best * practice and ensure that each is registered appropriately; the easiest * way to do so is to simply call parent::__construct($request, $response, * $invokeArgs). * * After the request, response, and invokeArgs are set, the * {@link $_helper helper broker} is initialized. * * Finally, {@link init()} is called as the final action of * instantiation, and may be safely overridden to perform initialization * tasks; as a general rule, override {@link init()} instead of the * constructor to customize an action controller's instantiation. * * @param Zend_Controller_Request_Abstract $request * @param Zend_Controller_Response_Abstract $response * @param array $invokeArgs Any additional invocation arguments * @return void */ public function __construct(Zend_Controller_Request_Abstract $request, Zend_Controller_Response_Abstract $response, array $invokeArgs = array()); /** * Dispatch the requested action * * @param string $action Method name of action * @return void */ public function dispatch($action); }
Zend_Controller_Action
<?php require_once 'Zend/Controller/Action/HelperBroker.php'; require_once 'Zend/Controller/Action/Interface.php'; require_once 'Zend/Controller/Front.php'; abstract class Zend_Controller_Action implements Zend_Controller_Action_Interface { protected $_classMethods; protected $_delimiters; protected $_invokeArgs = array(); protected $_frontController; protected $_request = null; protected $_response = null; public $viewSuffix = 'phtml'; public $view; protected $_helper = null; public function __construct(Zend_Controller_Request_Abstract $request, Zend_Controller_Response_Abstract $response, array $invokeArgs = array()) { $this->setRequest($request) ->setResponse($response) ->_setInvokeArgs($invokeArgs); $this->_helper = new Zend_Controller_Action_HelperBroker($this); $this->init(); } public function init() { } public function initView() { if (!$this->getInvokeArg('noViewRenderer') && $this->_helper->hasHelper('viewRenderer')) { return $this->view; } require_once 'Zend/View/Interface.php'; if (isset($this->view) && ($this->view instanceof Zend_View_Interface)) { return $this->view; } $request = $this->getRequest(); $module = $request->getModuleName(); $dirs = $this->getFrontController()->getControllerDirectory(); if (empty($module) || !isset($dirs[$module])) { $module = $this->getFrontController()->getDispatcher()->getDefaultModule(); } $baseDir = dirname($dirs[$module]) . DIRECTORY_SEPARATOR . 'views'; if (!file_exists($baseDir) || !is_dir($baseDir)) { require_once 'Zend/Controller/Exception.php'; throw new Zend_Controller_Exception('Missing base view directory ("' . $baseDir . '")'); } require_once 'Zend/View.php'; $this->view = new Zend_View(array('basePath' => $baseDir)); return $this->view; } public function render($action = null, $name = null, $noController = false) { if (!$this->getInvokeArg('noViewRenderer') && $this->_helper->hasHelper('viewRenderer')) { return $this->_helper->viewRenderer->render($action, $name, $noController); } $view = $this->initView(); $script = $this->getViewScript($action, $noController); $this->getResponse()->appendBody( $view->render($script), $name ); } public function renderScript($script, $name = null) { if (!$this->getInvokeArg('noViewRenderer') && $this->_helper->hasHelper('viewRenderer')) { return $this->_helper->viewRenderer->renderScript($script, $name); } $view = $this->initView(); $this->getResponse()->appendBody( $view->render($script), $name ); } public function getViewScript($action = null, $noController = null) { if (!$this->getInvokeArg('noViewRenderer') && $this->_helper->hasHelper('viewRenderer')) { $viewRenderer = $this->_helper->getHelper('viewRenderer'); if (null !== $noController) { $viewRenderer->setNoController($noController); } return $viewRenderer->getViewScript($action); } $request = $this->getRequest(); if (null === $action) { $action = $request->getActionName(); } elseif (!is_string($action)) { require_once 'Zend/Controller/Exception.php'; throw new Zend_Controller_Exception('Invalid action specifier for view render'); } if (null === $this->_delimiters) { $dispatcher = Zend_Controller_Front::getInstance()->getDispatcher(); $wordDelimiters = $dispatcher->getWordDelimiter(); $pathDelimiters = $dispatcher->getPathDelimiter(); $this->_delimiters = array_unique(array_merge($wordDelimiters, (array) $pathDelimiters)); } $action = str_replace($this->_delimiters, '-', $action); $script = $action . '.' . $this->viewSuffix; if (!$noController) { $controller = $request->getControllerName(); $controller = str_replace($this->_delimiters, '-', $controller); $script = $controller . DIRECTORY_SEPARATOR . $script; } return $script; } public function getRequest() { return $this->_request; } public function setRequest(Zend_Controller_Request_Abstract $request) { $this->_request = $request; return $this; } public function getResponse() { return $this->_response; } public function setResponse(Zend_Controller_Response_Abstract $response) { $this->_response = $response; return $this; } protected function _setInvokeArgs(array $args = array()) { $this->_invokeArgs = $args; return $this; } public function getInvokeArgs() { return $this->_invokeArgs; } public function getInvokeArg($key) { if (isset($this->_invokeArgs[$key])) { return $this->_invokeArgs[$key]; } return null; } public function getHelper($helperName) { return $this->_helper->{$helperName}; } public function getHelperCopy($helperName) { return clone $this->_helper->{$helperName}; } public function setFrontController(Zend_Controller_Front $front) { $this->_frontController = $front; return $this; } public function getFrontController() { // Used cache version if found if (null !== $this->_frontController) { return $this->_frontController; } // Grab singleton instance, if class has been loaded if (class_exists('Zend_Controller_Front')) { $this->_frontController = Zend_Controller_Front::getInstance(); return $this->_frontController; } // Throw exception in all other cases require_once 'Zend/Controller/Exception.php'; throw new Zend_Controller_Exception('Front controller class has not been loaded'); } public function preDispatch() { } public function postDispatch() { } public function __call($methodName, $args) { require_once 'Zend/Controller/Action/Exception.php'; if ('Action' == substr($methodName, -6)) { $action = substr($methodName, 0, strlen($methodName) - 6); throw new Zend_Controller_Action_Exception(sprintf('Action "%s" does not exist and was not trapped in __call()', $action), 404); } throw new Zend_Controller_Action_Exception(sprintf('Method "%s" does not exist and was not trapped in __call()', $methodName), 500); } public function dispatch($action) { // Notify helpers of action preDispatch state $this->_helper->notifyPreDispatch(); $this->preDispatch(); if ($this->getRequest()->isDispatched()) { if (null === $this->_classMethods) { $this->_classMethods = get_class_methods($this); } // If pre-dispatch hooks introduced a redirect then stop dispatch // @see ZF-7496 if (!($this->getResponse()->isRedirect())) { // preDispatch() didn't change the action, so we can continue if ($this->getInvokeArg('useCaseSensitiveActions') || in_array($action, $this->_classMethods)) { if ($this->getInvokeArg('useCaseSensitiveActions')) { trigger_error('Using case sensitive actions without word separators is deprecated; please do not rely on this "feature"'); } $this->$action(); } else { $this->__call($action, array()); } } $this->postDispatch(); } // whats actually important here is that this action controller is // shutting down, regardless of dispatching; notify the helpers of this // state $this->_helper->notifyPostDispatch(); } public function run(Zend_Controller_Request_Abstract $request = null, Zend_Controller_Response_Abstract $response = null) { if (null !== $request) { $this->setRequest($request); } else { $request = $this->getRequest(); } if (null !== $response) { $this->setResponse($response); } $action = $request->getActionName(); if (empty($action)) { $action = 'index'; } $action = $action . 'Action'; $request->setDispatched(true); $this->dispatch($action); return $this->getResponse(); } protected function _getParam($paramName, $default = null) { $value = $this->getRequest()->getParam($paramName); if ((null === $value || '' === $value) && (null !== $default)) { $value = $default; } return $value; } protected function _setParam($paramName, $value) { $this->getRequest()->setParam($paramName, $value); return $this; } protected function _hasParam($paramName) { return null !== $this->getRequest()->getParam($paramName); } protected function _getAllParams() { return $this->getRequest()->getParams(); } final protected function _forward($action, $controller = null, $module = null, array $params = null) { $request = $this->getRequest(); if (null !== $params) { $request->setParams($params); } if (null !== $controller) { $request->setControllerName($controller); // Module should only be reset if controller has been specified if (null !== $module) { $request->setModuleName($module); } } $request->setActionName($action) ->setDispatched(false); } protected function _redirect($url, array $options = array()) { $this->_helper->redirector->gotoUrl($url, $options); } }
Zend_Controller_Action bietet die Renderfunktion von Aktionen und Ansichten sowie die Registrierung von Anforderungs- und Antwortobjekten, allgemein Helfer usw.
Gemeinsame Methoden von Aktionscontrollern
Die häufig verwendeten Methoden und Attribute in Aktionscontrollern sind wie folgt:
$this->_helper führt hauptsächlich die zugehörigen Vorgänge des Assistenten aus , zum Beispiel:
// 只是局部控制器;当初始化加载时,对这个控制器的所有动作有效: $this->_helper->viewRenderer->setNoRender(true); // 全局: $this->_helper->removeHelper('viewRenderer'); // 也是全局,但需要和本地版本协作,以便繁殖这个控制器: Zend_Controller_Front::getInstance()->setParam('noViewRenderer', true);
Sie können das Rendern (Rendering) für eine unabhängige Ansicht einfach deaktivieren, indem Sie das noRender-Flag des ViewRenderers setzen:
class FooController extends Zend_Controller_Action { public function barAction() { // disable autorendering for this action only: $this->_helper->viewRenderer->setNoRender(); } }
Der Hauptgrund für die Deaktivierung von ViewRenderer ist, wenn Sie Sie benötigen das Ansichtsobjekt nicht oder wenn Sie es nicht über ein Ansichtsskript analysieren (z. B. wenn Sie einen Aktionscontroller verwenden, um ein Webdienstprotokoll wie SOAP, XML-RPC oder REST bereitzustellen). In den meisten Fällen müssen Sie ViewRenderer nicht global deaktivieren, sondern können es nur selektiv in einzelnen Controllern oder Aktionen deaktivieren.
Verwandte Operationen für Anforderungsobjekte und Antwortobjekte
Unzählige Objekte und Variablen sind beim Objekt registriert und jedes verfügt über Zugriffsmethoden.
Anforderungsobjekt: getRequest() kann zum Lesen des aufrufenden Aktionsanforderungsobjekts verwendet werden.
Antwortobjekt: getResponse() kann zum Lesen des Antwortobjekts verwendet werden, das die endgültige Antwort sammelt. Einige typische Aufrufe sehen so aus:
$this->getResponse()->setHeader('Content-Type', 'text/xml'); $this->getResponse()->appendBody($content);
Aufrufparameter: Front-End-Controller können Parameter an Router, Dispatcher und Aktionscontroller übergeben. Um diese Parameter zu lesen, verwenden Sie getInvokeArg($key); alternativ können Sie getInvokeArgs() verwenden, um die gesamte Parameterliste zu lesen.
Anforderungsparameter: Die Anforderungsparameter des Anforderungsobjekts, z. B. alle _GET- oder _POST-Parameter oder Benutzerparameter, die in den Pfadinformationen der URL angegeben sind. Um diese Parameter zu lesen, verwenden Sie _getParam($key) oder _getAllParams(). Sie können _setParam() auch zum Festlegen von Anforderungsparametern verwenden; dies ist nützlich, wenn Sie an eine andere Aktion weiterleiten.
Verwenden Sie _hasParam($key), um zu testen, ob ein Parameter vorhanden ist (nützlich für logische Verzweigungen).
Hinweis: _getParam() kann einen optionalen zweiten Parameter annehmen, der einen Standardwert enthält, wenn er nicht leer ist. Verwenden Sie es, um Aufrufe von _hasParam() vor dem Lesen des Werts zu eliminieren:
// Use default value of 1 if id is not set $id = $this->_getParam('id', 1); // Instead of: if ($this->_hasParam('id') { $id = $this->_getParam('id'); } else { $id = 1; }
Ansichtsbezogene Operationen
Zend_Controller_Action bietet einen anfänglichen flexiblen Mechanismus für die Ansichtsvererbung. Es gibt zwei Methoden, um dies zu erreichen: initView() und render(); erstere lädt die öffentliche Eigenschaft „$view“ und letztere löst die Ansicht basierend auf der aktuell angeforderten Aktion auf, die die Verzeichnishierarchie verwendet, um den Skriptpfad zu bestimmen.
Ansichtsinitialisierung
initView() initialisiert das Ansichtsobjekt. Um das View-Objekt zu lesen, ruft render() initView() auf, aber es kann jederzeit initialisiert werden, es fügt die $view-Eigenschaft mit einem Zend_View-Objekt zusammen, aber jede Klasse, die Zend_View_Interface implementiert, kann verwendet werden. Wenn $view initialisiert wurde, werden einfach die Eigenschaften zurückgegeben.
Die Standardimplementierung verwendet die folgende hypothetische Verzeichnisstruktur:
applicationOrModule/
controllers/
IndexController.php
views/
scripts/
index /
,,,,,,,,,,,,,,,,,, und Filter). Verwenden Sie beim Bestimmen des Namens und Pfads des Ansichtsskripts zunächst „views/scripts/“ als Basispfad und fügen Sie dann das Verzeichnis hinzu, das nach dem Controller benannt ist, der dem Ansichtsskript entspricht.
Rendering-Ansicht
render() hat die folgende Signatur:
render()-Parsing-Ansichtsskript. Wenn keine Parameter übergeben werden, geht es davon aus, dass das angeforderte Skript [controller]/[action].phtml ist (.phtml ist der Wert des $viewSuffix-Attributs). Durch die Übergabe eines Werts für $action wird die Vorlage im Unterverzeichnis [controller] aufgelöst. Übergeben Sie zum Überschreiben mit [Controller] einen wahren Wert an $noController. Abschließend wird die Vorlage in das Antwortobjekt geparst. Wenn Sie ein im Antwortobjekt angegebenes benanntes Segment analysieren möchten, übergeben Sie einen Wert an $name. Hinweis: Da Controller- und Aktionsnamen Trennzeichen wie „_“, „.“ und „-“ enthalten können, normalisiert render() sie bei der Bestimmung des Ansichtsnamens Dispatcher-Wörter und Pfadtrennzeichen zur Normalisierung. Auf diese Weise analysiert eine Anfrage für /foo.bar/baz-bat das Skript foo-bar/baz-bat.phtml. Wenn die Aktionsmethode „camelCasing“ enthält, denken Sie daran, dass diese bei der Bestimmung des Dateinamens des Ansichtsskripts durch „-“ getrennte Wörter werden.string render(string $action = null, string $name = null, bool $noController = false);
Einige Beispiele:
Andere_forward($action, $controller = null, $module = null, array $params = null) :执行另外一个动作。如果在preDispatch()里调用,当前请求的动作将被跳过来支持新的动作。否则,在当前动作被处理之后,在_forward()请求的动作将被执行。
_redirect($url, array $options = array()):重定向到另外一个地方。这个方法用URL和一组可选的选项。缺省地,它执行HTTP 302 重定向。
选项可包括一个或多个下面这些:
exit:是否立即退出。如果被请求,它将干净地关闭任何打开的会话和执行重定向。
可以用setRedirectExit()访问器在控制器里全局地设置这个选项。
prependBase:是否预先考虑基础URL和URL提供的请求对象一起注册。
使用setRedirectPrependBase()访问器,在控制器里全局地设置这个选项。
code:在重定向时要用什么HTTP代码。缺省使用302;可以用从301到306之间的任何代码。
使用setRedirectCode()访问器,在控制器里全局地设置这个选项。
扩展自定义Zend_Controller_Action
为了创建动作控制器,设计上,Zend_Controller_Action 必须被继承。至少,需要定义控制器可能调用的动作方法。
除了为web应用程序创建有用的函数外,你可能发现在不同的控制器里重复同样的设置和实用方法;如果这样,创建一个继承(extends)Zend_Controller_Action 的基础类可能会解决问题。
Example #1 如何处理不存在的动作
如果控制器的请求包括一个未定义的动作方法,Zend_Controller_Action::__call()将被调用。__call()当然是PHP中用来重载方法的魔术方法。
缺省地,这个方法抛出一个Zend_Controller_Action_Exception 来表明在控制器里没有发现要求的方法。如果要求的方法以'Action'结尾,就假设一个动作被请求并且不存在;这样的错误导致带有代码为 404 的异常。所有其它方法导致带有代码为 500 的异常。这使你很容易地在错误句柄里区分是页面没有发现还是程序错误。
如果想执行其它操作,你应该重写这个函数。例如,如果你想显示错误信息,可以象下面这样来写:
class MyController extends Zend_Controller_Action { public function __call($method, $args) { if ('Action' == substr($method, -6)) { // If the action method was not found, render the error // template return $this->render('error'); } // all other methods throw an exception throw new Exception('Invalid method "' . $method . '" called', 500); } }
另外的可能性就是你可能想转发到缺省控制页面:
class MyController extends Zend_Controller_Action { public function indexAction() { $this->render(); } public function __call($method, $args) { if ('Action' == substr($method, -6)) { // If the action method was not found, forward to the // index action return $this->_forward('index'); } // all other methods throw an exception throw new Exception('Invalid method "' . $method . '" called', 500); } }
为了定制控制器,除了重写__call()以外,本章前面说涉及的初始化、实用程序、访问器、视图和派遣钩子等方法都可以被重写。作为例子,如果把视图对象保存到注册表里,你可能想用象下面的代码来修改initView():
abstract class My_Base_Controller extends Zend_Controller_Action { public function initView() { if (null === $this->view) { if (Zend_Registry::isRegistered('view')) { $this->view = Zend_Registry::get('view'); } else { $this->view = new Zend_View(); $this->view->setBasePath(dirname(__FILE__) . '/../views'); } } return $this->view; } }
希望本文所述对大家PHP程序设计有所帮助。
更多Zend Framework教程之动作的基类Zend_Controller_Action详解相关文章请关注PHP中文网!