| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534 |
- <?xml version="1.0" encoding="UTF-8"?>
- <!-- Reviewed: no -->
- <sect1 id="zend.controller.router" xmlns:xi="http://www.w3.org/2001/XInclude">
- <title>The Standard Router</title>
- <sect2 id="zend.controller.router.introduction">
- <title>Introduction</title>
- <para>
- <classname>Zend_Controller_Router_Rewrite</classname> is the standard
- framework router. Routing is the process of taking a <acronym>URI</acronym> endpoint
- (that part of the <acronym>URI</acronym> which comes after the base
- <acronym>URL</acronym>) and decomposing it into parameters to determine which module,
- controller, and action of that controller should receive the
- request. This values of the module, controller, action and other
- parameters are packaged into a
- <classname>Zend_Controller_Request_Http</classname> object which is then
- processed by <classname>Zend_Controller_Dispatcher_Standard</classname>.
- Routing occurs only once: when the request is initially received and
- before the first controller is dispatched.
- </para>
- <para>
- <classname>Zend_Controller_Router_Rewrite</classname> is designed to allow for
- mod_rewrite-like functionality using pure <acronym>PHP</acronym> structures. It is very
- loosely based on Ruby on Rails routing and does not require any
- prior knowledge of webserver <acronym>URL</acronym> rewriting. It is designed to work
- with a single Apache mod_rewrite rule (one of):
- </para>
- <programlisting language="php"><![CDATA[
- RewriteEngine on
- RewriteRule !\.(js|ico|gif|jpg|png|css|html)$ index.php
- ]]></programlisting>
- <para>
- or (preferred):
- </para>
- <programlisting language="php"><![CDATA[
- RewriteEngine On
- RewriteCond %{REQUEST_FILENAME} -s [OR]
- RewriteCond %{REQUEST_FILENAME} -l [OR]
- RewriteCond %{REQUEST_FILENAME} -d
- RewriteRule ^.*$ - [NC,L]
- RewriteRule ^.*$ index.php [NC,L]
- ]]></programlisting>
- <para>
- The rewrite router can also be used with the <acronym>IIS</acronym> webserver (versions
- <= 7.0) if <ulink url="http://www.isapirewrite.com">Isapi_Rewrite</ulink> has been
- installed as an Isapi extension with the following rewrite rule:
- </para>
- <programlisting language="php"><![CDATA[
- RewriteRule ^[\w/\%]*(?:\.(?!(?:js|ico|gif|jpg|png|css|html)$)[\w\%]*$)? /index.php [I]
- ]]></programlisting>
- <note>
- <title>IIS Isapi_Rewrite</title>
- <para>
- When using <acronym>IIS</acronym>, <varname>$_SERVER['REQUEST_URI']</varname> will
- either not exist, or be set as an empty string. In this case,
- <classname>Zend_Controller_Request_Http</classname> will attempt to use
- the <varname>$_SERVER['HTTP_X_REWRITE_URL']</varname> value set by the
- <classname>Isapi_Rewrite</classname> extension.
- </para>
- </note>
- <para>
- <acronym>IIS</acronym> 7.0 introduces a native <acronym>URL</acronym> rewriting module,
- and it can be configured as follows:
- </para>
- <programlisting language="xml"><![CDATA[
- <?xml version="1.0" encoding="UTF-8"?>
- <configuration>
- <system.webServer>
- <rewrite>
- <rules>
- <rule name="Imported Rule 1" stopProcessing="true">
- <match url="^.*$" />
- <conditions logicalGrouping="MatchAny">
- <add input="{REQUEST_FILENAME}"
- matchType="IsFile" pattern=""
- ignoreCase="false" />
- <add input="{REQUEST_FILENAME}"
- matchType="IsDirectory"
- pattern="" ignoreCase="false" />
- </conditions>
- <action type="None" />
- </rule>
- <rule name="Imported Rule 2" stopProcessing="true">
- <match url="^.*$" />
- <action type="Rewrite" url="index.php" />
- </rule>
- </rules>
- </rewrite>
- </system.webServer>
- </configuration>
- ]]></programlisting>
- <para>
- If using Lighttpd, the following rewrite rule is valid:
- </para>
- <programlisting language="lighttpd"><![CDATA[
- url.rewrite-once = (
- ".*\?(.*)$" => "/index.php?$1",
- ".*\.(js|ico|gif|jpg|png|css|html)$" => "$0",
- "" => "/index.php"
- )
- ]]></programlisting>
- </sect2>
- <sect2 id="zend.controller.router.usage">
- <title>Using a Router</title>
- <para>
- To properly use the rewrite router you have to instantiate it, add
- some user defined routes and inject it into the controller. The
- following code illustrates the procedure:
- </para>
- <programlisting language="php"><![CDATA[
- // Create a router
- $router = $ctrl->getRouter(); // returns a rewrite router by default
- $router->addRoute(
- 'user',
- new Zend_Controller_Router_Route('user/:username',
- array('controller' => 'user',
- 'action' => 'info'))
- );
- ]]></programlisting>
- </sect2>
- <sect2 id="zend.controller.router.basic">
- <title>Basic Rewrite Router Operation</title>
- <para>
- The heart of the RewriteRouter is the definition of user defined
- routes. Routes are added by calling the addRoute method of
- RewriteRouter and passing in a new instance of a class implementing
- <classname>Zend_Controller_Router_Route_Interface</classname>. Eg.:
- </para>
- <programlisting language="php"><![CDATA[
- $router->addRoute('user',
- new Zend_Controller_Router_Route('user/:username'));
- ]]></programlisting>
- <para>
- Rewrite Router comes with six basic types of routes (one of which
- is special):
- </para>
- <itemizedlist mark="opencircle">
- <listitem>
- <para>
- <link
- linkend="zend.controller.router.routes.standard">Zend_Controller_Router_Route</link>
- </para>
- </listitem>
- <listitem>
- <para>
- <link
- linkend="zend.controller.router.routes.static">Zend_Controller_Router_Route_Static</link>
- </para>
- </listitem>
- <listitem>
- <para>
- <link
- linkend="zend.controller.router.routes.regex">Zend_Controller_Router_Route_Regex</link>
- </para>
- </listitem>
- <listitem>
- <para>
- <link
- linkend="zend.controller.router.routes.hostname">Zend_Controller_Router_Route_Hostname</link>
- </para>
- </listitem>
- <listitem>
- <para>
- <link
- linkend="zend.controller.router.routes.chain">Zend_Controller_Router_Route_Chain</link>
- </para>
- </listitem>
- <listitem>
- <para>
- <link
- linkend="zend.controller.router.default-routes">Zend_Controller_Router_Rewrite</link>
- *
- </para>
- </listitem>
- </itemizedlist>
- <para>
- Routes may be used numerous times to create a chain or user defined
- application routing schema. You may use any number of routes in any
- configuration, with the exception of the Module route, which should
- rather be used once and probably as the most generic route (i.e., as a
- default). Each route will be described in greater detail later on.
- </para>
- <para>
- The first parameter to addRoute is the name of the route. It is used
- as a handle for getting the routes out of the router (e.g., for <acronym>URL</acronym>
- generation purposes). The second parameter being the route itself.
- </para>
- <note>
- <para>
- The most common use of the route name is through the means of
- <classname>Zend_View</classname> url helper:
- </para>
- <programlisting language="php"><![CDATA[
- <a href=
- "<?php echo $this->url(array('username' => 'martel'), 'user') ?>">Martel</a>
- ]]></programlisting>
- <para>
- Which would result in the href: <filename>user/martel</filename>.
- </para>
- </note>
- <para>
- Routing is a simple process of iterating through all provided routes
- and matching its definitions to current request <acronym>URI</acronym>. When a positive
- match is found, variable values are returned from the Route instance
- and are injected into the <classname>Zend_Controller_Request</classname>
- object for later use in the dispatcher as well as in user created
- controllers. On a negative match result, the next route in the chain
- is checked.
- </para>
- <para>
- If you need to determine which route was matched, you can use the
- <methodname>getCurrentRouteName()</methodname> method, which will return the
- identifier used when registering the route with the router. If you
- want the actual route object, you can use
- <methodname>getCurrentRoute()</methodname>.
- </para>
- <note>
- <title>Reverse Matching</title>
- <para>
- Routes are matched in reverse order so make sure your most
- generic routes are defined first.
- </para>
- </note>
- <note>
- <title>Returned Values</title>
- <para>
- Values returned from routing come from <acronym>URL</acronym> parameters or user
- defined route defaults. These variables are later accessible
- through the <methodname>Zend_Controller_Request::getParam()</methodname> or
- <methodname>Zend_Controller_Action::_getParam()</methodname> methods.
- </para>
- </note>
- <para>
- There are three special variables which can be used in your routes
- - 'module', 'controller' and 'action'. These special variables are
- used by <classname>Zend_Controller_Dispatcher</classname> to find a controller and
- action to dispatch to.
- </para>
- <note>
- <title>Special Variables</title>
- <para>
- The names of these special variables may be different if you
- choose to alter the defaults in
- <classname>Zend_Controller_Request_Http</classname> by means of the
- <methodname>setControllerKey()</methodname> and
- <methodname>setActionKey()</methodname> methods.
- </para>
- </note>
- </sect2>
- <sect2 id="zend.controller.router.default-routes">
- <title>Default Routes</title>
- <para>
- <classname>Zend_Controller_Router_Rewrite</classname> comes preconfigured with a default
- route, which will match <acronym>URI</acronym>s in the shape of
- <filename>controller/action</filename>. Additionally, a module name may be
- specified as the first path element, allowing <acronym>URI</acronym>s of the form
- <filename>module/controller/action</filename>. Finally, it will also match
- any additional parameters appended to the <acronym>URI</acronym> by default -
- <filename>controller/action/var1/value1/var2/value2</filename>.
- </para>
- <para>
- Some examples of how such routes are matched:
- </para>
- <programlisting language="php"><![CDATA[
- // 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
- ]]></programlisting>
- <para>
- The default route is simply a
- <classname>Zend_Controller_Router_Route_Module</classname> object stored under
- the name (index) of 'default' in RewriteRouter. It's created
- more-or-less like below:
- </para>
- <programlisting language="php"><![CDATA[
- $compat = new Zend_Controller_Router_Route_Module(array(),
- $dispatcher,
- $request);
- $this->addRoute('default', $compat);
- ]]></programlisting>
- <para>
- If you do not want this particular default route in your routing
- schema, you may override it by creating your own 'default' route
- (i.e., storing it under the name of 'default') or removing it
- altogether by using <methodname>removeDefaultRoutes()</methodname>:
- </para>
- <programlisting language="php"><![CDATA[
- // Remove any default routes
- $router->removeDefaultRoutes();
- ]]></programlisting>
- </sect2>
- <sect2 id="zend.controller.router.rewritebase">
- <title>Base URL and Subdirectories</title>
- <para>
- The rewrite router can be used in subdirectories (e.g.,
- <filename>http://domain.com/user/application-root/</filename>) in which
- case the base <acronym>URL</acronym> of the application
- (<filename>/user/application-root</filename>) should be automatically
- detected by <classname>Zend_Controller_Request_Http</classname> and used
- accordingly.
- </para>
- <para>
- Should the base <acronym>URL</acronym> be detected incorrectly you can override it with
- your own base path by using
- <classname>Zend_Controller_Request_Http</classname> and calling the
- <methodname>setBaseUrl()</methodname> method (see <link
- linkend="zend.controller.request.http.baseurl">Base URL and Subdirectories</link>):
- </para>
- <programlisting language="php"><![CDATA[
- $request->setBaseUrl('/~user/application-root/');
- ]]></programlisting>
- </sect2>
- <sect2 id="zend.controller.router.global.parameters">
- <title>Global Parameters</title>
- <para>
- You can set global parameters in a router which are automatically
- supplied to a route when assembling through
- <methodname>setGlobalParam()</methodname>. If a global parameter is set
- but also given to the assemble method directly, the user parameter
- overrides the global parameter. You can set a global parameter this
- way:
- </para>
- <programlisting language="php"><![CDATA[
- $router->setGlobalParam('lang', 'en');
- ]]></programlisting>
- </sect2>
- <sect2 id="zend.controller.router.routes">
- <title>Route Types</title>
- <xi:include href="Zend_Controller-Router-Route.xml" />
- <xi:include href="Zend_Controller-Router-Route-Static.xml" />
- <xi:include href="Zend_Controller-Router-Route-Regex.xml" />
- <xi:include href="Zend_Controller-Router-Route-Hostname.xml" />
- <xi:include href="Zend_Controller-Router-Route-Chain.xml" />
- <xi:include href="Zend_Controller-Router-Route-Rest.xml" />
- </sect2>
- <sect2 id="zend.controller.router.add-config">
- <title>Using Zend_Config with the RewriteRouter</title>
- <para>
- Sometimes it is more convenient to update a configuration file with
- new routes than to change the code. This is possible via the
- <methodname>addConfig()</methodname> method. Basically, you create a
- <classname>Zend_Config</classname>-compatible configuration, and in your code read it in
- and pass it to the RewriteRouter.
- </para>
- <para>
- As an example, consider the following <acronym>INI</acronym> file:
- </para>
- <programlisting language="php"><![CDATA[
- [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
- ]]></programlisting>
- <para>
- The above <acronym>INI</acronym> file can then be read into a
- <classname>Zend_Config</classname> object as follows:
- </para>
- <programlisting language="php"><![CDATA[
- $config = new Zend_Config_Ini('/path/to/config.ini', 'production');
- $router = new Zend_Controller_Router_Rewrite();
- $router->addConfig($config, 'routes');
- ]]></programlisting>
- <para>
- In the above example, we tell the router to use the 'routes' section
- of the <acronym>INI</acronym> file to use for its routes. Each first-level key under
- that section will be used to define a route name; the above example
- defines the routes 'archive' and 'news'. Each route then requires,
- at minimum, a 'route' entry and one or more 'defaults' entries;
- optionally one or more 'reqs' (short for 'required') may be
- provided. All told, these correspond to the three arguments provided
- to a <classname>Zend_Controller_Router_Route_Interface</classname> object. An
- option key, 'type', can be used to specify the route class type to
- use for that particular route; by default, it uses
- <classname>Zend_Controller_Router_Route</classname>. In the example above, the
- 'news' route is defined to use
- <classname>Zend_Controller_Router_Route_Static</classname>.
- </para>
- </sect2>
- <sect2 id="zend.controller.router.subclassing">
- <title>Subclassing the Router</title>
- <para>
- The standard rewrite router should provide most functionality you
- may need; most often, you will only need to create a new route type
- in order to provide new or modified functionality over the provided
- routes.
- </para>
- <para>
- That said, you may at some point find yourself wanting to use a
- different routing paradigm. The interface
- <classname>Zend_Controller_Router_Interface</classname> provides the minimal
- information required to create a router, and consists of a single
- method.
- </para>
- <programlisting language="php"><![CDATA[
- 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);
- }
- ]]></programlisting>
- <para>
- Routing only occurs once: when the request is first received into
- the system. The purpose of the router is to determine the
- controller, action, and optional parameters based on the request
- environment, and then set them in the request. The request object
- is then passed to the dispatcher. If it is not possible to map a
- route to a dispatch token, the router should do nothing to the
- request object.
- </para>
- </sect2>
- </sect1>
- <!--
- vim:se ts=4 sw=4 et:
- -->
|