ホームページ バックエンド開発 PHPチュートリアル Zend Framework教程之路由功能Zend_Controller_Router详解_php实例

Zend Framework教程之路由功能Zend_Controller_Router详解_php实例

Jun 07, 2016 pm 05:09 PM
framework zend ルーティング機能

本文实例讲述了Zend Framework教程之路由功能Zend_Controller_Router用法。分享给大家供大家参考,具体如下:

Zend Framework的路由提供了两个主要功能路由和创建路由。

Zend_Controller_Router的Route类和相应Route目录下的类定义常见的路由操作

接口Zend_Controller_Router_Interface,类Zend_Controller_Router_Abstract和Zend_Controller_Router_Rewrite完成了基本的路由,创建路由,删除路由的功能。

└── Router
    ├── Abstract.php
    ├── Exception.php
    ├── Interface.php
    ├── Rewrite.php
    ├── Route
    │   ├── Abstract.php
    │   ├── Chain.php
    │   ├── Hostname.php
    │   ├── Interface.php
    │   ├── Module.php
    │   ├── Regex.php
    │   └── Static.php
    └── Route.php

Zend_Controller_Router路由功能的实现

Zend_Controller_Router_Interface

<&#63;php
interface Zend_Controller_Router_Interface
{
  /**
   * Processes a request and sets its controller and action. If
   * no route was possible, an exception is thrown.
   *
   * @param Zend_Controller_Request_Abstract
   * @throws Zend_Controller_Router_Exception
   * @return Zend_Controller_Request_Abstract|boolean
   */
  public function route(Zend_Controller_Request_Abstract $dispatcher);
  /**
   * Generates a URL path that can be used in URL creation, redirection, etc.
   *
   * May be passed user params to override ones from URI, Request or even defaults.
   * If passed parameter has a value of null, it's URL variable will be reset to
   * default.
   *
   * If null is passed as a route name assemble will use the current Route or 'default'
   * if current is not yet set.
   *
   * Reset is used to signal that all parameters should be reset to it's defaults.
   * Ignoring all URL specified values. User specified params still get precedence.
   *
   * Encode tells to url encode resulting path parts.
   *
   * @param array $userParams Options passed by a user used to override parameters
   * @param mixed $name The name of a Route to use
   * @param bool $reset Whether to reset to the route defaults ignoring URL params
   * @param bool $encode Tells to encode URL parts on output
   * @throws Zend_Controller_Router_Exception
   * @return string Resulting URL path
   */
  public function assemble($userParams, $name = null, $reset = false, $encode = true);
  /**
   * Retrieve Front Controller
   *
   * @return Zend_Controller_Front
   */
  public function getFrontController();
  /**
   * Set Front Controller
   *
   * @param Zend_Controller_Front $controller
   * @return Zend_Controller_Router_Interface
   */
  public function setFrontController(Zend_Controller_Front $controller);
  /**
   * Add or modify a parameter with which to instantiate any helper objects
   *
   * @param string $name
   * @param mixed $param
   * @return Zend_Controller_Router_Interface
   */
  public function setParam($name, $value);
  /**
   * Set an array of a parameters to pass to helper object constructors
   *
   * @param array $params
   * @return Zend_Controller_Router_Interface
   */
  public function setParams(array $params);
  /**
   * Retrieve a single parameter from the controller parameter stack
   *
   * @param string $name
   * @return mixed
   */
  public function getParam($name);
  /**
   * Retrieve the parameters to pass to helper object constructors
   *
   * @return array
   */
  public function getParams();
  /**
   * Clear the controller parameter stack
   *
   * By default, clears all parameters. If a parameter name is given, clears
   * only that parameter; if an array of parameter names is provided, clears
   * each.
   *
   * @param null|string|array single key or array of keys for params to clear
   * @return Zend_Controller_Router_Interface
   */
  public function clearParams($name = null);
}

ログイン後にコピー

Zend_Controller_Router_Abstract

<&#63;php
/** Zend_Controller_Router_Interface */
require_once 'Zend/Controller/Router/Interface.php';
abstract class Zend_Controller_Router_Abstract implements Zend_Controller_Router_Interface
{
  /**
   * URI delimiter
   */
  const URI_DELIMITER = '/';
  /**
   * Front controller instance
   * @var Zend_Controller_Front
   */
  protected $_frontController;
  /**
   * Array of invocation parameters to use when instantiating action
   * controllers
   * @var array
   */
  protected $_invokeParams = array();
  /**
   * Constructor
   *
   * @param array $params
   * @return void
   */
  public function __construct(array $params = array())
  {
    $this->setParams($params);
  }
  /**
   * Add or modify a parameter to use when instantiating an action controller
   *
   * @param string $name
   * @param mixed $value
   * @return Zend_Controller_Router
   */
  public function setParam($name, $value)
  {
    $name = (string) $name;
    $this->_invokeParams[$name] = $value;
    return $this;
  }
  /**
   * Set parameters to pass to action controller constructors
   *
   * @param array $params
   * @return Zend_Controller_Router
   */
  public function setParams(array $params)
  {
    $this->_invokeParams = array_merge($this->_invokeParams, $params);
    return $this;
  }
  /**
   * Retrieve a single parameter from the controller parameter stack
   *
   * @param string $name
   * @return mixed
   */
  public function getParam($name)
  {
    if(isset($this->_invokeParams[$name])) {
      return $this->_invokeParams[$name];
    }
    return null;
  }
  /**
   * Retrieve action controller instantiation parameters
   *
   * @return array
   */
  public function getParams()
  {
    return $this->_invokeParams;
  }
  /**
   * Clear the controller parameter stack
   *
   * By default, clears all parameters. If a parameter name is given, clears
   * only that parameter; if an array of parameter names is provided, clears
   * each.
   *
   * @param null|string|array single key or array of keys for params to clear
   * @return Zend_Controller_Router
   */
  public function clearParams($name = null)
  {
    if (null === $name) {
      $this->_invokeParams = array();
    } elseif (is_string($name) && isset($this->_invokeParams[$name])) {
      unset($this->_invokeParams[$name]);
    } elseif (is_array($name)) {
      foreach ($name as $key) {
        if (is_string($key) && isset($this->_invokeParams[$key])) {
          unset($this->_invokeParams[$key]);
        }
      }
    }
    return $this;
  }
  /**
   * Retrieve Front Controller
   *
   * @return Zend_Controller_Front
   */
  public function getFrontController()
  {
    // Used cache version if found
    if (null !== $this->_frontController) {
      return $this->_frontController;
    }
    require_once 'Zend/Controller/Front.php';
    $this->_frontController = Zend_Controller_Front::getInstance();
    return $this->_frontController;
  }
  /**
   * Set Front Controller
   *
   * @param Zend_Controller_Front $controller
   * @return Zend_Controller_Router_Interface
   */
  public function setFrontController(Zend_Controller_Front $controller)
  {
    $this->_frontController = $controller;
    return $this;
  }
}

