Heim > php教程 > PHP开发 > Der Weg zum Zend Framework-Tutorial wird anhand der Funktion Zend_Controller_Router ausführlich erklärt

Der Weg zum Zend Framework-Tutorial wird anhand der Funktion Zend_Controller_Router ausführlich erklärt

高洛峰
Freigeben: 2017-01-03 13:10:20
Original
1275 Leute haben es durchsucht

Das Beispiel in diesem Artikel beschreibt die Verwendung der Routing-Funktion Zend_Controller_Router des Zend Framework-Tutorials. Teilen Sie es als Referenz mit allen. Die Details lauten wie folgt:

Das Routing von Zend Framework bietet zwei Hauptfunktionen: Routing und Erstellungsrouting.

Die Route-Klasse von Zend_Controller_Router und die Klassen im entsprechenden Route-Verzeichnis definieren gemeinsame Routing-Operationen.

Die Schnittstelle Zend_Controller_Router_Interface, die Klassen Zend_Controller_Router_Abstract und Zend_Controller_Router_Rewrite vervollständigen die Funktionen des grundlegenden Routings, des Erstellens von Routen und des Löschens von Routen.

└── Router
├── Abstract.php
├── Exception.php
├── Interface.php
├── Rewrite.php
├ ── Route
    │   ├── Abstract.php
    │   ├── Chain.php
    │   ├── Hostname.php
    │   ├──. Interface.php
    │   ├── Module.php
│ ├ ─ ─ regex.php
│ └ ─ ─ 🎜> └ ─ Route.php

Zend_Controller_Router Route-Funktionsimplementierung

Zend_Controller _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&#39;s URL variable will be reset to
   * default.
   *
   * If null is passed as a route name assemble will use the current Route or &#39;default&#39;
   * if current is not yet set.
   *
   * Reset is used to signal that all parameters should be reset to it&#39;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);
}
Nach dem Login kopieren

Zend_Controller_Router_Abstract

