目錄
Zend Framework教程之路由功能Zend_Controller_Router详解,uiroutercontroller
您可能感兴趣的文章:
首頁 php教程 php手册 Zend Framework教程之路由功能Zend_Controller_Router详解,uiroutercontroller

Zend Framework教程之路由功能Zend_Controller_Router详解,uiroutercontroller

Jun 13, 2016 am 08:44 AM
framework zend 路由功能

Zend Framework教程之路由功能Zend_Controller_Router详解,uiroutercontroller

本文实例讲述了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程序设计有所帮助。

您可能感兴趣的文章:

  • Zend Framework教程之Autoloading用法详解
  • Zend Framework教程之Resource Autoloading用法实例
  • Zend Framework教程之MVC框架的Controller用法分析
  • Zend Framework教程之Zend_Controller_Plugin插件用法详解
  • Zend Framework教程之响应对象的封装Zend_Controller_Response实例详解
  • Zend Framework教程之请求对象的封装Zend_Controller_Request实例详解
  • Zend Framework教程之动作的基类Zend_Controller_Action详解
  • Zend Framework教程之分发器Zend_Controller_Dispatcher用法详解
  • Zend Framework教程之前端控制器Zend_Controller_Front用法详解
  • Zend Framework教程之视图组件Zend_View用法详解
  • Zend Framework教程之Loader以及PluginLoader用法详解
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Java教學
1662
14
CakePHP 教程
1419
52
Laravel 教程
1311
25
PHP教程
1261
29
C# 教程
1234
24
Microsoft NET Framework 安裝問題 錯誤代碼 0x800c0006 修復 Microsoft NET Framework 安裝問題 錯誤代碼 0x800c0006 修復 May 05, 2023 pm 04:01 PM

.NETFramework4是開發人員和最終使用者在Windows上執行最新版本的應用程式所必需的。但是,在下載安裝.NETFramework4時,許多用戶抱怨安裝程式在中途停止,顯示以下錯誤訊息-「 .NETFramework4hasnotbeeninstalledbecauseDownloadfailedwitherrorcode0x800c0006 」。在您的裝置上安裝.NETFramework4時,如果您也在體驗它,那麼您就來對了地方

如何在 Windows 11/10 上使用 SetupDiag 識別 Windows 升級問題 如何在 Windows 11/10 上使用 SetupDiag 識別 Windows 升級問題 Apr 17, 2023 am 10:07 AM

每當您的Windows11或Windows10PC出現升級或更新問題時,您通常會看到一個錯誤代碼,指示故障背後的實際原因。但是,有時,升級或更新失敗可能不會顯示錯誤代碼,這時就會混淆。有了方便的錯誤代碼,您可以確切地知道問題出在哪裡,因此您可以嘗試修復。但是由於沒有出現錯誤代碼,因此識別問題並解決它變得極具挑戰性。這會佔用您大量時間來簡單地找出錯誤背後的原因。在這種情況下,您可以嘗試使用Microsoft提供的名為SetupDiag的專用工具,該工具可協助您輕鬆識別錯誤背後的真

SCNotification 已停止運作 [修復它的 5 個步驟] SCNotification 已停止運作 [修復它的 5 個步驟] May 17, 2023 pm 09:35 PM

身為Windows用戶,您很可能會在每次啟動電腦時遇到SCNotification已停止工作錯誤。 SCNotification.exe是一個微軟系統通知文件,由於權限錯誤和點網故障等原因,每次啟動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的MicrosoftWindows用戶如果希望Microsoft將來透過產品更新支援該框架,則必須安裝較新版本的Microsoft框架。據微軟稱,這三個框架都將在2022年4月26日停止支援。支援日期結束後,產品將不會收到「安全修復或技術支援」。大多數家庭設備透過Windows更新保持最新。這些設備已經安裝了較新版本的框架,例如.NETFramework4.8。未自動更新的設備可能

PHP實作框架:Zend Framework入門教程 PHP實作框架:Zend Framework入門教程 Jun 19, 2023 am 08:09 AM

PHP實作框架:ZendFramework入門教學ZendFramework是PHP開發的開源網站框架,目前由ZendTechnologies維護,ZendFramework採用了MVC設計模式,提供了一系列可重複使用的程式碼庫,服務於實作Web2.0應用程式和Web服務。 ZendFramework深受PHP開發者的歡迎與推崇,擁有廣泛

適用於 Windows 11 的KB5012643破壞了.NET Framework 3.5應用程式 適用於 Windows 11 的KB5012643破壞了.NET Framework 3.5應用程式 May 09, 2023 pm 01:07 PM

自從我們談論影響安裝KB5012643forWindows11的用戶的新安全模式錯誤以來已經過去了一周。這個討厭的問題並沒有出現在微軟在發布當天發布的已知問題清單中,因此讓所有人都感到驚訝。好吧,就在您認為情況不會變得更糟的時候,微軟為安裝此累積更新的用戶投下了另一顆炸彈。 Windows11Build22000.652導致更多問題因此,這家科技公司警告Windows11用戶,他們在啟動和使用某些.NETFramework3.5應用程式時可能會遇到問題。聽起來很熟悉?不過請不要驚

如何在Zend框架中使用ACL(Access Control List)進行權限控制 如何在Zend框架中使用ACL(Access Control List)進行權限控制 Jul 29, 2023 am 09:24 AM

如何在Zend框架中使用ACL(AccessControlList)進行權限控制導言:在一個Web應用程式中,權限控制是至關重要的功能。它可以確保使用者只能存取其有權存取的頁面和功能,並防止未經授權的存取。 Zend框架提供了一種方便的方法來實現權限控制,即使用ACL(AccessControlList)元件。本文將介紹如何在Zend框架中使用ACL

酷冷至尊攜手Framework推出創新迷你機殼套件,相容於筆電主機板 酷冷至尊攜手Framework推出創新迷你機殼套件,相容於筆電主機板 Dec 15, 2023 pm 05:35 PM

12月9日消息,最近,酷冷至尊在台北電腦展上的一次展示活動中,展示了與筆記本模組化方案提供商framework合作的迷你機箱套件,這個套件的獨特之處在於,它可以兼容併安裝來自framework筆記本的主機板。目前,這款產品已開始在市場上銷售,售價定為39美元,以當前匯率折合約279元。這款機箱套件的型號被命名為「frameWORKMAINBOARDCASE」。在設計方面,它體現了極致的緊湊與實用性,尺寸僅為297x133x15毫米。它的設計初衷是為了能夠無縫連接到framework筆記本的

See all articles