ログイン後にコピー

Zend_Controller_Router_Rewrite

<&#63;php
/** Zend_Controller_Router_Abstract */
require_once 'Zend/Controller/Router/Abstract.php';
/** Zend_Controller_Router_Route */
require_once 'Zend/Controller/Router/Route.php';
class Zend_Controller_Router_Rewrite extends Zend_Controller_Router_Abstract
{
  /**
   * Whether or not to use default routes
   *
   * @var boolean
   */
  protected $_useDefaultRoutes = true;
  /**
   * Array of routes to match against
   *
   * @var array
   */
  protected $_routes = array();
  /**
   * Currently matched route
   *
   * @var Zend_Controller_Router_Route_Interface
   */
  protected $_currentRoute = null;
  /**
   * Global parameters given to all routes
   *
   * @var array
   */
  protected $_globalParams = array();
  /**
   * Separator to use with chain names
   *
   * @var string
   */
  protected $_chainNameSeparator = '-';
  /**
   * Determines if request parameters should be used as global parameters
   * inside this router.
   *
   * @var boolean
   */
  protected $_useCurrentParamsAsGlobal = false;
  /**
   * Add default routes which are used to mimic basic router behaviour
   *
   * @return Zend_Controller_Router_Rewrite
   */
  public function addDefaultRoutes()
  {
    if (!$this->hasRoute('default')) {
      $dispatcher = $this->getFrontController()->getDispatcher();
      $request = $this->getFrontController()->getRequest();
      require_once 'Zend/Controller/Router/Route/Module.php';
      $compat = new Zend_Controller_Router_Route_Module(array(), $dispatcher, $request);
      $this->_routes = array('default' => $compat) + $this->_routes;
    }
    return $this;
  }
  /**
   * Add route to the route chain
   *
   * If route contains method setRequest(), it is initialized with a request object
   *
   * @param string                 $name    Name of the route
   * @param Zend_Controller_Router_Route_Interface $route   Instance of the route
   * @return Zend_Controller_Router_Rewrite
   */
  public function addRoute($name, Zend_Controller_Router_Route_Interface $route)
  {
    if (method_exists($route, 'setRequest')) {
      $route->setRequest($this->getFrontController()->getRequest());
    }
    $this->_routes[$name] = $route;
    return $this;
  }
  /**
   * Add routes to the route chain
   *
   * @param array $routes Array of routes with names as keys and routes as values
   * @return Zend_Controller_Router_Rewrite
   */
  public function addRoutes($routes) {
    foreach ($routes as $name => $route) {
      $this->addRoute($name, $route);
    }
    return $this;
  }
  /**
   * Create routes out of Zend_Config configuration
   *
   * Example INI:
   * routes.archive.route = "archive/:year/*"
   * routes.archive.defaults.controller = archive
   * routes.archive.defaults.action = show
   * routes.archive.defaults.year = 2000
   * routes.archive.reqs.year = "\d+"
   *
   * routes.news.type = "Zend_Controller_Router_Route_Static"
   * routes.news.route = "news"
   * routes.news.defaults.controller = "news"
   * routes.news.defaults.action = "list"
   *
   * And finally after you have created a Zend_Config with above ini:
   * $router = new Zend_Controller_Router_Rewrite();
   * $router->addConfig($config, 'routes');
   *
   * @param Zend_Config $config Configuration object
   * @param string   $section Name of the config section containing route's definitions
   * @throws Zend_Controller_Router_Exception
   * @return Zend_Controller_Router_Rewrite
   */
  public function addConfig(Zend_Config $config, $section = null)
  {
    if ($section !== null) {
      if ($config->{$section} === null) {
        require_once 'Zend/Controller/Router/Exception.php';
        throw new Zend_Controller_Router_Exception("No route configuration in section '{$section}'");
      }
      $config = $config->{$section};
    }
    foreach ($config as $name => $info) {
      $route = $this->_getRouteFromConfig($info);
      if ($route instanceof Zend_Controller_Router_Route_Chain) {
        if (!isset($info->chain)) {
          require_once 'Zend/Controller/Router/Exception.php';
          throw new Zend_Controller_Router_Exception("No chain defined");
        }
        if ($info->chain instanceof Zend_Config) {
          $childRouteNames = $info->chain;
        } else {
          $childRouteNames = explode(',', $info->chain);
        }
        foreach ($childRouteNames as $childRouteName) {
          $childRoute = $this->getRoute(trim($childRouteName));
          $route->chain($childRoute);
        }
        $this->addRoute($name, $route);
      } elseif (isset($info->chains) && $info->chains instanceof Zend_Config) {
        $this->_addChainRoutesFromConfig($name, $route, $info->chains);
      } else {
        $this->addRoute($name, $route);
      }
    }
    return $this;
  }
  /**
   * Get a route frm a config instance
   *
   * @param Zend_Config $info
   * @return Zend_Controller_Router_Route_Interface
   */
  protected function _getRouteFromConfig(Zend_Config $info)
  {
    $class = (isset($info->type)) &#63; $info->type : 'Zend_Controller_Router_Route';
    if (!class_exists($class)) {
      require_once 'Zend/Loader.php';
      Zend_Loader::loadClass($class);
    }
    $route = call_user_func(array($class, 'getInstance'), $info);
    if (isset($info->abstract) && $info->abstract && method_exists($route, 'isAbstract')) {
      $route->isAbstract(true);
    }
    return $route;
  }
  /**
   * Add chain routes from a config route
   *
   * @param string                 $name
   * @param Zend_Controller_Router_Route_Interface $route
   * @param Zend_Config              $childRoutesInfo
   * @return void
   */
  protected function _addChainRoutesFromConfig($name,
                         Zend_Controller_Router_Route_Interface $route,
                         Zend_Config $childRoutesInfo)
  {
    foreach ($childRoutesInfo as $childRouteName => $childRouteInfo) {
      if (is_string($childRouteInfo)) {
        $childRouteName = $childRouteInfo;
        $childRoute   = $this->getRoute($childRouteName);
      } else {
        $childRoute = $this->_getRouteFromConfig($childRouteInfo);
      }
      if ($route instanceof Zend_Controller_Router_Route_Chain) {
        $chainRoute = clone $route;
        $chainRoute->chain($childRoute);
      } else {
        $chainRoute = $route->chain($childRoute);
      }
      $chainName = $name . $this->_chainNameSeparator . $childRouteName;
      if (isset($childRouteInfo->chains)) {
        $this->_addChainRoutesFromConfig($chainName, $chainRoute, $childRouteInfo->chains);
      } else {
        $this->addRoute($chainName, $chainRoute);
      }
    }
  }
  /**
   * Remove a route from the route chain
   *
   * @param string $name Name of the route
   * @throws Zend_Controller_Router_Exception
   * @return Zend_Controller_Router_Rewrite
   */
  public function removeRoute($name)
  {
    if (!isset($this->_routes[$name])) {
      require_once 'Zend/Controller/Router/Exception.php';
      throw new Zend_Controller_Router_Exception("Route $name is not defined");
    }
    unset($this->_routes[$name]);
    return $this;
  }
  /**
   * Remove all standard default routes
   *
   * @param Zend_Controller_Router_Route_Interface Route
   * @return Zend_Controller_Router_Rewrite
   */
  public function removeDefaultRoutes()
  {
    $this->_useDefaultRoutes = false;
    return $this;
  }
  /**
   * Check if named route exists
   *
   * @param string $name Name of the route
   * @return boolean
   */
  public function hasRoute($name)
  {
    return isset($this->_routes[$name]);
  }
  /**
   * Retrieve a named route
   *
   * @param string $name Name of the route
   * @throws Zend_Controller_Router_Exception
   * @return Zend_Controller_Router_Route_Interface Route object
   */
  public function getRoute($name)
  {
    if (!isset($this->_routes[$name])) {
      require_once 'Zend/Controller/Router/Exception.php';
      throw new Zend_Controller_Router_Exception("Route $name is not defined");
    }
    return $this->_routes[$name];
  }
  /**
   * Retrieve a currently matched route
   *
   * @throws Zend_Controller_Router_Exception
   * @return Zend_Controller_Router_Route_Interface Route object
   */
  public function getCurrentRoute()
  {
    if (!isset($this->_currentRoute)) {
      require_once 'Zend/Controller/Router/Exception.php';
      throw new Zend_Controller_Router_Exception("Current route is not defined");
    }
    return $this->getRoute($this->_currentRoute);
  }
  /**
   * Retrieve a name of currently matched route
   *
   * @throws Zend_Controller_Router_Exception
   * @return Zend_Controller_Router_Route_Interface Route object
   */
  public function getCurrentRouteName()
  {
    if (!isset($this->_currentRoute)) {
      require_once 'Zend/Controller/Router/Exception.php';
      throw new Zend_Controller_Router_Exception("Current route is not defined");
    }
    return $this->_currentRoute;
  }
  /**
   * Retrieve an array of routes added to the route chain
   *
   * @return array All of the defined routes
   */
  public function getRoutes()
  {
    return $this->_routes;
  }
  /**
   * Find a matching route to the current PATH_INFO and inject
   * returning values to the Request object.
   *
   * @throws Zend_Controller_Router_Exception
   * @return Zend_Controller_Request_Abstract Request object
   */
  public function route(Zend_Controller_Request_Abstract $request)
  {
    if (!$request instanceof Zend_Controller_Request_Http) {
      require_once 'Zend/Controller/Router/Exception.php';
      throw new Zend_Controller_Router_Exception('Zend_Controller_Router_Rewrite requires a Zend_Controller_Request_Http-based request object');
    }
    if ($this->_useDefaultRoutes) {
      $this->addDefaultRoutes();
    }
    // Find the matching route
    $routeMatched = false;
    foreach (array_reverse($this->_routes, true) as $name => $route) {
      // TODO: Should be an interface method. Hack for 1.0 BC
      if (method_exists($route, 'isAbstract') && $route->isAbstract()) {
        continue;
      }
      // TODO: Should be an interface method. Hack for 1.0 BC
      if (!method_exists($route, 'getVersion') || $route->getVersion() == 1) {
        $match = $request->getPathInfo();
      } else {
        $match = $request;
      }
      if ($params = $route->match($match)) {
        $this->_setRequestParams($request, $params);
        $this->_currentRoute = $name;
        $routeMatched    = true;
        break;
      }
    }
     if (!$routeMatched) {
       require_once 'Zend/Controller/Router/Exception.php';
       throw new Zend_Controller_Router_Exception('No route matched the request', 404);
     }
    if($this->_useCurrentParamsAsGlobal) {
      $params = $request->getParams();
      foreach($params as $param => $value) {
        $this->setGlobalParam($param, $value);
      }
    }
    return $request;
  }
  protected function _setRequestParams($request, $params)
  {
    foreach ($params as $param => $value) {
      $request->setParam($param, $value);
      if ($param === $request->getModuleKey()) {
        $request->setModuleName($value);
      }
      if ($param === $request->getControllerKey()) {
        $request->setControllerName($value);
      }
      if ($param === $request->getActionKey()) {
        $request->setActionName($value);
      }
    }
  }
  /**
   * Generates a URL path that can be used in URL creation, redirection, etc.
   *
   * @param array $userParams Options passed by a user used to override parameters
   * @param mixed $name The name of a Route to use
   * @param bool $reset Whether to reset to the route defaults ignoring URL params
   * @param bool $encode Tells to encode URL parts on output
   * @throws Zend_Controller_Router_Exception
   * @return string Resulting absolute URL path
   */
  public function assemble($userParams, $name = null, $reset = false, $encode = true)
  {
    if (!is_array($userParams)) {
      require_once 'Zend/Controller/Router/Exception.php';
      throw new Zend_Controller_Router_Exception('userParams must be an array');
    }
    if ($name == null) {
      try {
        $name = $this->getCurrentRouteName();
      } catch (Zend_Controller_Router_Exception $e) {
        $name = 'default';
      }
    }
    // Use UNION (+) in order to preserve numeric keys
    $params = $userParams + $this->_globalParams;
    $route = $this->getRoute($name);
    $url  = $route->assemble($params, $reset, $encode);
    if (!preg_match('|^[a-z]+://|', $url)) {
      $url = rtrim($this->getFrontController()->getBaseUrl(), self::URI_DELIMITER) . self::URI_DELIMITER . $url;
    }
    return $url;
  }
  /**
   * Set a global parameter
   *
   * @param string $name
   * @param mixed $value
   * @return Zend_Controller_Router_Rewrite
   */
  public function setGlobalParam($name, $value)
  {
    $this->_globalParams[$name] = $value;
    return $this;
  }
  /**
   * Set the separator to use with chain names
   *
   * @param string $separator The separator to use
   * @return Zend_Controller_Router_Rewrite
   */
  public function setChainNameSeparator($separator) {
    $this->_chainNameSeparator = $separator;
    return $this;
  }
  /**
   * Get the separator to use for chain names
   *
   * @return string
   */
  public function getChainNameSeparator() {
    return $this->_chainNameSeparator;
  }
  /**
   * Determines/returns whether to use the request parameters as global parameters.
   *
   * @param boolean|null $use
   *      Null/unset when you want to retrieve the current state.
   *      True when request parameters should be global, false otherwise
   * @return boolean|Zend_Controller_Router_Rewrite
   *       Returns a boolean if first param isn't set, returns an
   *       instance of Zend_Controller_Router_Rewrite otherwise.
   *
   */
  public function useRequestParametersAsGlobal($use = null) {
    if($use === null) {
      return $this->_useCurrentParamsAsGlobal;
    }
    $this->_useCurrentParamsAsGlobal = (bool) $use;
    return $this;
  }
}

