AnewtURLDispatcher class

Dispatcher that routes requests to request handler methods.

Class Overview

Dispatcher that routes requests to request handler methods.

Well-designed web applications use a clean URL scheme for all pages and resources in the application. Read ‘Cool URIs don't change’ to find out why this is important. Clean web applications do not need ugly .php extensions or weird HTTP GET parameters with cryptic numbers or strange identifers. Instead, you are encouraged to use clean URLs, e.g. /user/USERNAME for a user page.

AnewtURLDispatcher offers the basic functionality to implement web applications that use clean URLs. AnewtURLDispatcher processes incoming requests and looks at the URL of the request to decide which piece of code should be invoked to handle that request. This means that AnewtURLDispatcher is at the heart of your application: it is the main entry point for all the functionality your application offers.

AnewtURLDispatcher is based around two main concepts: commands and routes.

Commands

Commands are methods that do the actual work, like building an output page. Commands are regular methods on your AnewtURLDispatcher subclass, and look like command_xyz(), where xyz is the name of the command. What you would normally create a separate PHP file for, e.g. users.php, you can now write as a simple method, e.g. command_users(). Other related pages are just additional methods on the same class. AnewtURLDispatcher allows you to group related functionality together in one file, e.g. a user page, an ‘edit user’ page, or a ‘new user’ page. (Note that if you insist you can still require_once('latest-news.php') in your command method, though this is not how AnewtURLDispatcher is intended to be used).

Routes

Routes define how URLs map to commands. This is where you define your URL scheme and say which command should be executed when AnewtURLDispatcher processes an incoming request. The section on routes below explains how routes work in more detail.

Getting Started

Getting started with AnewtURLDispatcher is not hard. You define the URLs you want your application to respond to, and implement the corresponding commands. It is really straight-forward:

Setting up clean URLs for the Apache web server can be done using this .htaccess snippet. This instructs Apache to invoke dispatch.php for all URLs that do not point to an existing file (such as a static HTML page or image files, which are not served through the dispatcher).

  1.  RewriteEngine On
  2.  RewriteBase /the/base/url/of/your/application
  3.  
  4.  RewriteRule ^$ dispatch.php [L,QSA]
  5.  
  6.  RewriteCond %{REQUEST_FILENAME} !-f
  7.  RewriteCond %{REQUEST_FILENAME} !-d
  8.  RewriteRule ^(.*) dispatch.php [L,QSA]

Since AnewtURLDispatcher takes care of the complete request, the only thing the dispatch.php file should do is something like this:

  1.  // Load the relevant classes here...
  2.  $d = new YourDispatcher();
  3.  $d->dispatch();

Handling Errors

If no command to execute can be found, e.g. because none of the routes match, an AnewtHTTPException will be thrown. Additionally, if you want to raise an error from your command, e.g. because a requested database record does not exists, you can throw an AnewtHTTPException yourself. This will cause a ‘HTTP 404 Not Found’ error page to be shown. Example:

  1.  if ($something_could_not_be_found)
  2.      throw AnewtHTTPException(
  3.          HTTP_STATUS_NOT_FOUND,
  4.          'The requested news item does not exists.');

To create your own error handlers, override the error handling methods, e.g. handle_error_not_found(). See below for more information.

Properties

The following properties influence how AnewtURLDispatcher behaves:

When a command is invoked, you can use the following properties to get the URLs of the current request:

For routes based on URL parts, constraints that should apply to all routes (instead of to just one route) can be configured:

Public Methods

__construct()

Construct a new AnewtURLDispatcher instance.

Make sure you call this method from derived classes!

Route Methods

Routes define how URLs map to commands. Whenever a route matches the request, the corresponding command is invoked to handle the request. Command methods get passed a $parameters argument containing values for parameters that were defined when setting up the route (either regular expression matches, or named parameters, depending on the type of URL route).

Incoming requests will be matched against all defined routes, until a route matches the current request, in which case the associated command is invoked. The routes are tried in the order in which they are added to the dispatcher. Therefore you should add more specific routes before more general routes.

If you decide to use automatic commands, those will be tried if none of the explicitly defined routes matched the request. See the automatic-commands property description for more details on this feature.

In addition to explicitly created routes, you can also add a default command that will be invoked if none of the routes match. The default command will be invoked if none of the provided URL routes (both explicit routes and automatic commands, if enabled) match the request URL. This method can be used to supply default functionality. Note that this is not the right way to handle errors; use handle_error_not_found() or one of the other error callbacks instead.

Two types of routes can be used (read on for an explanation on both):

  1. using regular expressions
  2. using URL parts

Regular expression routes use a regular expression to match an URL, and can be added using AnewtURLDispatcher::add_route_regex(). The URL that is used for matching does not contain a leading /, so you should not specify this in the regular expression.

To extract parameters from the URL, the $parameters array passed to the command contains the matches from preg_match(), i.e. the parenthesized expressions. Parameters can have names (instead of numbers) by using named matches, e.g. (?P<year>\d{4}). See below for more information about how regular expressions are used.

