>  기사  >  php教程  >  Zend Framework 튜토리얼 액션 기본 클래스 Zend_Controller_Action에 대한 자세한 설명

Zend Framework 튜토리얼 액션 기본 클래스 Zend_Controller_Action에 대한 자세한 설명

高洛峰
高洛峰원래의
2017-01-03 13:16:461250검색

이 문서의 예에서는 Zend Framework 튜토리얼에 있는 작업의 기본 클래스 Zend_Controller_Action을 설명합니다. 참고용으로 다음과 같이 공유하세요.

Zend_Controller_Action 구현

Zend Framework의 액션 컨트롤러는 Zend_Controller_Action을 상속해야 합니다. 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를 비활성화하는 주된 이유는 다음과 같습니다. 뷰 객체가 필요하지 않거나 뷰 스크립트를 통해 이를 구문 분석하지 않는 경우(예: 액션 컨트롤러를 사용하여 SOAP, XML-RPC 또는 REST와 같은 웹 서비스 프로토콜을 제공하는 경우) 대부분의 경우 ViewRenderer를 전체적으로 비활성화할 필요는 없으며 개별 컨트롤러나 작업에서 선택적으로 비활성화하면 됩니다.

요청 객체와 응답 객체에 대한 관련 작업

수많은 객체와 변수가 객체에 등록되며 각각 접근자 메서드를 갖습니다.

요청 객체: getRequest()를 사용하여 호출 작업 요청 객체를 읽을 수 있습니다.

응답 객체: 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()은 비어 있지 않은 경우 기본값을 포함하는 선택적 두 번째 매개변수를 취할 수 있습니다. 이를 사용하여 값을 읽기 전에 _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()는 전자는 $view 공용 속성을 느슨하게 로드하고 후자는 디렉터리 계층 구조를 사용하여 스크립트 경로를 결정하는 현재 요청된 작업을 기반으로 보기를 확인합니다.

뷰 초기화

initView()는 뷰 객체를 초기화합니다. 뷰 객체를 읽기 위해 render()는 initView()를 호출하지만 언제든지 초기화될 수 있습니다. 기본적으로 $view 속성을 Zend_View 객체와 결합하지만 Zend_View_Interface를 구현하는 모든 클래스를 사용할 수 있습니다. $view가 초기화된 경우 단순히 속성을 반환합니다.

기본 구현에서는 다음과 같은 가상 디렉터리 구조를 사용합니다.

applicationOrModule/
Controllers/
IndexController.php
views/
scripts/
index /
                                  index.phtml                                                                 ~                                                도우미/및 필터). 뷰 스크립트의 이름과 경로를 결정할 때 먼저 views/scripts/를 기본 경로로 사용한 후, 뷰 스크립트에 해당하는 컨트롤러 이름을 따서 디렉터리를 추가합니다.

렌더링 뷰

render()에는 다음과 같은 서명이 있습니다.

render() 구문 분석 뷰 스크립트. 매개변수가 전달되지 않으면 요청된 스크립트가 [controller]/[action].phtml(.phtml은 $viewSuffix 속성의 값)이라고 가정합니다. $action 값을 전달하면 [controller] 하위 디렉터리의 템플릿이 확인됩니다. [controller]로 재정의하려면 $noController에 참값을 전달하세요. 마지막으로 템플릿은 응답 개체로 구문 분석됩니다. 응답 개체에 지정된 명명된 세그먼트로 구문 분석하려면 값을 $name에 전달합니다.

참고: 컨트롤러 및 작업 이름에는 '_', '.' 및 '-'와 같은 구분 기호가 포함될 수 있으므로 render()는 내부적으로 뷰 이름을 결정할 때 이를 '-'로 정규화합니다. 정규화를 위한 디스패처의 단어 및 경로 구분 기호입니다. 이렇게 하면 /foo.bar/baz-bat에 대한 요청이 foo-bar/baz-bat.phtml 스크립트를 구문 분석합니다. 액션 메소드에 camelCasing이 포함되어 있으면 뷰 스크립트 파일 이름을 결정할 때 '-'로 구분된 단어가 된다는 점을 기억하세요.
string render(string $action = null,
       string $name = null,
       bool $noController = false);

몇 가지 예:

기타

_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으로 문의하세요.