# The Request Object

## Introduction

The request object is a simple value object that is passed between `Zend_Controller_Front` and the router, dispatcher, and controller classes. It packages the names of the requested module, controller, action, and optional parameters, as well as the rest of the request environment, be it HTTP, the CLI, or PHP-GTK.

- The module name is accessed by `getModuleName()` and `setModuleName()`.

- The controller name is accessed by `getControllerName()` and `setControllerName()`.

- The name of the action to call within that controller is accessed by `getActionName()` and `setActionName()`.

- Parameters to be accessible by the action are an associative array of key and value pairs that are retrieved by `getParams()` and set with `setParams()`, or individually by `getParam()` and `setParam()`.

Based on the type of request, there may be more methods available. The default request used, `Zend_Controller_Request_Http`, for instance, has methods for retrieving the request URI, path information, `$_GET` and `$_POST` parameters, etc.

The request object is passed to the front controller, or if none is provided, it is instantiated at the beginning of the dispatch process, before routing occurs. It is passed through to every object in the dispatch chain.

Additionally, the request object is particularly useful in testing. The developer may craft the request environment, including module, controller, action, parameters, URI, etc, and pass the request object to the front controller to test application flow. When paired with the response object, elaborate and precise unit testing of MVC applications becomes possible.

## HTTP Requests

### Accessing Request Data

`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. 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()` and `getParam()` methods to set or retrieve user parameters.

#### Superglobal Data

When accessing superglobal data through `Zend_Controller_Request_Http` as public member properties, it is necessary to keep in mind that the property name (superglobal array key) is matched to a superglobal in a specific order of precedence: 1. `GET`, 2. `POST`, 3. `COOKIE`, 4. `SERVER`, 5. `ENV`.

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. These include `getQuery()` for retrieving `$_GET` elements, and `getHeader()` for retrieving request headers.

#### GET and POST Data

Be cautious when accessing data from the request object as it is not filtered in any way. The router and dispatcher validate and filter data for use with their tasks, but leave the data untouched in the request object.

#### Retrieving the Raw POST Data

As of 1.5.0, you can also retrieve the raw post data via the `getRawBody()` method. This method returns `FALSE` if no data was submitted in that fashion, but the full body of the post otherwise.

This is primarily useful for accepting content when developing a RESTful MVC application.

You may also set user parameters in the request object using `setParam()` and retrieve these later using `getParam()`. The router makes use of this functionality to set parameters matched in the request URI into the request object.

#### getParam() Retrieves More than User Parameters

In order to do some of its work, `getParam()` actually retrieves from several sources. In order of priority, these include: user parameters set via `setParam()`, `GET` parameters, and finally `POST` parameters. Be aware of this when pulling data via this method.

If you wish to pull only from parameters you set via `setParam()`, use the `getUserParam()`.

Additionally, as of 1.5.0, you can lock down which parameter sources will be searched. `setParamSources()` allows you to specify an empty array or an array with one or more of the values '_GET' or '_POST' indicating which parameter sources are allowed (by default, both are allowed); if you wish to restrict access to only '_GET' specify `setParamSources(array('_GET'))`.

#### Apache Quirks

If you are using Apache's 404 handler to pass incoming requests to the front controller, or using a PT flag with rewrite rules, `$_SERVER['REDIRECT_URL']` contains the URI you need, not `$_SERVER['REQUEST_URI']`. If you are using such a setup and getting invalid routing, you should use the `Zend_Controller_Request_Apache404` class instead of the default Http class for your request object:

    $request = new Zend_Controller_Request_Apache404();
    $front->setRequest($request);

This class extends the `Zend_Controller_Request_Http` class and simply modifies the autodiscovery of the request URI. It can be used as a drop-in replacement.

### Base Url and Subdirectories

`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, an exception will be raised.

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();

### Determining the Request Method

`getMethod()` allows you to determine the HTTP request method used to request the current resource. Additionally, a variety of methods exist that allow you to get boolean responses when asking if a specific type of request has been made:

- `isGet()`

- `isPost()`

- `isPut()`

- `isDelete()`

- `isHead()`

- `isOptions()`

The primary use case for these is for creating RESTful MVC architectures.

### Detecting AJAX Requests

`Zend_Controller_Request_Http` has a rudimentary method for detecting AJAX requests: `isXmlHttpRequest()`. This method looks for an HTTP request header X-Requested-With with the value 'XMLHttpRequest'; if found, it returns `TRUE`.

Currently, this header is known to be passed by default with the following JS libraries:

- Prototype and Scriptaculous (and libraries derived from Prototype)

- Yahoo! UI Library

- jQuery

- MochiKit

Most AJAX libraries allow you to send custom HTTP request headers; if your library does not send this header, simply add it as a request header to ensure the `isXmlHttpRequest()` method works for you.

## Subclassing the Request Object

The base request class used for all request objects is the abstract class `Zend_Controller_Request_Abstract`. At its most basic, it defines the following methods:

    abstract class Zend_Controller_Request_Abstract
    {
        /**
         * @return string
         */
        public function getControllerName();

        /**
         * @param string $value
         * @return self
         */
        public function setControllerName($value);

        /**
         * @return string
         */
        public function getActionName();

        /**
         * @param string $value
         * @return self
         */
        public function setActionName($value);

        /**
         * @return string
         */
        public function getControllerKey();

        /**
         * @param string $key
         * @return self
         */
        public function setControllerKey($key);

        /**
         * @return string
         */
        public function getActionKey();

        /**
         * @param string $key
         * @return self
         */
        public function setActionKey($key);

        /**
         * @param string $key
         * @return mixed
         */
        public function getParam($key);

        /**
         * @param string $key
         * @param mixed $value
         * @return self
         */
        public function setParam($key, $value);

        /**
         * @return array
         */
         public function getParams();

        /**
         * @param array $array
         * @return self
         */
        public function setParams(array $array);

        /**
         * @param boolean $flag
         * @return self
         */
        public function setDispatched($flag = true);

        /**
         * @return boolean
         */
        public function isDispatched();
    }

The request object is a container for the request environment. The controller chain really only needs to know how to set and retrieve the controller, action, optional parameters, and dispatched status. By default, the request will search its own parameters using the controller or action keys in order to determine the controller and action.

Extend this class, or one of its derivatives, when you need the request class to interact with a specific environment in order to retrieve data for use in the above tasks. Examples include the HTTP environment, a CLI environment, or a PHP-GTK environment.