ログイン後にコピー

添加路由的操作方法

public function addRoute($name, Zend_Controller_Router_Route_Interface $route)
public function addRoutes($routes)

$router = $ctrl->getRouter(); // returns a rewrite router by default
$router->addRoute('user',
         new Zend_Controller_Router_Route('user/:username'));

ログイン後にコピー

addRoute的第一个参数是路由名。第二个参数是路由自己。路由名最普通的用法是通过Zend_View_Url助手的方法:

"<&#63;= $this->url(array('username' => 'martel'), 'user') &#63;>">Martel</a>

ログイン後にコピー

它将导致在 href: user/martel.

路由是一个简单的过程,这个过程通过所有提供的路由和匹配它的当前请求的URI定义来迭代。当一个正匹配被发现,变量值从路由实例返回并注入到Zend_Controller_Request对象以备将来在派遣器和用户创建的控制器中使用。如果是负匹配,在链中的下个路由被检查。

Note: 倒序匹配

用倒序来匹配路由确保最通用的路由被首先定义。

Note: 返回的值

从路由返回的值来自于URL参数或用于定义的缺省值。这些变量以后可通过Zend_Controller_Request::getParam() 或 Zend_Controller_Action::_getParam() 方法来访问。

有三个特殊的变量可用于你的路由-'module'、 'controller' 和 'action'。这些特殊的变量被Zend_Controller_Dispatcher用来找出控制器和动作然后派遣过去。