Examples for routes using regular expressions:

  1.  $this->add_route_regex('latest_news''#^news$#');
  2.  $this->add_route_regex('month_archive''#^news/(\\d{4})$#');
  3.  $this->add_route_regex('month_archive''#^news/(?P<year>\\d{4})/(?P<month>\\d{1,2})$#');

Routes based on URL parts are the other way to define URL routes. These routes can be added using AnewtURLDispatcher::add_route_url_parts(). To define a route, you can provide either a URL string, or an array of URL parts. An URL part corresponds to a "path component" in the URL, e.g. the URL /news/2009/06/ consists of three parts.

For routes based on URL parts, parameters can be specified using a : character before the parameter name, e.g. :year The constraints used for the parameters are regular expressions that will be matched using preg_match(). If no constraint is specified for a parameter, no checking is performed (any value is accepted). See below for more information about how regular expressions are used.

Examples for routes using URL parts:

  1.  $this->constraints = array('year' => '#^\\d{4}$#''month' => '#^\\d{1,2}$#');
  2.  $this->add_route_url_parts('latest_news''news');
  3.  $this->add_route_url_parts('month_archive''news/:year/:month/');
  4.  $this->add_route_url_parts('month_archive', array('news'':year'':month'));

Constraints should be provided as an associative array that maps parameter names to regular expressions. The constraints in the constraints property apply to all routes using URL parts, but can be overridden by specifying additional constraints when calling AnewtURLDispatcher::add_route_url_parts().

Note about the regular expressions used for URL and parameter matching: the pattern is passed directly to preg_match(). Make sure to include ^ and $ appropriately to match the full string, since otherwise you might match URLs that you do not want to match! Hint: use a # character for the regular expression delimiter, since the often-used / is confusing because it is a common character in URLs. (A literal # cannot occur in URLs anyway since it is used for the client-side fragment specifier.)

add_route_regex($command, $regex)

Add a route based on a regular expression.

Parameters

$command

The command to execute when this route matches.

$regex

The regular expression to match against the URL.

See also

add_route_url_parts($command, $url_parts, $additional_constraints=null)

Add a route based on URL parts.

Parameters

$command

The command to execute when this route matches.

$url_parts

Array with the URL parts, or a URL string. Variable parts (parameters) can be specified using a : character, e.g. :year

$additional_constraints

Associative array with constraints specific to this route. These are applied on top of the default constraints that can be set using the constraints property on the AnewtURLDispatcher instance.

See also

Dispatching Methods

dispatch($url=null, $prefix=null)

Dispatch an URL to the correct handlers.

Parameters

$url

The URL to dispatch (optional, defaults to null). In almost all cases you should not provide this URL to let the dispatcher figure out the current request URL and prefix.

$prefix

The prefix of the URL that should not be taken into account to match URL routes. The automatic detection works fine in almost all case, so you should likely omit this parameter.

See also

real_dispatch($url=null, $prefix=null) [private]

(Really) dispatch an URL to the correct handlers.

This method does the actual magic, such as URL parsing, matching and command invocation. You can optionally provide a custom URL and tell the dispatcher that some parts of the URL should be skipped when handling this request.

Parameters

$url

$prefix

See also

Callback Methods

pre_command($parameters) [protected]

Called before the actual command is invoked.

This method does nothing by default.

Parameters

$parameters

The parameters array, as passed to the command.

post_command($parameters) [protected]

Called after the command has completed succesfully.

Note that this method may or may not be called depending on the succcesful completion of pre_command() and real command method.

This method does nothing by default.

Parameters

$parameters

The parameters array, as passed to the command.

Error Handling Methods

A command may throw an AnewtHTTPException (or another exception) to indicate something went wrong during the request. In this case, AnewtURLDispatcher::dispatch() will invoke the AnewtURLDispatcher::handle_error() method with the exception that was thrown.

The common "HTTP 404 Not Found" and "HTTP 403 Forbidden" cases have their own convenience error handler methods that you can override: AnewtURLDispatcher::handle_error_not_found() and AnewtURLDispatcher::handle_error_forbidden(). All other errors are passed directly to AnewtURLDispatcher::handle_error().

handle_error($exception) [protected]

Handle dispatcher errors.

Override this method for custom error handling.

Parameters

$exception

The exception to be handled.

See also

handle_error_not_found($exception) [protected]

Handle 'Not Found' errors.

Override this method for custom error handling. The default implementation just propagates the error by calling AnewtURLDispatcher::handle_error().

Parameters

$exception

See also

handle_error_forbidden($exception) [protected]

Handle 'Forbidden' errors.

Override this method for custom error handling. The default implementation just propagates the error by calling AnewtURLDispatcher::handle_error().

Parameters

$exception

See also

show_error_page($exception) [protected]

Show a simple error page.

Parameters

$exception

The AnewtHTTPException instance

Private Attributes

$routes [private]

URL routes.

$url_part_constraints [private]

Constraints for URL parts.

This only applies to routes added using add_route_url_parts().

Inheritance

Base Classes

Inherited members