<?php
/** Zend_Controller_Router_Interface */
require_once &#39;Zend/Controller/Router/Interface.php&#39;;
abstract class Zend_Controller_Router_Abstract implements Zend_Controller_Router_Interface
{
  /**
   * URI delimiter
   */
  const URI_DELIMITER = &#39;/&#39;;
  /**
   * 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 &#39;Zend/Controller/Front.php&#39;;
    $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;
  }
}
Nach dem Login kopieren

Zend_Controller_Router_Rewrite

<?php
/** Zend_Controller_Router_Abstract */
require_once &#39;Zend/Controller/Router/Abstract.php&#39;;
/** Zend_Controller_Router_Route */
require_once &#39;Zend/Controller/Router/Route.php&#39;;
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 = &#39;-&#39;;
  /**
   * 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(&#39;default&#39;)) {
      $dispatcher = $this->getFrontController()->getDispatcher();
      $request = $this->getFrontController()->getRequest();
      require_once &#39;Zend/Controller/Router/Route/Module.php&#39;;
      $compat = new Zend_Controller_Router_Route_Module(array(), $dispatcher, $request);
      $this->_routes = array(&#39;default&#39; => $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, &#39;setRequest&#39;)) {
      $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, &#39;routes&#39;);
   *
   * @param Zend_Config $config Configuration object
   * @param string   $section Name of the config section containing route&#39;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 &#39;Zend/Controller/Router/Exception.php&#39;;
        throw new Zend_Controller_Router_Exception("No route configuration in section &#39;{$section}&#39;");
      }
      $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 &#39;Zend/Controller/Router/Exception.php&#39;;
          throw new Zend_Controller_Router_Exception("No chain defined");
        }
        if ($info->chain instanceof Zend_Config) {
          $childRouteNames = $info->chain;
        } else {
          $childRouteNames = explode(&#39;,&#39;, $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 : &#39;Zend_Controller_Router_Route&#39;;
    if (!class_exists($class)) {
      require_once &#39;Zend/Loader.php&#39;;
      Zend_Loader::loadClass($class);
    }
    $route = call_user_func(array($class, &#39;getInstance&#39;), $info);
    if (isset($info->abstract) && $info->abstract && method_exists($route, &#39;isAbstract&#39;)) {
      $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 &#39;Zend/Controller/Router/Exception.php&#39;;
      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 &#39;Zend/Controller/Router/Exception.php&#39;;
      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 &#39;Zend/Controller/Router/Exception.php&#39;;
      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 &#39;Zend/Controller/Router/Exception.php&#39;;
      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 &#39;Zend/Controller/Router/Exception.php&#39;;
      throw new Zend_Controller_Router_Exception(&#39;Zend_Controller_Router_Rewrite requires a Zend_Controller_Request_Http-based request object&#39;);
    }
    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, &#39;isAbstract&#39;) && $route->isAbstract()) {
        continue;
      }
      // TODO: Should be an interface method. Hack for 1.0 BC
      if (!method_exists($route, &#39;getVersion&#39;) || $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 &#39;Zend/Controller/Router/Exception.php&#39;;
       throw new Zend_Controller_Router_Exception(&#39;No route matched the request&#39;, 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 &#39;Zend/Controller/Router/Exception.php&#39;;
      throw new Zend_Controller_Router_Exception(&#39;userParams must be an array&#39;);
    }
    if ($name == null) {
      try {
        $name = $this->getCurrentRouteName();
      } catch (Zend_Controller_Router_Exception $e) {
        $name = &#39;default&#39;;
      }
    }
    // 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(&#39;|^[a-z]+://|&#39;, $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&#39;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;
  }
}
Nach dem Login kopieren

So fügen Sie Routen hinzu

öffentliche Funktion addRoute($name, Zend_Controller_Router_Route_Interface $route)

öffentliche Funktion addRoutes($routes)

$router = $ctrl->getRouter(); // returns a rewrite router by default
$router->addRoute(&#39;user&#39;,
         new Zend_Controller_Router_Route(&#39;user/:username&#39;));
Nach dem Login kopieren

Der erste Parameter von addRoute ist der Routenname. Der zweite Parameter ist die Route selbst. Die häufigste Verwendung von Routennamen erfolgt über die Hilfsmethode Zend_View_Url:

"<?= $this->url(array(&#39;username&#39; => &#39;martel&#39;), &#39;user&#39;) ?>">Martel</a>
Nach dem Login kopieren

, was zu href: user/martel.

<🎜 führt > Routing ist ein einfacher Prozess, der alle bereitgestellten Routen und URI-Definitionen durchläuft, die mit der aktuellen Anfrage übereinstimmen. Wenn eine positive Übereinstimmung gefunden wird, wird der Variablenwert von der Routeninstanz zurückgegeben und in das Zend_Controller_Request-Objekt zur zukünftigen Verwendung in Dispatchern und vom Benutzer erstellten Controllern eingefügt. Bei einer negativen Übereinstimmung wird die nächste Route in der Kette überprüft.

Hinweis: Abgleich in umgekehrter Reihenfolge

Durch den Abgleich von Routen in umgekehrter Reihenfolge wird sichergestellt, dass die häufigsten Routen zuerst definiert werden.

Hinweis: Der zurückgegebene Wert

Der von der Route zurückgegebene Wert stammt aus dem URL-Parameter oder dem für die Definition verwendeten Standardwert. Auf diese Variablen kann später über die Methoden Zend_Controller_Request::getParam() oder Zend_Controller_Action::_getParam() zugegriffen werden.

Für Ihre Routen stehen drei spezielle Variablen zur Verfügung: „Modul“, „Controller“ und „Aktion“. Diese speziellen Variablen werden von Zend_Controller_Dispatcher verwendet, um Controller und Aktionen zu finden und diese zu versenden.

Hinweis: Spezielle Variablen

Wenn Sie den Standardwert über die Methoden setControllerKey und setActionKey ändern, können die Namen dieser speziellen Variablen unterschiedlich sein.

Standardroute

Zend_Controller_Router_Rewrite ist mit der Standardroute vorkonfiguriert, die URIs in der Form von Controller/Aktion abgleicht. Darüber hinaus kann als erster Pfadparameter ein Modulname angegeben werden, der URIs der Form Modul/Controller/Aktion ermöglicht. Schließlich werden standardmäßig auch alle zusätzlichen Parameter abgeglichen, die an den URI angehängt sind – controller/action/var1/value1/var2/value2.

Einige Beispiele, wie Routen abgeglichen werden:

// Assuming the following:
$ctrl->setControllerDirectory(
  array(
    &#39;default&#39; => &#39;/path/to/default/controllers&#39;,
    &#39;news&#39;  => &#39;/path/to/news/controllers&#39;,
    &#39;blog&#39;  => &#39;/path/to/blog/controllers&#39;
  )
);
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
Nach dem Login kopieren

Die Standardroute wird im RewriteRouter mit dem Namen (Index) ' gespeichert. default' Einfaches Zend_Controller_Router_Route_Module-Objekt. Es wird ungefähr so ​​erstellt:

$compat = new Zend_Controller_Router_Route_Module(array(),
                         $dispatcher,
                         $request);
$this->addRoute(&#39;default&#39;, $compat);
Nach dem Login kopieren

Wenn Sie diese bestimmte Standardroute nicht in Ihrem Routenplan haben möchten, können Sie sie neu schreiben Ihre eigene „Standard“-Route (speichern Sie sie beispielsweise unter dem Namen „default“) oder löschen Sie sie vollständig mit „removeDefaultRoutes()“:

// Remove any default routes
$router->removeDefaultRoutes();
Nach dem Login kopieren

In Um die Flexibilität des Routings zu erhöhen und die Anpassung neuer Routing-Typen zu erleichtern, definiert Zend_Controller_Router die Zend_Controller_Router_Route_Interface-Schnittstelle und die Klasse Zend_Controller_Router_Route_Abstract. Durch die Implementierung der entsprechenden Klassenmethode kann der Routing-Typ definiert werden, was die Entwicklung erleichtert.

Routentypen von Zend_Controller_Router

Zend_Controller_Router stellt standardmäßig die folgenden Routentypen bereit:

Zend_Controller_Router_Route

Zend_Controller_Router_Route_Static

Zend_Controller_Router_Ro ute_Regex
Zend_Controller_ Router_Route_Hostname
Zend_Controller_Router_Route_Module
Zend_Controller_Router_Route_Chain
Zend_Controller_Router_Route

Zend_Controller_Router_Route ist eine Standard-Framework-Route. Es kombiniert Benutzerfreundlichkeit mit flexiblen Routendefinitionen. Jede Route enthält eine grundlegende URL-Zuordnung (statische und dynamische Teile (Variablen)) und kann standardmäßig oder entsprechend unterschiedlichen Anforderungen initialisiert werden.

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

$route = new Zend_Controller_Router_Route(
  &#39;author/:username&#39;,
  array(
    &#39;controller&#39; => &#39;profile&#39;,
    &#39;action&#39;   => &#39;userinfo&#39;
  )
);
$router->addRoute(&#39;user&#39;, $route);
Nach dem Login kopieren

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

Note: 字符的的用法

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

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

$values = array(
  &#39;username&#39;  => &#39;martel&#39;,
  &#39;controller&#39; => &#39;profile&#39;,
  &#39;action&#39;   => &#39;userinfo&#39;
);
Nach dem Login kopieren

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

public function userinfoAction()
{
  $request = $this->getRequest();
  $username = $request->getParam(&#39;username&#39;);
  $username = $this->_getParam(&#39;username&#39;);
}
Nach dem Login kopieren

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

$route = new Zend_Controller_Router_Route(
  &#39;:module/:controller/:action/*&#39;,
  array(&#39;module&#39; => &#39;default&#39;)
);
$router->addRoute(&#39;default&#39;, $route);
Nach dem Login kopieren

变量缺省

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

$route = new Zend_Controller_Router_Route(
  &#39;archive/:year&#39;,
  array(&#39;year&#39; => 2006)
);
$router->addRoute(&#39;archive&#39;, $route);
Nach dem Login kopieren

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

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

$route = new Zend_Controller_Router_Route(
  &#39;archive/:year&#39;,
  array(
    &#39;year&#39;    => 2006,
    &#39;controller&#39; => &#39;archive&#39;,
    &#39;action&#39;   => &#39;show&#39;
  )
);
$router->addRoute(&#39;archive&#39;, $route);
Nach dem Login kopieren

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

变量请求

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

$route = new Zend_Controller_Router_Route(
  &#39;archive/:year&#39;,
  array(
    &#39;year&#39;    => 2006,
    &#39;controller&#39; => &#39;archive&#39;,
    &#39;action&#39;   => &#39;show&#39;
  ),
  array(&#39;year&#39; => &#39;\d+&#39;)
);
$router->addRoute(&#39;archive&#39;, $route);
Nach dem Login kopieren

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

主机名路由

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

$route = new Zend_Controller_Router_Route(
  array(
    &#39;host&#39; => &#39;blog.mysite.com&#39;,
    &#39;path&#39; => &#39;archive&#39;
  ),
  array(
    &#39;module&#39;   => &#39;blog&#39;,
    &#39;controller&#39; => &#39;archive&#39;,
    &#39;action&#39;   => &#39;index&#39;
  )
);
$router->addRoute(&#39;archive&#39;, $route);
Nach dem Login kopieren

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

$route = new Zend_Controller_Router_Route(
  array(
    &#39;host&#39; => array(
      &#39;regex&#39;  => &#39;([a-z]+).mysite.com&#39;,
      &#39;reverse&#39; => &#39;%s.mysite.com&#39;
      &#39;params&#39; => array(
        1 => &#39;username&#39;
      )
    ),
    &#39;path&#39; => &#39;&#39;
  ),
  array(
    &#39;module&#39;   => &#39;users&#39;,
    &#39;controller&#39; => &#39;profile&#39;,
    &#39;action&#39;   => &#39;index&#39;
  )
);
Nach dem Login kopieren

$router->addRoute('profile', $route);

Zend_Controller_Router_Route_Static

设置固定不变的路由:

$route = new Zend_Controller_Router_Route_Static(
  &#39;login&#39;,
  array(&#39;controller&#39; => &#39;auth&#39;, &#39;action&#39; => &#39;login&#39;)
);
$router->addRoute(&#39;login&#39;, $route);
Nach dem Login kopieren

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

Zend_Controller_Router_Route_Regex

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

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

$route = new Zend_Controller_Router_Route_Regex(
  &#39;archive/(\d+)&#39;,
  array(
    &#39;controller&#39; => &#39;archive&#39;,
    &#39;action&#39;   => &#39;show&#39;
  )
);
$router->addRoute(&#39;archive&#39;, $route);
Nach dem Login kopieren

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

$values = array(
  1      => &#39;2006&#39;,
  &#39;controller&#39; => &#39;archive&#39;,
  &#39;action&#39;   => &#39;show&#39;
);
Nach dem Login kopieren

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 = &#39;2006&#39;;
}
Nach dem Login kopieren

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

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

$route = new Zend_Controller_Router_Route_Regex(
  &#39;archive(?:/(\d+))?&#39;,
  array(
    1      => &#39;2006&#39;,
    &#39;controller&#39; => &#39;archive&#39;,
    &#39;action&#39;   => &#39;show&#39;
  )
);
$router->addRoute(&#39;archive&#39;, $route);
Nach dem Login kopieren

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

$route = new Zend_Controller_Router_Route_Regex(
  &#39;archive/(\d+)&#39;,
  array(
    &#39;controller&#39; => &#39;archive&#39;,
    &#39;action&#39; => &#39;show&#39;
  ),
  array(
    1 => &#39;year&#39;
  )
);
$router->addRoute(&#39;archive&#39;, $route);
Nach dem Login kopieren

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

$values = array(
  &#39;year&#39;    => &#39;2006&#39;,
  &#39;controller&#39; => &#39;archive&#39;,
  &#39;action&#39;   => &#39;show&#39;
);
Nach dem Login kopieren

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

$route = new Zend_Controller_Router_Route_Regex(
  &#39;archive/(\d+)&#39;,
  array( ... ),
  array(1 => &#39;year&#39;)
);
// OR
$route = new Zend_Controller_Router_Route_Regex(
  &#39;archive/(\d+)&#39;,
  array( ... ),
  array(&#39;year&#39; => 1)
);
Nach dem Login kopieren

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

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

$route = new Zend_Controller_Router_Route_Regex(
  &#39;archive/(\d+)/page/(\d+)&#39;,
  array( ... ),
  array(&#39;year&#39; => 1)
);
Nach dem Login kopieren

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

$values = array(
  &#39;year&#39;    => &#39;2006&#39;,
  2      => 10,
  &#39;controller&#39; => &#39;archive&#39;,
  &#39;action&#39;   => &#39;show&#39;
);
Nach dem Login kopieren

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

$route = new Zend_Controller_Router_Route_Regex(
  &#39;archive/(\d+)&#39;,
  array( ... ),
  array(&#39;year&#39; => 1),
  &#39;archive/%s&#39;
);
Nach dem Login kopieren

所有这些都已经可能由标准路由对象完成,那么使用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(
  &#39;blog/archive/(\d+)-(.+)\.html&#39;,
  array(
    &#39;controller&#39; => &#39;blog&#39;,
    &#39;action&#39;   => &#39;view&#39;
  ),
  array(
    1 => &#39;id&#39;,
    2 => &#39;description&#39;
  ),
  &#39;blog/archive/%d-%s.html&#39;
);
$router->addRoute(&#39;blogArchive&#39;, $route);
Nach dem Login kopieren

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

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

例如

[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
Nach dem Login kopieren

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

$config = new Zend_Config_Ini(&#39;/path/to/config.ini&#39;, &#39;production&#39;);
$router = new Zend_Controller_Router_Rewrite();
$router->addConfig($config, &#39;routes&#39;);
Nach dem Login kopieren

在上面的例子中,我们告诉路由器去使用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);
}
Nach dem Login kopieren

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

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

更多Zend Framework教程之路由功能Zend_Controller_Router详解相关文章请关注PHP中文网!

Verwandte Etiketten:
Quelle:php.cn
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Empfehlungen
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage