本文实例讲述了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

<?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

<?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

<?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)) ? $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助手的方法:

"<?= $this->url(array('username' => 'martel'), 'user') ?>">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(?:/(\d ))?',
  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程序设计有所帮助。

Zend Framework教程之路由功能Zend_Controller_Router详解的更多相关文章

  1. ios – 黑客入侵MFMessageComposeViewController

    2)如何找出实际的messageSend方法及其实现的类?

  2. ios – 在设备上构建和运行时,仅将嵌入式框架与其他动态框架链接失败

    TL;博士将您的嵌入式框架与其他框架链接,并且不将其他框架与您的应用程序链接,导致Build&在设备上运行.描述:建立:我的设置非常简单(Swift2.3&XcodeXcode8.0;Build版本8S162m):>使用Carthage(0.17.2)我用xcodebuild8.0和TOOLCHAINS=com.apple.dt.toolchain.Swift_2_3carthagebui

  3. ios – Xcode 7.1 PrototypeTools链接器错误(仅限模拟器)

    我正在尝试使用Xcode7.1在iOS模拟器中运行我的应用程序,但我收到链接器错误.这是错误:clang:错误:链接器命令失败,退出代码为1这似乎是一个新问题,因为我在升级到新的Xcode之前没有它.我在Google上搜索过,但是这个问题几乎没有相关主题.有趣的是,该应用程序在设备上运行良好.我已经尝试重置模拟器并再次清洁/建造,但两者都没有奏效.有没有其他人遇到过这个问题,你能提供什么建议吗?

  4. ios – iPhone崩溃日志不能正确地符号化并且是双重间隔的

    任何建议超过欢迎.谢谢.解决方法当这件事发生在我身上时,它只是我通过电子邮件收到的日志.如果我记得,至少有一些是在.msg文件中,我不得不把它们拿出来.它可能是Exchange编码更改.如果你显示不可见的字符,你可能会看到每个字符之间的东西.您可以找到并替换它们以删除它们或更改编辑器中的编码.

  5. 如何使用iOS上的BluetoothManager.framework私有API发送和接收数据

    这些天我正在开展一个项目,我们需要将非MFI蓝牙设备连接到iPhone,并且该设备不支持成为BLE外围设备客户端,因此我们必须在经典蓝牙上执行此操作.我设法使用BluetoothManager.framework与demoprojectBeeTee的指南配对并将设备连接到iPhone但我不知道如何发送和recv数据,我在类转储标头中找不到API.似乎答案在于这三个结构:BTAccessoryMan

  6. ios – 如何存档包含自定义框架的应用程序?

    我有一个我创建的xcode框架项目,我可以编译成一个myframework.framework文件.编译之后,我将这个框架拖到我应用程序的Frameworks项目文件夹中,然后利用框架中的类,将适当的import语句添加到需要它的任何类;这允许我的应用程序成功编译与在框架中定义的类的引用.要使应用程序成功部署到我的设备,我还将我的自定义框架添加到我的目标的“嵌入式二进制文件”部分.有了这一切,我可

  7. ios – Xcode无法找到strip-frameworks.sh目录

    谢谢!

  8. ios – Iphone / Ipad在缩放时崩溃

    i=hUb1GHJ6有没有人有什么可能出错的线索?解决方法我们正在做很多调试,我们终于找到了一个解决方案.我们有一个“跳过导航”链接,只有在您的键盘上按“标签”时才显示.这最初设置为“text-indent:-10000px”.这可能导致视口宽度超过10000像素,然后导致手机使用太多内存,然后最终崩溃.我们已经通过删除这个CSS规则来解决这个问题,所以blush.no不会崩溃那么多了.Iphone仍然有内存泄漏的问题,直到他们解决这个问题,网站有时会崩溃,但不会像以前那样接近.

  9. 在客户端获取iOS Universal Framework的版本号

    这可能不限于iOSUniversalFrameworks,而是所有xxx.framework文件.然而,我似乎找不到如何获取当前版本和客户端应用程序中构建框架的文档.在一个应用程序中,您可以使用以下内容:这将为您提供存储在应用程序的Info.plist中的当前信息.但是我们如何找到一个框架的信息.在我的情况下,具体是嵌入式框架.解决方法我发现苹果在Xcode6中支持的新的CocoaTouch框架为

  10. 在快速iOS应用程序中使用FBSDK的问题

    我正在使用FBSDK在swift中编写一个iOS8应用程序,以允许用户登录到我的应用程序.到目前为止,我已经使用Bridging-Header.h文件在swift中使用FBSDKv3.25成功实现了登录功能,并根据FB开发者网站上的说明更新了info.plist.现在我想制作一个应用程序到FBSDKv4.01,但是当我按照同样的过程将其集成到我的应用程序中时,我会收到以下错误:最明显的事情是最后一个错误,表示桥接头无法找到,但它是在同一个地方,因为当我使用FBSDK3.25?