Note: 特殊变量

如果你选择通过 setControllerKey 和 setActionKey方法的方式来改变缺省值,这些特殊变量的名字可能会不同。

缺省路由

Zend_Controller_Router_Rewrite 和缺省路由一起预先配置,它将以controller/action的形式匹配URIs。另外,模块名可以被指定作为第一个路径参数,允许这种module/controller/action形式的URIs。最后,它也将缺省地匹配任何另外的追加到URI的参数-controller/action/var1/value1/var2/value2。

一些路由如何匹配的例子:

// Assuming the following:
$ctrl->setControllerDirectory(
  array(
    'default' => '/path/to/default/controllers',
    'news'  => '/path/to/news/controllers',
    'blog'  => '/path/to/blog/controllers'
  )
);
Module only:
http://example/news
  module == news
Invalid module maps to controller name:
http://example/foo
  controller == foo
Module + controller:
http://example/blog/archive
  module   == blog
  controller == archive
Module + controller + action:
http://example/blog/archive/list
  module   == blog
  controller == archive
  action   == list
Module + controller + action + params:
http://example/blog/archive/list/sort/alpha/date/desc
  module   == blog
  controller == archive
  action   == list
  sort    == alpha
  date    == desc

ログイン後にコピー

缺省路由是存储在RewriteRouter名(index)为'default'的简单的Zend_Controller_Router_Route_Module对象。它被创建多多少少象下面这样:

