ホームページ  >  記事  >  php教程  >  Zend Framework チュートリアルのアクション基本クラス Zend_Controller_Action の詳細な説明

Zend Framework チュートリアルのアクション基本クラス Zend_Controller_Action の詳細な説明

高洛峰
高洛峰オリジナル
2017-01-03 13:16:461293ブラウズ

この記事の例では、Zend Framework チュートリアルのアクションの基本クラス Zend_Controller_Action について説明します。参考として、次のようにみんなと共有してください:

Zend_Controller_Action

Zend Framework のアクション コントローラーの実装は、Zend_Controller_Action を継承する必要があります。詳細については、次のコードを参照してください:

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&#39;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 &#39;Zend/Controller/Action/HelperBroker.php&#39;;
require_once &#39;Zend/Controller/Action/Interface.php&#39;;
require_once &#39;Zend/Controller/Front.php&#39;;
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 = &#39;phtml&#39;;
  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(&#39;noViewRenderer&#39;) && $this->_helper->hasHelper(&#39;viewRenderer&#39;)) {
      return $this->view;
    }
    require_once &#39;Zend/View/Interface.php&#39;;
    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 . &#39;views&#39;;
    if (!file_exists($baseDir) || !is_dir($baseDir)) {
      require_once &#39;Zend/Controller/Exception.php&#39;;
      throw new Zend_Controller_Exception(&#39;Missing base view directory ("&#39; . $baseDir . &#39;")&#39;);
    }
    require_once &#39;Zend/View.php&#39;;
    $this->view = new Zend_View(array(&#39;basePath&#39; => $baseDir));
    return $this->view;
  }
  public function render($action = null, $name = null, $noController = false)
  {
    if (!$this->getInvokeArg(&#39;noViewRenderer&#39;) && $this->_helper->hasHelper(&#39;viewRenderer&#39;)) {
      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(&#39;noViewRenderer&#39;) && $this->_helper->hasHelper(&#39;viewRenderer&#39;)) {
      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(&#39;noViewRenderer&#39;) && $this->_helper->hasHelper(&#39;viewRenderer&#39;)) {
      $viewRenderer = $this->_helper->getHelper(&#39;viewRenderer&#39;);
      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 &#39;Zend/Controller/Exception.php&#39;;
      throw new Zend_Controller_Exception(&#39;Invalid action specifier for view render&#39;);
    }
    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, &#39;-&#39;, $action);
    $script = $action . &#39;.&#39; . $this->viewSuffix;
    if (!$noController) {
      $controller = $request->getControllerName();
      $controller = str_replace($this->_delimiters, &#39;-&#39;, $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(&#39;Zend_Controller_Front&#39;)) {
      $this->_frontController = Zend_Controller_Front::getInstance();
      return $this->_frontController;
    }
    // Throw exception in all other cases
    require_once &#39;Zend/Controller/Exception.php&#39;;
    throw new Zend_Controller_Exception(&#39;Front controller class has not been loaded&#39;);
  }
  public function preDispatch()
  {
  }
  public function postDispatch()
  {
  }
  public function __call($methodName, $args)
  {
    require_once &#39;Zend/Controller/Action/Exception.php&#39;;
    if (&#39;Action&#39; == substr($methodName, -6)) {
      $action = substr($methodName, 0, strlen($methodName) - 6);
      throw new Zend_Controller_Action_Exception(sprintf(&#39;Action "%s" does not exist and was not trapped in __call()&#39;, $action), 404);
    }
    throw new Zend_Controller_Action_Exception(sprintf(&#39;Method "%s" does not exist and was not trapped in __call()&#39;, $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&#39;t change the action, so we can continue
        if ($this->getInvokeArg(&#39;useCaseSensitiveActions&#39;) || in_array($action, $this->_classMethods)) {
          if ($this->getInvokeArg(&#39;useCaseSensitiveActions&#39;)) {
            trigger_error(&#39;Using case sensitive actions without word separators is deprecated; please do not rely on this "feature"&#39;);
          }
          $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 = &#39;index&#39;;
    }
    $action = $action . &#39;Action&#39;;
    $request->setDispatched(true);
    $this->dispatch($action);
    return $this->getResponse();
  }
  protected function _getParam($paramName, $default = null)
  {
    $value = $this->getRequest()->getParam($paramName);
     if ((null === $value || &#39;&#39; === $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 は、アクションとビューのレンダリング機能、登録されたリクエストとレスポンスのオブジェクト、共通ヘルパーなどを提供します。

アクション コントローラーの一般的なメソッド

アクション コントローラーで一般的に使用されるメソッドと属性は次のとおりです:

$this->_helper は主にアシスタント関連の操作を完了します。 例:

// 只是局部控制器;当初始化加载时,对这个控制器的所有动作有效:
$this->_helper->viewRenderer->setNoRender(true);
// 全局:
$this->_helper->removeHelper(&#39;viewRenderer&#39;);
 // 也是全局,但需要和本地版本协作,以便繁殖这个控制器:
Zend_Controller_Front::getInstance()->setParam(&#39;noViewRenderer&#39;, true);

ViewRenderer の noRender タグを設定することで、スタンドアロン ビューのレンダリングを無効にするだけです:

class FooController extends Zend_Controller_Action
{
  public function barAction()
  {
    // disable autorendering for this action only:
    $this->_helper->viewRenderer->setNoRender();
  }
}

ViewRenderer を無効にする主な理由は、ビュー オブジェクトが必要ない場合、またはビュー スクリプトを通じて Web サービス プロトコルを提供しない場合 (たとえば、 SOAP、XML-RPC、REST などの Web サイト サービス プロトコルを提供して解析するアクション コントローラー。ほとんどの場合、ViewRenderer をグローバルに無効にする必要はなく、個々のコントローラーまたはアクションで選択的に無効にするだけです。

リクエストオブジェクトとレスポンスオブジェクトに対する関連操作

オブジェクトには無数のオブジェクトと変数が登録されており、それぞれにアクセサメソッドがあります。

Request オブジェクト: getRequest() を使用して、呼び出し元のアクション要求オブジェクトを読み取ることができます。

Response オブジェクト: getResponse() を使用して、最終応答を収集する応答オブジェクトを読み取ることができます。いくつかの典型的な呼び出しは次のようになります:

$this->getResponse()->setHeader(&#39;Content-Type&#39;, &#39;text/xml&#39;);
$this->getResponse()->appendBody($content);

呼び出しパラメーター: フロント コントローラーはルーター、ディスパッチャー、およびアクション コントローラーにパラメーターを渡すことがあります。これらのパラメータを読み取るには、getInvokeArg($key) を使用します。あるいは、getInvokeArgs() を使用してパラメータ リスト全体を読み取ります。

リクエスト パラメータ: _GET パラメータや _POST パラメータなどのリクエスト オブジェクトのリクエスト パラメータ、または URL のパス情報で指定されたユーザー パラメータ。これらのパラメータを読み取るには、_getParam($key) または _getAllParams() を使用します。 _setParam() を使用してリクエスト パラメータを設定することもできます。これは、別のアクションに転送するときに便利です。

_hasParam($key) を使用して、パラメーターが存在するかどうかをテストします (論理分岐に役立ちます)。

注: _getParam() はオプションの 2 番目のパラメーターを取ることができ、空でない場合はデフォルト値が含まれます。これを使用して、値を読み取る前に _hasParam() への呼び出しを排除します。

// Use default value of 1 if id is not set
$id = $this->_getParam(&#39;id&#39;, 1);
// Instead of:
if ($this->_hasParam(&#39;id&#39;) {
  $id = $this->_getParam(&#39;id&#39;);
} else {
  $id = 1;
}

ビュー関連操作

Zend_Controller_Action は、ビュー継承のための初期の柔軟なメカニズムを提供します。これを実現するには、initView() と render() の 2 つのメソッドがあります。前者は $view パブリック プロパティを緩やかに読み込み、後者は現在要求されているアクションに基づいてビューを解決し、ディレクトリ階層を使用してスクリプト パスを決定します。

ビューの初期化

initView() はビュー オブジェクトを初期化します。ビュー オブジェクトを読み取るために、render() は initView() を呼び出しますが、これはいつでも初期化できます。デフォルトでは $view プロパティが Zend_View オブジェクトでアセンブルされますが、Zend_View_Interface を実装する任意のクラスを使用できます。 $view が初期化されている場合は、単にプロパティを返します。

デフォルトの実装では、次の仮想ディレクトリ構造が使用されます:

applicationOrModule/
controllers/
IndexController.php
views/
scripts/ .phtml
helpers/
filters/

つまり、view スクリプトは次のように想定されます。これは、views/scripts/ サブディレクトリに配置され、views サブディレクトリには兄弟関数 (ヘルパーとフィルター) も含まれると想定されます。ビュー スクリプトの名前とパスを決定するときは、まず views/scripts/ をベース パスとして使用し、次にビュー スクリプトに対応するコントローラにちなんだ名前のディレクトリを追加します。

ビューのレンダリング

render() には次のシグネチャがあります:

string render(string $action = null,
       string $name = null,
       bool $noController = false);

render() はビュー スクリプトを解析します。パラメーターが渡されない場合、要求されたスクリプトは [controller]/[action].phtml (.phtml は $viewSuffix 属性の値) であると想定されます。 $action の値を渡すと、[controller] サブディレクトリ内のテンプレートが解決されます。 [controller] でオーバーライドするには、$noController に true 値を渡します。最後に、テンプレートは応答オブジェクトに解析されます。応答オブジェクトで指定された名前付きセグメントに解析したい場合は、値を $name に渡します。

注: コントローラー名とアクション名には「_」、「.」、「-」などの区切り文字が含まれる場合があるため、render() はビュー名を決定する際にそれらを内部的に「-」に正規化します。ディスパッチャーの単語とパスが使用されます。区切り文字は正規化に使用されます。このように、/foo.bar/baz-bat に対するリクエストはスクリプト foo-bar/baz-bat.phtml を解析します。アクション メソッドにキャメルケーシングが含まれる場合、ビュー スクリプト ファイル名を決定するときに、これが「-」で区切られた単語になることに注意してください。

いくつかの例:

class MyController extends Zend_Controller_Action
{
  public function fooAction()
  {
    // Renders my/foo.phtml
    $this->render();
    // Renders my/bar.phtml
    $this->render(&#39;bar&#39;);
    // Renders baz.phtml
    $this->render(&#39;baz&#39;, null, true);
    // Renders my/login.phtml to the &#39;form&#39; segment of the
    // response object
    $this->render(&#39;login&#39;, &#39;form&#39;);
    // Renders site.phtml to the &#39;page&#39; segment of the response
    // object; does not use the &#39;my/&#39; subirectory
    $this->render(&#39;site&#39;, &#39;page&#39;, true);
  }
  public function bazBatAction()
  {
    // Renders my/baz-bat.phtml
    $this->render();
  }
}

その他

_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 (&#39;Action&#39; == substr($method, -6)) {
      // If the action method was not found, render the error
      // template
      return $this->render(&#39;error&#39;);
    }
    // all other methods throw an exception
    throw new Exception(&#39;Invalid method "&#39;
              . $method
              . &#39;" called&#39;,
              500);
  }
}

另外的可能性就是你可能想转发到缺省控制页面:

class MyController extends Zend_Controller_Action
{
  public function indexAction()
  {
    $this->render();
  }
  public function __call($method, $args)
  {
    if (&#39;Action&#39; == substr($method, -6)) {
      // If the action method was not found, forward to the
      // index action
      return $this->_forward(&#39;index&#39;);
    }
    // all other methods throw an exception
    throw new Exception(&#39;Invalid method "&#39;
              . $method
              . &#39;" called&#39;,
              500);
  }
}

为了定制控制器,除了重写__call()以外,本章前面说涉及的初始化、实用程序、访问器、视图和派遣钩子等方法都可以被重写。作为例子,如果把视图对象保存到注册表里,你可能想用象下面的代码来修改initView():

abstract class My_Base_Controller extends Zend_Controller_Action
{
  public function initView()
  {
    if (null === $this->view) {
      if (Zend_Registry::isRegistered(&#39;view&#39;)) {
        $this->view = Zend_Registry::get(&#39;view&#39;);
      } else {
        $this->view = new Zend_View();
        $this->view->setBasePath(dirname(__FILE__) . &#39;/../views&#39;);
      }
    }
    return $this->view;
  }
}

希望本文所述对大家PHP程序设计有所帮助。

更多Zend Framework教程之动作的基类Zend_Controller_Action详解相关文章请关注PHP中文网!

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。