随机推荐

  1. PHP个人网站架设连环讲(一)

    先下一个OmnihttpdProffesinalV2.06,装上就有PHP4beta3可以用了。PHP4给我们带来一个简单的方法,就是使用SESSION(会话)级变量。但是如果不是PHP4又该怎么办?我们可以假设某人在15分钟以内对你的网页的请求都不属于一个新的人次,这样你可以做个计数的过程存在INC里,在每一个页面引用,访客第一次进入时将访问时间送到cookie里。以后每个页面被访问时都检查cookie上次访问时间值。

  2. PHP函数学习之PHP函数点评

    PHP函数使用说明,应用举例,精简点评,希望对您学习php有所帮助

  3. ecshop2.7.3 在php5.4下的各种错误问题处理

    将方法内的函数,分拆为2个部分。这个和gd库没有一点关系,是ecshop程序的问题。会出现这种问题,不外乎就是当前会员的session或者程序对cookie的处理存在漏洞。进过本地测试,includes\modules\integrates\ecshop.php这个整合自身会员的类中没有重写integrate.php中的check_cookie()方法导致,验证cookie时返回的username为空,丢失了登录状态,在ecshop.php中重写了此方法就可以了。把他加到ecshop.php的最后面去就可

  4. NT IIS下用ODBC连接数据库

    $connection=intodbc_connect建立数据库连接,$query_string="查询记录的条件"如:$query_string="select*fromtable"用$cur=intodbc_exec检索数据库,将记录集放入$cur变量中。再用while{$var1=odbc_result;$var2=odbc_result;...}读取odbc_exec()返回的数据集$cur。最后是odbc_close关闭数据库的连接。odbc_result()函数是取当前记录的指定字段值。

  5. PHP使用JpGraph绘制折线图操作示例【附源码下载】

    这篇文章主要介绍了PHP使用JpGraph绘制折线图操作,结合实例形式分析了php使用JpGraph的相关操作技巧与注意事项,并附带源码供读者下载参考,需要的朋友可以参考下

  6. zen_cart实现支付前生成订单的方法

    这篇文章主要介绍了zen_cart实现支付前生成订单的方法,结合实例形式详细分析了zen_cart支付前生成订单的具体步骤与相关实现技巧,需要的朋友可以参考下

  7. Thinkphp5框架实现获取数据库数据到视图的方法

    这篇文章主要介绍了Thinkphp5框架实现获取数据库数据到视图的方法,涉及thinkPHP5数据库配置、读取、模型操作及视图调用相关操作技巧,需要的朋友可以参考下

  8. PHP+jquery+CSS制作头像登录窗(仿QQ登陆)

    本篇文章介绍了PHP结合jQ和CSS制作头像登录窗(仿QQ登陆),实现了类似QQ的登陆界面,很有参考价值,有需要的朋友可以了解一下。

  9. 基于win2003虚拟机中apache服务器的访问

    下面小编就为大家带来一篇基于win2003虚拟机中apache服务器的访问。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  10. Yii2中组件的注册与创建方法

    这篇文章主要介绍了Yii2之组件的注册与创建的实现方法,非常不错,具有参考借鉴价值,需要的朋友可以参考下

返回
顶部