$compat = new Zend_Controller_Router_Route_Module(array(),
                         $dispatcher,
                         $request);
$this->addRoute('default', $compat);

ログイン後にコピー

如果你不想这个特别的缺省路由在你的路由计划中,你可以重写你自己的‘缺省'路由(例如,把它存储在'default'名下)或用removeDefaultRoutes()完全清除它:

// Remove any default routes
$router->removeDefaultRoutes();

ログイン後にコピー

为了增加路由的灵活性,方便自定义新的路由类型,Zend_Controller_Router定义了Zend_Controller_Router_Route_Interface接口和类Zend_Controller_Router_Route_Abstract,实现相应的类方法即可定义路由类型,为开发提供了便利。

Zend_Controller_Router的路由类型

Zend_Controller_Router默认提供了以下路由类型,分别为:

Zend_Controller_Router_Route
Zend_Controller_Router_Route_Static
Zend_Controller_Router_Route_Regex
Zend_Controller_Router_Route_Hostname
Zend_Controller_Router_Route_Module
Zend_Controller_Router_Route_Chain
Zend_Controller_Router_Route

Zend_Controller_Router_Route是标准的框架路由。它结合了灵活路由定义的易用性。每个路由包含了基本的URL映射(静态的和动态的部分(变量))并且可以被缺省地初始化,也可以根据不同的要求初始化。

让我们想象一下我们假设的应用程序将需要一些广域内容作者的信息页面。我们想能够把浏览器指向http://domain.com/author/martel去看一个叫"martel"的信息。有这样功能的路由看起来是这样的:

$route = new Zend_Controller_Router_Route(
  'author/:username',
  array(
    'controller' => 'profile',
    'action'   => 'userinfo'
  )
);
$router->addRoute('user', $route);

ログイン後にコピー

在Zend_Controller_Router_Route里构造函数的第一个参数是路由的定义,它将匹配一个URL。路由定义包含静态的和动态部分,它们由正斜杠('/')符分开。静态部分只是简单的字符:author。动态部分,被叫做变量,用预设的冒号来标记变量名::username。

Note: 字符的的用法

当前的实现允许你使用任何字符(正斜杠除外)作为变量标识符,但强烈建议只使用PHP使用的变量标识符。将来的实现也许会改变这个行为,它可能会导致在你的代码里有隐藏的bugs。

当你把浏览器指向http://domain.com/author/martel这个例子的路由应该被匹配,它所有的变量将被注入到Zend_Controller_Request对象并在ProfileController可访问。由这个例子返回的变量可能会被表示为如下键和值配对的数组:

$values = array(
  'username'  => 'martel',
  'controller' => 'profile',
  'action'   => 'userinfo'
);

ログイン後にコピー

稍后,基于这些值,Zend_Controller_Dispatcher_Standard应该调用ProfileController类(在缺省模块中)中的userinfoAction()方法。你将依靠Zend_Controller_Action::_getParam()或者Zend_Controller_Request::getParam()方法能够访问所有的变量:

public function userinfoAction()
{
  $request = $this->getRequest();
  $username = $request->getParam('username');
  $username = $this->_getParam('username');
}

ログイン後にコピー

路由定义可以包一个额外的特别字符-通配符-表示为'*'号。它被用来取得参数,和缺省模块路由类似(在URI中定义的var=>value)。下面的路由多多少少地模仿了模块路由的行为:

$route = new Zend_Controller_Router_Route(
  ':module/:controller/:action/*',
  array('module' => 'default')
);
$router->addRoute('default', $route);

ログイン後にコピー

变量缺省

在路由中每个变量可以有一个缺省值,这就是Zend_Controller_Router_Route中构造函数使用的第二个变量。这个参数是一个数组,在数组中键表示变量名,值就是期望的缺省值:

$route = new Zend_Controller_Router_Route(
  'archive/:year',
  array('year' => 2006)
);
$router->addRoute('archive', $route);

ログイン後にコピー

上述路由将匹配象http://domain.com/archive/2005和http://example.com/archive的URLs。对于后者变量year将有一个初始的缺省值为2006。

这个例子将导致注入一个year变量给请求对象。应为没有路由信息出现(没有控制器和动作参数被定义),应用程序将被派遣给缺省的控制器和动作方法(它们都在Zend_Controller_Dispatcher_Abstract被定义)。为使它更可用,你必须提供一个有效的控制器和动作作为路由的缺省值:

$route = new Zend_Controller_Router_Route(
  'archive/:year',
  array(
    'year'    => 2006,
    'controller' => 'archive',
    'action'   => 'show'
  )
);
$router->addRoute('archive', $route);

ログイン後にコピー

这个路由将导致派遣给ArchiveController类的showAction()方法。

变量请求

当变量请求被设定,第三个参数可以加给Zend_Controller_Router_Route的构造函数。这些被定义为正则表达式的一部分:

