Page contents

Request and Response objects

New in CakePHP 2.0 are request and response objects. In previous versions these objects were represented through arrays, and the related methods were spread across RequestHandlerComponent, Router, Dispatcher and Controller. There was no authoritative object on what information the request contained. For 2.0, CakeRequest and CakeResponse are used for this purpose.

CakeRequest

CakeRequest is the default request object used in CakePHP. It centralizes a number of features for interrogating and interacting with request data. On each request one CakeRequest is created and then passed by reference to the various layers of an application that use request data. By default CakeRequest is assigned to $this->request, and is available in Controller, Views and Helpers. You can also access it in Components by using the controller reference. Some of the duties CakeRequest performs include:

  • Process the GET, POST, and FILES arrays into the data structures you are familiar with.
  • Provide environment introspection pertaining to the request. Things like the headers sent, the client’s IP address, and the subdomain/domain information about the application the server is running on.
  • Provide access to request parameters both as array indices and object properties.

Accessing request parameters

CakeRequest exposes several interfaces for accessing request parameters. The first is as array indexes, the second is through $this->request->params, and the third is as object properties:

<?php
$this->request['controller'];
$this->request->controller;
$this->request->params['controller'];

All of the above will both access the same value. Multiple ways of accessing the parameters was done to ease migration for existing applications. All Route elements are accessed through this interface.

In addition to Route elements you also often need access to Passed arguments and Named parameters. These are both available on the request object as well:

<?php
// Passed arguments
$this->request['pass'];
$this->request->pass;
$this->request->params['pass'];

// named parameters
$this->request['named'];
$this->request->named;
$this->request->params['named'];

Will all provide you access to the passed arguments and named parameters. There are several important/useful parameters that CakePHP uses internally, these are also all found in the request parameters:

  • plugin The plugin handling the request, will be null for no plugin.
  • controller The controller handling the current request.
  • action The action handling the current request.
  • prefix The prefix for the current action. See Prefix Routing for more information.
  • bare Present when the request came from requestAction() and included the bare option. Bare requests do not have layouts rendered.
  • requested Present and set to true when the action came from requestAction.

Accessing Querystring parameters

Querystring parameters can be read from using CakeRequest::$query:

<?php
// url is /posts/index?page=1&sort=title
$this->request->query['page'];

// You can also access it via array access
$this->request['url']['page'];

Accessing POST data

All POST data can be accessed using CakeRequest::$data. Any form data that contains a data prefix, will have that data prefix removed. For example:

<?php
// An input with a name attribute equal to 'data[Post][title]' is accessible at
$this->request->data['Post']['title'];

You can either directly access the data property, or you can use CakeRequest::data() to read the data array in an error free manner. Any keys that do not exist will return null:

<?php
$foo = $this->request->data('Value.that.does.not.exist');
// $foo == null

Accessing PUT or POST data

New in version 2.2.

When building REST services you often accept request data on PUT and DELETE requests. As of 2.2 any application/x-www-form-urlencoded request body data will automatically be parsed and set to $this->data for PUT and DELETE requests. If you are accepting JSON or XML data, see below for how you can access those request bodies.

Accessing XML or JSON data

Applications employing REST often exchange data in non URL encoded post bodies. You can read input data in any format using CakeRequest::input(). By providing a decoding function you can receive the content in a deserialized format:

<?php
// Get JSON encoded data submitted to a PUT/POST action
$data = $this->request->input('json_decode');

Since some deserializing methods require additional parameters when being called, such as the ‘as array’ parameter on json_decode or if you want XML converted into a DOMDocument object, CakeRequest::input() supports passing in additional parameters as well:

<?php
// Get Xml encoded data submitted to a PUT/POST action
$data = $this->request->input('Xml::build', array('return' => 'domdocument'));

Accessing path information

CakeRequest also provides useful information about the paths in your application. CakeRequest::$base and CakeRequest::$webroot are useful for generating urls, and determining whether or not your application is in a subdirectory.

Inspecting the request

Detecting various request conditions used to require using RequestHandlerComponent. These methods have been moved to CakeRequest, and offer a new interface alongside a more backwards compatible usage:

<?php
$this->request->is('post');
$this->request->isPost();

Both method calls will return the same value. For the time being the methods are still available on RequestHandler, but are deprecated and still might be removed before the final release. You can also easily extend the request detectors that are available, by using CakeRequest::addDetector() to create new kinds of detectors. There are four different types of detectors that you can create:

  • Environment value comparison - An environment value comparison, compares a value fetched from env() to a known value the environment value is equality checked against the provided value.
  • Pattern value comparison - Pattern value comparison allows you to compare a value fetched from env() to a regular expression.
  • Option based comparison - Option based comparisons use a list of options to create a regular expression. Subsequent calls to add an already defined options detector will merge the options.
  • Callback detectors - Callback detectors allow you to provide a ‘callback’ type to handle the check. The callback will receive the request object as its only parameter.

Some examples would be:

<?php
// Add an environment detector.
$this->request->addDetector('post', array('env' => 'REQUEST_METHOD', 'value' => 'POST'));

// Add a pattern value detector.
$this->request->addDetector('iphone', array('env' => 'HTTP_USER_AGENT', 'pattern' => '/iPhone/i'));

// Add an option detector
$this->request->addDetector('internalIp', array(
    'env' => 'CLIENT_IP',
    'options' => array('192.168.0.101', '192.168.0.100')
));

// Add a callback detector. Can either be an anonymous function or a regular callable.
$this->request->addDetector('awesome', array('callback' => function ($request) {
    return isset($request->awesome);
}));

CakeRequest also includes methods like CakeRequest::domain(), CakeRequest::subdomains() and CakeRequest::host() to help applications with subdomains, have a slightly easier life.

There are several built-in detectors that you can use:

  • is('get') Check to see if the current request is a GET.
  • is('put') Check to see if the current request is a PUT.
  • is('post') Check to see if the current request is a POST.
  • is('delete') Check to see if the current request is a DELETE.
  • is('head') Check to see if the current request is HEAD.
  • is('options') Check to see if the current request is OPTIONS.
  • is('ajax') Check to see of the current request came with X-Requested-with = XmlHttpRequest.
  • is('ssl') Check to see if the request is via SSL
  • is('flash') Check to see if the request has a User-Agent of Flash
  • is('mobile') Check to see if the request came from a common list of mobile agents.

CakeRequest and RequestHandlerComponent

Since many of the features CakeRequest offers used to be the realm of RequestHandlerComponent some rethinking was required to figure out how it still fits into the picture. For 2.0, RequestHandlerComponent acts as a sugar daddy. Providing a layer of sugar on top of the utility CakeRequest affords. Sugar like switching layout and views based on content types or ajax is the domain of RequestHandlerComponent. This separation of utility and sugar between the two classes lets you more easily pick and choose what you want and what you need.

Interacting with other aspects of the request

You can use CakeRequest to introspect a variety of things about the request. Beyond the detectors, you can also find out other information from various properties and methods.

  • $this->request->webroot contains the webroot directory.
  • $this->request->base contains the base path.
  • $this->request->here contains the full address to the current request
  • $this->request->query contains the query string parameters.

CakeRequest API

class CakeRequest

CakeRequest encapsulates request parameter handling, and introspection.

CakeRequest::domain()

Returns the domain name your application is running on.

CakeRequest::subdomains()

Returns the subdomains your application is running on as an array.

CakeRequest::host()

Returns the host your application is on.

CakeRequest::method()

Returns the HTTP method the request was made with.

CakeRequest::referer()

Returns the referring address for the request.

CakeRequest::clientIp()

Returns the current visitor’s IP address.

CakeRequest::input($callback[, $options])

Retrieve the input data for a request, and optionally pass it through a decoding function. Additional parameters for the decoding function can be passed as arguments to input().

CakeRequest::data($key)

Provides dot notation access to request data. Allows for reading and modification of request data, calls can be chained together as well:

<?php
// Modify some request data, so you can prepopulate some form fields.
$this->request->data('Post.title', 'New post')
    ->data('Comment.1.author', 'Mark');

// You can also read out data.
$value = $this->request->data('Post.title');
CakeRequest::is($check)

Check whether or not a Request matches a certain criteria. Uses the built-in detection rules as well as any additional rules defined with CakeRequest::addDetector().

CakeRequest::addDetector($name, $callback)

Add a detector to be used with is(). See Inspecting the request for more information.

CakeRequest::accepts($type)

Find out which content types the client accepts or check if they accept a particular type of content.

Get all types:

<?php
$this->request->accepts();

Check for a single type:

<?php
$this->request->accepts('application/json');
static CakeRequest::acceptLanguage($language)

Get either all the languages accepted by the client, or check if a specific language is accepted.

Get the list of accepted languages:

<?php
CakeRequest::acceptLanguage();

Check if a specific language is accepted:

<?php
CakeRequest::acceptLanguage('es-es');
property CakeRequest::$data

An array of POST data. You can use CakeRequest::data() to read this property in a way that suppresses notice errors.

property CakeRequest::$query

An array of query string parameters.

property CakeRequest::$params

An array of route elements and request parameters.

property CakeRequest::$here

Returns the current request uri.

property CakeRequest::$base

The base path to the application, usually / unless your application is in a subdirectory.

