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 Controllers, 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 indexes and object
properties.
Accessing request parameters
CakeRequest
exposes several interfaces for accessing request parameters. The first uses object
properties, the second uses array indexes, and the third uses $this->request->params
:
$this->request->controller;
$this->request['controller'];
$this->request->params['controller'];
All of the above will access the same value. Multiple ways of accessing the
parameters have been provided 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:
// Passed arguments
$this->request->pass;
$this->request['pass'];
$this->request->params['pass'];
// named parameters
$this->request->named;
$this->request['named'];
$this->request->params['named'];
All of these will 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 when there is 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 using CakeRequest::$query
:
// URL is /posts/index?page=1&sort=title
$this->request->query['page'];
// You can also access it via an array
// Note: BC accessor, will be deprecated in future versions
$this->request['url']['page'];
You can either directly access the $query
property, or you can use
CakeRequest::query()
to read the URL query array in an error-free manner.
Any keys that do not exist will return null
:
$foo = $this->request->query('value_that_does_not_exist');
// $foo === null
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:
// An input with a name attribute equal to 'data[MyModel][title]'
// is accessible at
$this->request->data['MyModel']['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
:
$foo = $this->request->data('Value.that.does.not.exist');
// $foo == null
Accessing PUT or POST data
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:
// Get JSON encoded data submitted to a PUT/POST action
$data = $this->request->input('json_decode');
Some deserializing methods require additional parameters when called,
such as the ‘as array’ parameter on json_decode
. If you want XML converted
into a DOMDocument object, CakeRequest::input()
supports passing
in additional parameters as well:
// Get Xml encoded data submitted to a PUT/POST action
$data = $this->request->input('Xml::build', array('return' => 'domdocument'));
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:
$this->request->is('post');
$this->request->isPost(); // deprecated
Both method calls will return the same value. For the time being, the methods
are still available on RequestHandlerComponent
, but are deprecated and
will be removed in 3.0.0. 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 - Compares a
value fetched from env()
for equality
with 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:
// 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.
There are several built-in detectors that you can use:
is('get')
Check to see whether the current request is a GET.
is('put')
Check to see whether the current request is a PUT.
is('post')
Check to see whether the current request is a POST.
is('delete')
Check to see whether the current request is a DELETE.
is('head')
Check to see whether the current request is HEAD.
is('options')
Check to see whether the current request is OPTIONS.
is('ajax')
Check to see whether the current request came with
X-Requested-With = XMLHttpRequest.
is('ssl')
Check to see whether the request is via SSL
is('flash')
Check to see whether the request has a User-Agent of Flash
is('mobile')
Check to see whether 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
provides a layer of sugar, such as switching layout
and views based on content, on top of the utility that
CakeRequest
affords.
This separation of utility and sugar between the two classes lets you
more easily choose what you want.
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($tldLength = 1)
Returns the domain name your application is running on.
-
CakeRequest::subdomains($tldLength = 1)
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::onlyAllow($methods)
Set allowed HTTP methods. If not matched, will throw MethodNotAllowedException.
The 405 response will include the required Allow
header with the passed methods
-
CakeRequest::allowMethod($methods)
Set allowed HTTP methods. If not matched will throw MethodNotAllowedException.
The 405 response will include the required Allow
header with the passed methods
-
CakeRequest::referer($local = false)
Returns the referring address for the request.
-
CakeRequest::clientIp($safe = true)
Returns the current visitor’s IP address.
Allows you to access any of the HTTP_*
headers that were used
for the request. For example:
$this->request->header('User-Agent');
would return the user agent used for the request.
-
CakeRequest::input($callback[, $options])
Retrieve the input data for a request, and optionally pass it through a
decoding function. Useful when interacting with XML or JSON
request body content. Additional parameters for the decoding function
can be passed as arguments to input():
$this->request->input('json_decode');
-
CakeRequest::data($name)
Provides dot notation access to request data. Allows request data to be read and
modified. Calls can be chained together as well:
// 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::query($name)
Provides dot notation access to URL query data:
// URL is /posts/index?page=1&sort=title
$value = $this->request->query('page');
-
CakeRequest::is($type)
Check whether or not a Request matches a certain criterion. Uses
the built-in detection rules as well as any additional rules defined
with CakeRequest::addDetector()
.
-
CakeRequest::addDetector($name, $options)
Add a detector to be used with CakeRequest::is()
. See Inspecting the request
for more information.
-
CakeRequest::accepts($type = null)
Find out which content types the client accepts, or check whether it accepts a
particular type of content.
Get all types:
$this->request->accepts();
Check for a single type:
$this->request->accepts('application/json');
-
static CakeRequest::acceptLanguage($language = null)
Get all the languages accepted by the client,
or check whether a specific language is accepted.
Get the list of accepted languages:
CakeRequest::acceptLanguage();
Check whether a specific language is accepted:
CakeRequest::acceptLanguage('es-es');
-
CakeRequest::param($name)
Safely read values in $request->params
. This removes the need to call
isset()
or empty()
before using param values.
-
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 class. If you need to override it with your own application-specific class,
you can replace CakeResponse
in app/webroot/index.php
.
This will make all the controllers in your application use CustomResponse
instead of CakeResponse
. You can also replace the response
instance 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
CakeResponse::type()
. If your application needs to deal with
content types that are not built into CakeResponse
, you can map them
with CakeResponse::type()
as well:
// 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 files
There are times when you want to send files as responses for your requests.
Prior to version 2.3, you could use MediaView
.
As of 2.3, MediaView
is deprecated and you can use CakeResponse::file()
to send a file as response:
public function sendFile($id) {
$file = $this->Attachment->getFile($id);
$this->response->file($file['path']);
// Return response object to prevent controller from trying to render
// a view
return $this->response;
}
As shown in the above example, you must pass the file path to the method.
CakePHP will send a proper content type header if it’s a known file type listed in
CakeResponse::$_mimeTypes
. You can add new types prior to calling CakeResponse::file()
by using the CakeResponse::type()
method.
If you want, you can also force a file to be downloaded instead of displayed in
the browser by specifying the options:
$this->response->file(
$file['path'],
array('download' => true, 'name' => 'foo')
);
Sending a string as file
You can respond with a file that does not exist on the disk, such as
a pdf or an ics generated on the fly from a string:
public function sendIcs() {
$icsString = $this->Calendar->generateIcs();
$this->response->body($icsString);
$this->response->type('ics');
//Optionally force file download
$this->response->download('filename_for_download.ics');
// Return response object to prevent controller from trying to render
// a view
return $this->response;
}
Interacting with browser caching
You sometimes need to force browsers not to cache the results of a controller
action. CakeResponse::disableCache()
is intended for just that:
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()
:
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. CakeResponse::cache()
sets the
Last-Modified
value to the first argument.
Expires
header and the max-age
directive are set based on the second parameter.
Cache-Control’s public
directive is set as well.
Fine tuning HTTP cache
One of the best and easiest ways of speeding up your application is to use 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 and response entity tag.
Rather than forcing you 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 much simpler to use.
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.
CakeResponse and testing
Probably one of the biggest wins from CakeResponse
comes from how it makes
testing controllers and components easier. Instead of having methods spread across
several objects, you only have to mock a single object, since controllers and
components delegate to CakeResponse
. This helps you to get closer to a unit
test and makes testing controllers easier:
public function testSomething() {
$this->controller->response = $this->getMock('CakeResponse');
$this->controller->response->expects($this->once())->method('header');
// ...
}
Additionally, you can run tests from the command line more easily, as you can use
mocks to avoid the ‘headers sent’ errors that can occur when 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.
Allows you to directly set one or more headers to be sent with the response.
-
CakeResponse::location($url = null)
Allows you to directly set the redirect location header to be sent with the response:
// Set the redirect location
$this->response->location('http://example.com');
// Get the current redirect location header
$location = $this->response->location();
-
CakeResponse::charset($charset = null)
Sets the charset that will be used in the response.
-
CakeResponse::type($contentType = null)
Sets the content type of the response. You can either use a known content
type alias or the full content type name.
-
CakeResponse::cache($since, $time = '+1 day')
Allows you to set caching headers in the response.
-
CakeResponse::disableCache()
Sets the headers to disable client caching for the response.
-
CakeResponse::sharable($public = null, $time = null)
Sets the Cache-Control
header to be either public
or private
and
optionally sets a max-age
directive of the resource
-
CakeResponse::expires($time = null)
Allows the Expires
header to be set to a specific date.
-
CakeResponse::etag($tag = null, $weak = false)
Sets the Etag
header to uniquely identify a response resource.
-
CakeResponse::modified($time = null)
Sets the Last-Modified
header to a specific date and time in the correct
format.
-
CakeResponse::checkNotModified(CakeRequest $request)
Compares the cache headers for the request object with the cache header from
the response and determines whether it can still be considered fresh. If so,
deletes the response content, and sends the 304 Not Modified header.
-
CakeResponse::compress()
Turns on gzip compression for the request.
-
CakeResponse::download($filename)
Allows you to send a response as an attachment, and to set its filename.
-
CakeResponse::statusCode($code = null)
Allows you to set the status code of the response.
-
CakeResponse::body($content = null)
Sets the content body of 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
.
-
CakeResponse::file($path, $options = array())
Allows you to set the Content-Disposition
header of a file either to display or to download.