$route = new Zend_Controller_Router_Route(
  'archive/:year',
  array(
    'year'    => 2006,
    'controller' => 'archive',
    'action'   => 'show'
  ),
  array('year' => '\d+')
);
$router->addRoute('archive', $route);

ログイン後にコピー

用上述定义的路由,路由器仅当year变量包含数字数据将匹配它,例如http://domain.com/archive/2345。象http://example.com/archive/test这样的URL将不被匹配并且控制将被传递给在链中的下一个路由。

主机名路由

你也可以使用主机名做路由匹配。对简单的匹配使用静态主机名选项:

$route = new Zend_Controller_Router_Route(
  array(
    'host' => 'blog.mysite.com',
    'path' => 'archive'
  ),
  array(
    'module'   => 'blog',
    'controller' => 'archive',
    'action'   => 'index'
  )
);
$router->addRoute('archive', $route);

ログイン後にコピー

如果你想匹配参数在主机名里,使用 regex 选项。在下面例子中,子域为动作控制器被用作用户名参数。 当组装路由时,你可以给出用户名为参数,就像你用其它路径参数一样:

$route = new Zend_Controller_Router_Route(
  array(
    'host' => array(
      'regex'  => '([a-z]+).mysite.com',
      'reverse' => '%s.mysite.com'
      'params' => array(
        1 => 'username'
      )
    ),
    'path' => ''
  ),
  array(
    'module'   => 'users',
    'controller' => 'profile',
    'action'   => 'index'
  )
);
$router->addRoute('profile', $route);
ログイン後にコピー

Zend_Controller_Router_Route_Static

设置固定不变的路由:

$route = new Zend_Controller_Router_Route_Static(
  'login',
  array('controller' => 'auth', 'action' => 'login')
);
$router->addRoute('login', $route);

ログイン後にコピー

上面的路由将匹配http://domain.com/login的URL,并分派到 AuthController::loginAction().

Zend_Controller_Router_Route_Regex

除了缺省的和静态的路由类型外,正则表达式路由类型也可用。这个路由比其它路由更强更灵活,只是稍微有点复杂。同时,它应该比标准路由快。

象标准路由一样,这个路由必须用路由定义和一些缺省条件来初始化。让我们创建一个archive路由作为例子,和先前定义的类似,这次只是用了Regex:

$route = new Zend_Controller_Router_Route_Regex(
  'archive/(\d+)',
  array(
    'controller' => 'archive',
    'action'   => 'show'
  )
);
$router->addRoute('archive', $route);

ログイン後にコピー

每个定义的regex子模式将被注入到请求对象里。同上述的例子,再成功匹配http://domain.com/archive/2006之后,结果值的数组看起来象这样:

$values = array(
  1      => '2006',
  'controller' => 'archive',
  'action'   => 'show'
);

ログイン後にコピー

Note: 在匹配之前,开头和结尾的斜杠从路由器里的URL中去除掉了。结果,匹配http://domain.com/foo/bar/,需要foo/bar这样的regex,而不是/foo/bar。

Note: 行开头和行结尾符号(分别为'^' 和 '$')被自动预先追加到所有表达式。这样,你不需要在你的正则表达式里用它们,你应该匹配整个字符串。

Note: 这个路由类使用#符作为分隔符。这意味着你将需要避免哈希符('#')但不是正斜杠('/')在你的路由定义里。因为'#'符(名称为锚)很少被传给webserver,你将几乎不需要在你的regex里使用它。

你可以用通常的办法获得已定义的子模式的内容:

public function showAction()
{
  $request = $this->getRequest();
  $year  = $request->getParam(1); // $year = '2006';
}

ログイン後にコピー

Note: 注意这个键是整数(1) 而不是字符串('1')。

因为'year'的缺省没有设置,这个路由将和它的标准路由副本不是非常精确地相同。即使我们为'year'声明一个缺省并使子模式可选,也不清楚是否会在拖尾斜杠(trailing slash)上还将有问题。方案是使整个'year'部分和斜杠一起可选但只抓取数字部分:(这段比较绕口,请校对者仔细看看,谢谢 Jason Qi)

$route = new Zend_Controller_Router_Route_Regex(
  'archive(&#63;:/(\d+))&#63;',
  array(
    1      => '2006',
    'controller' => 'archive',
    'action'   => 'show'
  )
);
$router->addRoute('archive', $route);

ログイン後にコピー

让我们看看你可能注意到的问题。 给参数使用基于整数的键不是容易管理的办法,今后可能会有问题。这就是为什么有第三个参数。这是个联合数组表示一个regex子模式到参数名键的映射。我们来看看一个简单的例子:

$route = new Zend_Controller_Router_Route_Regex(
  'archive/(\d+)',
  array(
    'controller' => 'archive',
    'action' => 'show'
  ),
  array(
    1 => 'year'
  )
);
$router->addRoute('archive', $route);

ログイン後にコピー

这将导致下面的值被注入到请求:

$values = array(
  'year'    => '2006',
  'controller' => 'archive',
  'action'   => 'show'
);

ログイン後にコピー

这个映射被任何目录来定义使它能工作于任何环境。键可以包含变量名或子模式索引:

$route = new Zend_Controller_Router_Route_Regex(
  'archive/(\d+)',
  array( ... ),
  array(1 => 'year')
);
// OR
$route = new Zend_Controller_Router_Route_Regex(
  'archive/(\d+)',
  array( ... ),
  array('year' => 1)
);

ログイン後にコピー

Note: 子模式键必须用整数表示。

注意在请求值中的数字索引不见了,代替的是一个名字变量。当然如果你愿意可以把数字和名字变量混合使用

$route = new Zend_Controller_Router_Route_Regex(
  'archive/(\d+)/page/(\d+)',
  array( ... ),
  array('year' => 1)
);