property CakeRequest::$webroot

The current webroot.

CakeResponse

CakeResponse is the default response class in CakePHP. It encapsulates a number of features and functionality for generating HTTP responses in your application. It also assists in testing, as it can be mocked/stubbed allowing you to inspect headers that will be sent. Like CakeRequest, CakeResponse consolidates a number of methods previously found on Controller, RequestHandlerComponent and Dispatcher. The old methods are deprecated in favour of using CakeResponse.

CakeResponse provides an interface to wrap the common response related tasks such as:

  • Sending headers for redirects.
  • Sending content type headers.
  • Sending any header.
  • Sending the response body.

Changing the response class

CakePHP uses CakeResponse by default. CakeResponse is a flexible and transparent to use class. But if you need to replace it with an application specific class, you can override and replace CakeResponse with your own class. By replacing the CakeResponse used in index.php.

This will make all the controllers in your application use CustomResponse instead of CakeResponse. You can also replace the response instance used by setting $this->response in your controllers. Overriding the response object is handy during testing, as it allows you to stub out the methods that interact with header(). See the section on CakeResponse and testing for more information.

Dealing with content types

You can control the Content-Type of your application’s responses with using CakeResponse::type(). If your application needs to deal with content types that are not built into CakeResponse, you can map those types with type() as well:

<?php
// Add a vCard type
$this->response->type(array('vcf' => 'text/v-card'));

// Set the response Content-Type to vcard.
$this->response->type('vcf');

Usually you’ll want to map additional content types in your controller’s beforeFilter callback, so you can leverage the automatic view switching features of RequestHandlerComponent if you are using it.

Sending attachments

There are times when you want to send Controller responses as files for download. You can either accomplish this using Media Views or by using the features of CakeResponse. CakeResponse::download() allows you to send the response as file for download:

<?php
public function sendFile($id) {
    $this->autoRender = false;

    $file = $this->Attachment->getFile($id);
    $this->response->type($file['type']);
    $this->response->download($file['name']);
    $this->response->body($file['content']);
}

The above shows how you could use CakeResponse to generate a file download response without using MediaView. In general you will want to use MediaView as it provides a few additional features above what CakeResponse does.

Setting headers

Setting headers is done with the CakeResponse::header() method. It can be called with a few different parameter configurations:

<?php
// Set a single header
$this->response->header('Location', 'http://example.com');

// Set multiple headers
$this->response->header(array('Location' => 'http://example.com', 'X-Extra' => 'My header'));
$this->response->header(array('WWW-Authenticate: Negotiate', 'Content-type: application/pdf'));

Setting the same header multiple times will result in overwriting the previous values, just like regular header calls. Headers are not sent when CakeResponse::header() is called either. They are just buffered until the response is actually sent.

Interacting with browser caching

You sometimes need to force browsers to not cache the results of a controller action. CakeResponse::disableCache() is intended for just that:

<?php
public function index() {
    // do something.
    $this->response->disableCache();
}

Warning

Using disableCache() with downloads from SSL domains while trying to send files to Internet Explorer can result in errors.

You can also tell clients that you want them to cache responses. By using CakeResponse::cache():

<?php
public function index() {
    //do something
    $this->response->cache('-1 minute', '+5 days');
}

The above would tell clients to cache the resulting response for 5 days, hopefully speeding up your visitors’ experience. cache() sets the Last-Modified value to the first argument. Expires, and Max-age are set based on the second parameter. Cache-Control is set to public as well.

Fine tuning HTTP cache

One of the best and easiest ways of speeding up your application is using HTTP cache. Under this caching model you are only required to help clients decide if they should use a cached copy of the response by setting a few headers such as modified time, response entity tag and others.

Opposed to having to code the logic for caching and for invalidating (refreshing) it once the data has changed, HTTP uses two models, expiration and validation which usually are a lot simpler than having to manage the cache yourself.

Apart from using CakeResponse::cache() you can also use many other methods to fine tune HTTP cache headers to take advantage of browser or reverse proxy caching.

The Cache Control header

New in version 2.1.

Used under the expiration model, this header contains multiple indicators which can change the way browsers or proxies use the cached content. A Cache-Control header can look like this:

Cache-Control: private, max-age=3600, must-revalidate

CakeResponse class helps you set this header with some utility methods that will produce a final valid Cache-Control header. First of them is CakeResponse::sharable() method, which indicates whether a response in to be considered sharable across different users or clients or users. This method actually controls the public or private part of this header. Setting a response as private indicates that all or part of it is intended for a single user. To take advantage of shared caches it is needed to set the control directive as public

Second parameter of this method is used to specify a max-age for the cache, which is the number of seconds after which the response is no longer considered fresh.:

<?php
public function view() {
    ...
    // set the Cache-Control as public for 3600 seconds
    $this->response->sharable(true, 3600);
}

public function my_data() {
    ...
    // set the Cache-Control as private for 3600 seconds
    $this->response->sharable(false, 3600);
}

CakeResponse exposes separate methods for setting each of the components in the Cache-Control header.

The Expiration header

New in version 2.1.

Also under the cache expiration model, you can set the Expires header, which according to the HTTP specification is the date/time after which the response is no longer considered fresh. This header can be set using the CakeResponse::expires() method:

<?php
public function view() {
    $this->response->expires('+5 days');
}

This method also accepts a DateTime or any string that can be parsed by the DateTime class.

The Etag header

New in version 2.1.

Cache validation in HTTP is often used when content is constantly changing, and asks the application to only generate the response contents if the cache is no longer fresh. Under this model, the client continues to store pages in the cache, but instead of using it directly, it asks the application every time whether the resources changed or not. This is commonly used with static resources such as images and other assets.

The Etag header (called entity tag) is string that uniquely identifies the requested resource. It is very much like the checksum of a file, caching will compare checksums to tell whether they match or not.

To actually get advantage of using this header you have to either call manually CakeResponse::checkNotModified() method or have the RequestHandlerComponent included in your controller:

<?php
public function index() {
    $articles = $this->Article->find('all');
    $this->response->etag($this->Article->generateHash($articles));
    if ($this->response->checkNotModified($this->request)) {
        return $this->response;
    }
    ...
}

The Last Modified header

New in version 2.1.

Also under the HTTP cache validation model, you can set the Last-Modified header to indicate the date and time at which the resource was modified for the last time. Setting this header helps CakePHP respond to caching clients whether the response was modified or not based on the client cache.

To actually get advantage of using this header you have to either call manually CakeResponse::checkNotModified() method or have the RequestHandlerComponent included in your controller:

<?php
public function view() {
    $article = $this->Article->find('first');
    $this->response->modified($article['Article']['modified']);
    if ($this->response->checkNotModified($this->request)) {
        return $this->response;
    }
    ...
}

The Vary header

In some cases you might want to serve different contents using the same url. This is often the case when you have a multilingual page or respond with different HTML according to the browser that is requesting the resource. For such circumstances, you use the Vary header:

<?php
    $this->response->vary('User-Agent');
    $this->response->vary('Accept-Encoding', 'User-Agent');
    $this->response->vary('Accept-Language');

CakeResponse and testing

Probably one of the biggest wins from CakeResponse comes from how it makes testing controllers and components easier. Instead of methods spread across several objects, you only have a single object to mock as controllers and components delegate to CakeResponse. This helps you get closer to a ‘unit’ test and makes testing controllers easier:

<?php
public function testSomething() {
    $this->controller->response = $this->getMock('CakeResponse');
    $this->controller->response->expects($this->once())->method('header');
    // ...
}

Additionally you can more easily run tests from the command line, as you can use mocks to avoid the ‘headers sent’ errors that can come up from trying to set headers in CLI.

CakeResponse API

class CakeResponse

CakeResponse provides a number of useful methods for interacting with the response you are sending to a client.

CakeResponse::header()

Allows you to directly set one or many headers to be sent with the response.

CakeResponse::charset()

Sets the charset that will be used in the response.

CakeResponse::type($type)

Sets the content type for the response. You can either use a known content type alias or the full content type name.

CakeResponse::cache()

Allows you to set caching headers in the response.

CakeResponse::disableCache()

Sets the headers to disable client caching for the response.

CakeResponse::sharable($isPublic, $time)

Sets the Cache-Control header to be either public or private and optionally sets a max-age directive of the resource

New in version 2.1.

CakeResponse::expires($date)

Allows to set the Expires header to a specific date.

New in version 2.1.

CakeResponse::etag($tag, $weak)

Sets the Etag header to uniquely identify a response resource.

New in version 2.1.

CakeResponse::modified($time)

Sets the Last-Modified header to a specific date and time in the correct format.

New in version 2.1.

CakeResponse::checkNotModified(CakeRequest $request)

Compares the cache headers for the request object with the cache header from the response and determines if it can still be considered fresh. In that case deletes any response contents and sends the 304 Not Modified header.

New in version 2.1.

CakeResponse::compress()

Turns on gzip compression for the request.

CakeResponse::download()

Allows you to send the response as an attachment and set the filename.

CakeResponse::statusCode()

Allows you to set the status code for the response.

CakeResponse::body()

Set the content body for the response.

CakeResponse::send()

Once you are done creating a response, calling send() will send all the set headers as well as the body. This is done automatically at the end of each request by Dispatcher