Zend Framework provides several alternatives to the default classes provided, including alternate request objects, routers, and response objects.
Zend_Controller_Request_Http
provides a request object
for use in an HTTP environment.
Zend_Controller_Request_Http
is the default request class utilised by
Zend_Controller_Dispatcher
.
Zend_Controller_Request_Http
encapsulates access
to relevant values such as the key name and value for the
controller and action router variables, and all additional
parameters parsed from the URI. By proxying to
Zend_Controller_Request_Http
it additionally allows
access to values contained in the superglobals as public
members and manages the current Base URL and Request URI.
Superglobal values cannot be set on a request object, instead use
the setParam/getParam methods to set or retrieve user parameters.
Superglobal data | |
---|---|
When accessing superglobal data through |
Specific superglobals can be accessed using a public method as an
alternative. For example, the raw value of $_POST['user']
can be accessed by calling getPost('user')
on the
request object.
Zend_Controller_Request_Http
allows
Zend_Controller_Router_Rewrite to be used in subdirectories.
Zend_Controller_Request_Http will attempt to automatically
detect your base URL and set it accordingly.
For example, if you keep your
index.php
in a webserver subdirectory named
/projects/myapp/index.php
, base URL (rewrite base)
should be set to /projects/myapp
. This string will
then be stripped from the beginning of the path before
calculating any route matches. This frees one from the necessity
of prepending it to any of your routes. A route of
'user/:username'
will match URIs like
http://localhost/projects/myapp/user/martel
and
http://example.com/user/martel
.
URL detection is case sensitive | |
---|---|
Automatic base URL detection is case sensitive, so make sure your URL will match a subdirectory name in a filesystem (even on Windows machines). If it doesn't you will get to noRoute action. |
Should base URL be detected incorrectly you can override it
with your own base path with the help of the
setBaseUrl()
method of either the
Zend_Controller_Request_Http
class, or the
Zend_Controller_Front
class. The easiest
method is to set it in Zend_Controller_Front
,
which will proxy it into the request object. Example usage to
set a custom base URL:
/** * Dispatch Request with custom base URL with Zend_Controller_Front. */ $router = new Zend_Controller_Router_Rewrite(); $controller = Zend_Controller_Front::getInstance(); $controller->setControllerDirectory('./application/controllers') ->setRouter($router) ->setBaseUrl('/projects/myapp'); // set the base url! $response = $controller->dispatch();
Zend_Controller_Router_Rewrite
is the standard
framework router. Routing is the process of taking a URI
endpoint (that part of the URI which comes after the base URL)
and decomposing it into parameters to determine which controller
and action of that controller should receive the request. This
value of the controller, action and other parameters is packaged
into a Zend_Controller_Request_Http
object which is
then processed by Zend_Controller_Dispatcher_Standard
.
Routing occurs only once: when the request is initially received
and before the first controller is dispatched.
Zend_Controller_Router_Rewrite
is designed to allow for
mod_rewrite like functionality using pure php structures. It is
very loosely based on Ruby on Rails routing and does not require
any prior knowledge of webserver URL rewriting. It is designed
to work with a single Apache mod_rewrite rule (one of):
RewriteEngine on RewriteRule !\.(js|ico|gif|jpg|png|css)$ index.php
or:
RewriteEngine on RewriteCond %{SCRIPT_FILENAME} !-f RewriteCond %{SCRIPT_FILENAME} !-d RewriteRule ^(.*)$ index.php/$1
The rewrite router can also be used with the IIS webserver if Isapi_Rewrite has been installed as an Isapi extension with the following rewrite rule:
RewriteRule ^[\w/\%]*(?:\.(?!(?:js|ico|gif|jpg|png|css)$)[\w\%]*$)? /index.php [I]
IIS Isapi_Rewrite | |
---|---|
When using IIS, |
If using Lighttpd, the following rewrite rule is valid:
url.rewrite-once = ( ".*\.(js|ico|gif|jpg|png|css)$" => "$0", "" => "/index.php")
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:
/* 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')) );
The heart of the RewriteRouter is the definition of user defined
routes. Routes are created by calling the addRoute method of
RewriteRouter and passing in a new instance of
Zend_Controller_Router_Route
:
$router->addRoute('user', new Zend_Controller_Router_Route('user/:username'));
The first parameter is the name of the route. It is redundant at
the moment of writing but will be used in the future in a URL
view helper to allow for easy URL generation in your views.
Should you need to make use of a previously configured named
route, you can retrieve it with the getRoute method of the
RewriteRouter. The second parameter is an instance of
Zend_Controller_Router_Route
.
The first parameter for the
Zend_Controller_Router_Route
constructor is a route that will be matched to a URL -
for example, the above route will match
http://example.com/user/martel
. The colon in a
route marks a URL variable. After the successful routing, values
of all defined variables will be injected to the Zend_Controller_Request.
After that they will be accessible through a Zend_Controller_Request::getParam or
Zend_Controller_Action::_getParam methods. In our example a
parameter named username will be set to a value of 'martel'.
Reverse matching | |
---|---|
Routes are matched in reverse order so make sure your most generic routes are defined first. |
Character useage | |
---|---|
For now the current implementation allows for use of any characters except a slash (/) as a variable identifier but it is strongly recommended that one uses only php variable friendly characters. In future the implementation will probably be altered and this may introduce bugs to your code. |
There are two special variables which can be used in your routes - ':controller' and ':action'. These special variables will be used to find a controller and/or an action chosen in the URL. The ':action' variable must always be defined either in the route or as a default parameter. The ':controller' variable will default to the IndexController if it is not defined.
Special variables | |
---|---|
Names of these special variables may be different if you choose to
alter the defaults in |
$router->addRoute( 'user', new Zend_Controller_Router_Route(':controller/:action') );
If you point your browser to 'http://example.com/news/latest'
with this route defined the Zend_Controller_Dispatcher
will invoke the latestAction method of your NewsController class.
Every variable in the route can have a default. To provide it
you have to add a second parameter to the
Zend_Controller_Router_Route
constructor. This
parameter is an array with keys as variable names and
values as desired defaults.
$router->addRoute( 'archive', new Zend_Controller_Router_Route('archive/:year', array('year' => 2006)) );
What may not be clearly visible is that the above route will match URLs like 'http://example.com/archive/2005' and 'http://example.com/archive'. In the latter case the variable year will have a value of 2006.
The above example will only result in injecting a year variable to the request. No routing will take place since controller and action parameters are not set. To make it more usable you have to provide a valid controller and a valid action as defaults.
$router->addRoute( 'archive', new Zend_Controller_Router_Route('archive/:year', array('year' => 2006, 'controller' => 'archive', 'action' => 'show') );
This route will then result in dispatching to showAction of ArchiveController.
One can add a third parameter to the
Zend_Controller_Router_Route
constructor where variable requirements can
be set. These are defined as regular expressions:
$router->addRoute( 'archive', new Zend_Controller_Router_Route('archive/:year', array('year' => 2006), array('year' => '\d+')) );
Routing behavior | |
---|---|
Unlike Ruby on Rails, ZF RewriteRouter will match a route and use a default when a third parameter variable requirement is not met. So the URL of 'http://example.com/archive/test' will match the above route and set the year to 2006. This functionality may be altered in the future as it is being discussed at the moment of writing of this documentation. |
The rewrite router can be used in subdirectories, and the base
URL will be automatically detected by
Zend_Controller_Request_Http
.
Should the base URL be detected incorrectly you can override it
with your own base path with the help of Zend_Controller_Request_Http
by calling the setBaseUrl()
method (see Section 7.4.2.3, “Base Url and subdirectories”).
Zend_Controller_Router_Rewrite is preconfigured with one default.
It will match URIs in the shape of 'controller/action'
Additionally, a module name may be specified as the first path
element, allowing URIs of the form
'module/controller/action
.
Finally, it will also match any additional parameters appended
to the URI by default.
As some examples of how such routes are matched:
// Assuming the following: // $ctrl->setControllerDirectory(array( // 'default' => '/path/to/default/controllers', // 'news' => '/path/to/blog/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
The default route is a
Zend_Controller_Router_Route_Module
object
instantiated without any defaults:
// Route for Router v1 compatibility $compat = new Zend_Controller_Router_Route_Module(); $this->addRoute('default', $compat);
Matching URIs | |
---|---|
|
If you do not want the default route in your routing schema, you
may remove it using removeDefaultRoutes()
:
// Remove default compatability route $router->removeDefaultRoutes();
The examples above all use dynamic routes -- routes that contain patterns to match against. Sometimes, however, a particular route is set in stone, and firing up the regular expression engine would be overkill. The answer to this situation is to use static routes:
$loginRoute = new Zend_Controller_Router_Route_Static('login', array('controller' => 'login', 'action' => 'form')); $router->addRoute('login', $static);
Sometimes its more convenient to update a configuration file
with new routes than to change the code. This is possible via
the addConfig()
method. Basically, you create a
Zend_Config-compatible configuration, and in your code read it
in and pass it to the RewriteRouter:
/** * Example INI located at /path/to/config.ini: * * [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" */ $config = new Zend_Config_Ini('/path/to/config.ini', 'production'); $router = new Zend_Controller_Router_Rewrite(); $router->addConfig($config, 'routes');
In the above example, we tell the router to use the 'routes'
section of the INI 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, minimally 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 Zend_Controller_Router_Route_Interface
object. An option key, 'type', can be used to specify the route
class type to use for that particular route; by default, it uses
Zend_Controller_Router_Route
. In the example above,
the 'news' route is defined to use
Zend_Controller_Router_Route_Static
.
Zend_Controller_Response_Http
is a response object
suitable for use in an HTTP environment. It contains methods for
setting, retrieving, and clearing headers, and the
__toString()
method sends all headers at once before
returning the response content.
setHeader()
takes two arguments, a header type and the
header value. A third, optional parameter, if passed and true, will
force the new header to replace any other headers registered with
that type.