ログイン後にコピー

这将导致在请求中有混合的值可用。例如:URLhttp://domain.com/archive/2006/page/10将在下列结果中:

$values = array(
  'year'    => '2006',
  2      => 10,
  'controller' => 'archive',
  'action'   => 'show'
);

ログイン後にコピー

因为regex模型不容易颠倒,如果你想用URL助手或这个类中的 assemble方法,你需要准备一个颠倒的URL。这个颠倒的路径用可由sprintf()解析的字符串来表示并定义为第四个构造参数:

$route = new Zend_Controller_Router_Route_Regex(
  'archive/(\d+)',
  array( ... ),
  array('year' => 1),
  'archive/%s'
);

ログイン後にコピー

所有这些都已经可能由标准路由对象完成,那么使用Regex路由的好处在哪里?首先,它允许你不受限制地描述任何类型的URL。想象一下你有一个博客并希望创建象http://domain.com/blog/archive/01-Using_the_Regex_Router.html这样的URLs,还有把解析它路径元素中的最后部分,01-Using_the_Regex_Router.html,到一个文章的ID和文章的标题/描述;这不可能由标准路由完成。用Regex路由,你可以做象下面的方案:

$route = new Zend_Controller_Router_Route_Regex(
  'blog/archive/(\d+)-(.+)\.html',
  array(
    'controller' => 'blog',
    'action'   => 'view'
  ),
  array(
    1 => 'id',
    2 => 'description'
  ),
  'blog/archive/%d-%s.html'
);
$router->addRoute('blogArchive', $route);

ログイン後にコピー

正如你所看到的,这个在标准路由上添加了巨大的灵活性。

通过配置文件定义路由规则

例如

[production]
routes.archive.route = "archive/:year/*"
routes.archive.defaults.controller = archive
routes.archive.defaults.action = show
routes.archive.defaults.year = 2000
routes.archive.reqs.year = "\d+"
routes.news.type = "Zend_Controller_Router_Route_Static"
routes.news.route = "news"
routes.news.defaults.controller = "news"
routes.news.defaults.action = "list"
routes.archive.type = "Zend_Controller_Router_Route_Regex"
routes.archive.route = "archive/(\d+)"
routes.archive.defaults.controller = "archive"
routes.archive.defaults.action = "show"
routes.archive.map.1 = "year"
; OR: routes.archive.map.year = 1

ログイン後にコピー

上述的INI文件可以被读进Zend_Config对象:

$config = new Zend_Config_Ini('/path/to/config.ini', 'production');
$router = new Zend_Controller_Router_Rewrite();
$router->addConfig($config, 'routes');

ログイン後にコピー

在上面的例子中,我们告诉路由器去使用INI文件'routes'一节给它的路由。每个在这个节下的顶级键将用来定义路由名;上述例子定义了路由'archive'和'news'。每个路由接着要求,至少,一个'route'条目和一个或更多'defaults'条目;可选地,一个或更多'reqs'('required'的简写)可能要求提供。总之,这些相对应的三个参数提供给Zend_Controller_Router_Route_Interface对象。一个选项键,'type',可用来指定路由类的类型给特殊的路由;缺省地,它使用Zend_Controller_Router_Route。在上述例子中,'news'路由被定义来使用Zend_Controller_Router_Route_Static。

自定义路由类型

标准的rewrite路由器应当最大限度提供你所需的功能;大多时候,为了通过已知的路由提供新的或修改的功能,你将只需要创建一个新的路由类型

那就是说,你可能想要用不同的路由范例。接口Zend_Controller_Router_Interface提供了需要最少的信息来创建路由器,并包含一个单个的方法。

interface Zend_Controller_Router_Interface
{
 /**
  * @param Zend_Controller_Request_Abstract $request
  * @throws Zend_Controller_Router_Exception
  * @return Zend_Controller_Request_Abstract
  */
 public function route(Zend_Controller_Request_Abstract $request);
}

ログイン後にコピー

路由只发生一次:当请求第一次接收到系统。路由器的意图是基于请求的环境决定控制器、动作和可选的参数,并把它们发给请求。请求对象接着传递给派遣器。如果不可能映射一个路由到一个派遣令牌,路由器对请求对象就什么也不做。

更多关于zend相关内容感兴趣的读者可查看本站专题:《Zend FrameWork框架入门教程》、《php优秀开发框架总结》、《Yii框架入门及常用技巧总结》、《ThinkPHP入门教程》、《php面向对象程序设计入门教程》、《php+mysql数据库操作入门教程》及《php常见数据库操作技巧汇总》

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

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

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

Microsoft NET Framework のインストールの問題エラー コード 0x800c0006 の修正 Microsoft NET Framework のインストールの問題エラー コード 0x800c0006 の修正 May 05, 2023 pm 04:01 PM

開発者とエンド ユーザーが Windows 上で最新バージョンのアプリケーションを実行するには、.NET Framework 4 が必要です。しかし、.NET Framework 4 のダウンロードとインストール中に、多くのユーザーから、インストーラーが途中で停止し、「ダウンロードがエラー コード 0x800c0006 で失敗したため、.NET Framework 4 はインストールされていません」というエラー メッセージが表示されるという苦情が寄せられました。デバイスに .NETFramework4 をインストールしているときにもこの問題が発生する場合は、正しい場所にいます。

Windows 11/10 で SetupDiag を使用して Windows アップグレードの問題を特定する方法 Windows 11/10 で SetupDiag を使用して Windows アップグレードの問題を特定する方法 Apr 17, 2023 am 10:07 AM

Windows 11 または Windows 10 PC でアップグレードまたはアップデートの問題が発生すると、通常、失敗の背後にある実際の理由を示すエラー コードが表示されます。ただし、エラー コードが表示されずにアップグレードまたはアップデートが失敗すると、混乱が生じることがあります。便利なエラー コードを使用すると、問題の場所が正確にわかるので、修正を試みることができます。ただし、エラー コードが表示されないため、問題を特定して解決することが困難になります。エラーの背後にある理由を見つけるだけでも多くの時間がかかります。この場合、Microsoft が提供する SetupDiag という専用ツールを使用すると、エラーの背後にある本当の理由を簡単に特定できます。

SCNotification が動作を停止しました [問題を解決する 5 つのステップ] SCNotification が動作を停止しました [問題を解決する 5 つのステップ] May 17, 2023 pm 09:35 PM

Windows ユーザーは、コンピュータを起動するたびに「SCNotification は動作を停止しました」というエラーに遭遇する可能性があります。 SCNotification.exe は Microsoft システム通知ファイルであり、アクセス許可エラーやネットワーク障害が原因で PC を起動するたびにクラッシュします。このエラーは、問題のあるイベント名でも知られています。したがって、これは SCNotification が動作を停止したということではなく、バグ clr20r3 として認識される可能性があります。この記事では、SCNotification が動作を停止した問題を修正して再び悩まされないようにするために必要なすべての手順を説明します。 SCNotification.eとは何ですか

Microsoft .NET Framework 4.5.2、4.6、および 4.6.1 は 2022 年 4 月にサポートを終了します Microsoft .NET Framework 4.5.2、4.6、および 4.6.1 は 2022 年 4 月にサポートを終了します Apr 17, 2023 pm 02:25 PM

Microsoft.NET バージョン 4.5.2、4.6、または 4.6.1 をインストールしている Microsoft Windows ユーザーが、将来の製品更新を通じて Microsoft にフレームワークをサポートさせることを希望する場合は、新しいバージョンの Microsoft Framework をインストールする必要があります。 Microsoft によると、3 つのフレームワークはすべて 2022 年 4 月 26 日にサポートを終了します。サポート期限が終了すると、製品は「セキュリティ修正またはテクニカル サポート」を受けられなくなります。ほとんどのホーム デバイスは、Windows アップデートを通じて最新の状態に保たれます。これらのデバイスには、.NET Framework 4.8 などの新しいバージョンのフレームワークがすでにインストールされています。自動的に更新されないデバイスは、

Windows 11 の KB5012643 により .NET Framework 3.5 アプリが中断される Windows 11 の KB5012643 により .NET Framework 3.5 アプリが中断される May 09, 2023 pm 01:07 PM

Windows 11 に KB5012643 をインストールしたユーザーに影響を与える新しいセーフ モードのバグについてお話ししてから 1 週間が経過しました。このやっかいな問題は、Microsoft が発売日に投稿した既知の問題のリストには載っていなかったので、誰もが驚きました。さて、事態がこれ以上悪化するはずはないと思ったそのとき、Microsoft は、この累積的な更新プログラムをインストールしたユーザーに別の爆弾を投下します。 Windows 11 Build 22000.652 はさらなる問題を引き起こす そこで同社は、Windows 11 ユーザーに対し、一部の .NET Framework 3.5 アプリケーションの起動と使用に問題が発生する可能性があると警告しています。おなじみですね?でも驚かないでください

Zend Framework でのアクセス許可制御に ACL (アクセス コントロール リスト) を使用する方法 Zend Framework でのアクセス許可制御に ACL (アクセス コントロール リスト) を使用する方法 Jul 29, 2023 am 09:24 AM

Zend Framework でのアクセス許可制御に ACL (AccessControlList) を使用する方法 はじめに: Web アプリケーションでは、アクセス許可制御は重要な機能です。これにより、ユーザーはアクセスを許可されたページと機能にのみアクセスできるようになり、不正アクセスが防止されます。 Zend フレームワークは、ACL (AccessControlList) コンポーネントを使用してアクセス許可制御を実装する便利な方法を提供します。この記事では、Zend Framework で ACL を使用する方法を紹介します。

PHP 実装フレームワーク: Zend Framework 入門チュートリアル PHP 実装フレームワーク: Zend Framework 入門チュートリアル Jun 19, 2023 am 08:09 AM

PHP 実装フレームワーク: ZendFramework 入門チュートリアル ZendFramework は、PHP によって開発されたオープン ソースの Web サイト フレームワークであり、現在 ZendTechnologies によって保守されています。ZendFramework は、MVC デザイン パターンを採用し、Web2.0 アプリケーションと Web サーブの実装に役立つ一連の再利用可能なコード ライブラリを提供します。 。 ZendFramework は PHP 開発者に非常に人気があり、尊敬されており、幅広い機能を備えています。

Cooler Master と Framework が、ラップトップのマザーボードと互換性のある革新的なミニケース キットを発売 Cooler Master と Framework が、ラップトップのマザーボードと互換性のある革新的なミニケース キットを発売 Dec 15, 2023 pm 05:35 PM

12月9日のニュースによると、Cooler Masterは最近、台北コンピューティングショーでのデモンストレーションイベントで、ノートブックモジュラーソリューションプロバイダーのFrameworkと協力して、ミニシャーシキットをデモしました。このキットのユニークな点は、マザーボードと互換性があり、マザーボードを取り付けることができることです。フレームワークノートから。現在、この製品は市場で販売が開始されており、価格は39ドル、現在の為替レートで約279元に相当します。このシャーシキットの型番は「frameWORKMAINBOARDCASE」となります。デザイン面では、わずか297x133x15mmという究極のコンパクトさと実用性を実現しています。そのオリジナルのデザインは、フレームワーク ノートブックにシームレスに接続できるようにすることです。

See all articles