Controllers. CakePHP CakePHP
Advertisement
Advertisement
CHAPTER 4
Controllers
Controllers are the ‘C’ in MVC. After routing has been applied and the correct controller has been found, your controller’s action is called. Your controller should handle interpreting the request data, making sure the correct models are called, and the right response or view is rendered. Controllers can be thought of as middle man between the Model and View. You want to keep your controllers thin, and your models fat. This will help you more easily reuse your code and makes your code easier to test.
Commonly, controllers are used to manage the logic around a single model. For example, if you were building a site for an on-line bakery, you might have a RecipesController and an IngredientsController managing your recipes and their ingredients. In CakePHP, controllers are named after the primary model they handle. It’s totally possible to have controllers work with more than one model as well.
Your application’s controllers extend
AppController class, which in turn extends the core
class.
The AppController class can be defined in
/app/Controller/AppController.php
and it should contain methods that are shared between all of your application’s controllers.
Controllers provide a number of methods which are called actions. Actions are methods on a controller that handle requests. By default all public methods on a controller are an action, and accessible from a url.
Actions are responsible for interpreting the request and creating the response. Usually responses are in the form of a rendered view, but there are other ways to create responses as well.
The App Controller
As stated in the introduction, the AppController class is the parent class to all of your application’s controllers. AppController itself extends the Controller class included in the CakePHP core library. As such,
AppController is defined in /app/Controller/AppController.php like so:
class AppController extends
Controller {
}
Controller attributes and methods created in your AppController will be available to all of your application’s controllers. It is the ideal place to create code that is common to all of your controllers. Components (which you’ll learn about later) are best used for code that is used in many (but not necessarily all) controllers.
43
CakePHP Cookbook Documentation, Release 2.x
While normal object-oriented inheritance rules apply, CakePHP does a bit of extra work when it comes to special controller attributes. The list of components and helpers used by a controller are treated specially.
In these cases, AppController value arrays are merged with child controller class arrays. The values in the child class will always override those in AppController.
Note: CakePHP merges the following variables from the AppController to your application’s controllers:
• $components
• $helpers
• $uses
Remember to add the default Html and Form helpers, if you define var $helpers in your AppController
Please also remember to call AppController’s callbacks within child controller callbacks for best results:
public function
beforeFilter () {
parent
:: beforeFilter ();
}
Request parameters
When a request is made to a CakePHP application, CakePHP’s
and Dispatcher classes use
to find and create the correct controller. The request data is encapsulated into a request object. CakePHP puts all of the important request information into the $this->request property. See the section on
for more information on the CakePHP request object.
Controller actions
Controller actions are responsible for converting the request parameters into a response for the browser/user making the request. CakePHP uses conventions to automate this process and remove some boiler-plate code you would otherwise need to write.
By convention CakePHP renders a view with an inflected version of the action name. Returning to our online bakery example, our RecipesController might contain the view(), share(), and search() actions.
The controller would be found in /app/Controller/RecipesController.php and contain:
# /app/Controller/RecipesController.php
class RecipesController extends
AppController {
public function
view ( $id ) {
//action logic goes here..
}
public function
share ( $customerId , $recipeId ) {
//action logic goes here..
}
44 Chapter 4. Controllers
CakePHP Cookbook Documentation, Release 2.x
public function
search ( $query ) {
//action logic goes here..
}
}
The view files for these actions would be app/View/Recipes/view.ctp
, app/View/Recipes/share.ctp
, and app/View/Recipes/search.ctp.
The conventional view file name is the lower cased and underscored version of the action name.
Controller actions generally use
to create a context that
uses to render the view. Because of the conventions that CakePHP uses, you don’t need to create and render the view manually. Instead once a controller action has completed, CakePHP will handle rendering and delivering the View.
If for some reason you’d like to skip the default behavior. Both of the following techniques will by-pass the default view rendering behavior.
• If you return a string, or an object that can be converted to a string from your controller action, it will be used as the response body.
• You can return a
object with the completely created response.
When controller methods are used with
you will often want to return data that isn’t a string. If you have controller methods that are used for normal web requests + requestAction you should check the request type before returning:
class RecipesController extends
AppController {
public function
popular () {
$popular = $this -> Recipe -> popular ();
if
( !
empty
( $this -> request -> params [ ’requested’ ])) {
return
$popular ;
}
$this -> set ( ’popular’ , $popular );
}
}
The above controller action is an example of how a method can be used with requestAction() and normal requests.
Returning an array data to a non-requestAction request will cause errors and should be avoided. See the section on
for more tips on using requestAction()
In order for you to use a controller effectively in your own application, we’ll cover some of the core attributes and methods provided by CakePHP’s controllers.
Request Life-cycle callbacks
class Controller
CakePHP controllers come fitted with callbacks you can use to insert logic around the request life-cycle:
Controller::beforeFilter()
This function is executed before every action in the controller. It’s a handy place to check for an active session or inspect user permissions.
Request Life-cycle callbacks 45
CakePHP Cookbook Documentation, Release 2.x
Note: The beforeFilter() method will be called for missing actions, and scaffolded actions.
Controller::beforeRender()
Called after controller action logic, but before the view is rendered. This callback is not used often, but may be needed if you are calling render() manually before the end of a given action.
Controller::afterFilter()
Called after every controller action, and after rendering is complete. This is the last controller method to run.
In addition to controller life-cycle callbacks,
also provide a similar set of callbacks.
Controller Methods
For a complete list of controller methods and their descriptions visit the CakePHP API. Check out http://api20.cakephp.org/class/controller .
Interacting with Views
Controllers interact with the view in a number of ways. First they are able to pass data to the views, using set()
. You can also decide which view class to use, and which view file should be rendered from the controller.
Controller::set( string $var , mixed $value)
The set() method is the main way to send data from your controller to your view. Once you’ve used set(), the variable can be accessed in your view:
// First you pass data from the controller:
$this -> set ( ’color’ , ’pink’ );
// Then, in the view, you can utilize the data:
?>
You have selected <?php echo $color ; ?> icing for the cake.
The set() method also takes an associative array as its first parameter. This can often be a quick way to assign a set of information to the view. Changed in version 1.3: Array keys will no longer be inflected before they are assigned to the view (‘underscored_key’ does not become ‘underscoredKey’ anymore, etc.):
$data =
array
(
’color’ => ’pink’ ,
’type’ => ’sugar’ ,
’base_price’ => 23.95
);
// make $color, $type, and $base_price
46 Chapter 4. Controllers
CakePHP Cookbook Documentation, Release 2.x
// available to the view:
$this -> set ( $data );
The attribute $pageTitle no longer exists, use set() to set the title:
$this -> set ( ’title_for_layout’ , ’This is the page title’ );
Controller::render( string $view , string $layout)
The render() method is automatically called at the end of each requested controller action. This method performs all the view logic (using the data you’ve given in using the set() method), places the view inside its layout and serves it back to the end user.
The default view file used by render is determined by convention. If the search() action of the
RecipesController is requested, the view file in /app/View/Recipes/search.ctp will be rendered:
class RecipesController extends
AppController {
// ...
public function
search () {
// Render the view in /View/Recipes/search.ctp
$this -> render ();
}
// ...
}
Although CakePHP will automatically call it (unless you’ve set $this->autoRender to false) after every action’s logic, you can use it to specify an alternate view file by specifying an action name in the controller using $action.
If $view starts with ‘/’ it is assumed to be a view or element file relative to the /app/View folder.
This allows direct rendering of elements, very useful in ajax calls.
// Render the element in /View/Elements/ajaxreturn.ctp
$this -> render ( ’/Elements/ajaxreturn’ );
The $layout parameter allows you to specify the layout the view is rendered in.
Rendering a specific view
In your controller you may want to render a different view than what would conventionally be done. You can do this by calling render() directly. Once you have called render() CakePHP will not try to re-render the view:
class PostsController extends
AppController {
public function
my_action () {
$this -> render ( ’custom_file’ );
}
}
This would render app/View/Posts/custom_file.ctp
app/View/Posts/my_action.ctp
instead of
Controller Methods 47
CakePHP Cookbook Documentation, Release 2.x
Flow Control
Controller::redirect( mixed $url , integer $status, boolean $exit)
The flow control method you’ll use most often is redirect(). This method takes its first parameter in the form of a CakePHP-relative URL. When a user has successfully placed an order, you might wish to redirect them to a receipt screen.:
public function
place_order () {
// Logic for finalizing order goes here
if
( $success ) {
$this -> redirect (
array
( ’controller’ => ’orders’ , ’action’ => ’thanks’ ));
}
else
{
$this -> redirect (
array
( ’controller’ => ’orders’ , ’action’ => ’confirm’ ));
}
}
You can also use a relative or absolute URL as the $url argument:
$this -> redirect ( ’/orders/thanks’ ));
$this -> redirect ( ’http://www.example.com’ );
You can also pass data to the action:
$this -> redirect (
array
( ’action’ => ’edit’ , $id ));
The second parameter of redirect() allows you to define an HTTP status code to accompany the redirect. You may want to use 301 (moved permanently) or 303 (see other), depending on the nature of the redirect.
The method will issue an exit() after the redirect unless you set the third parameter to false.
If you need to redirect to the referer page you can use:
$this -> redirect ( $this -> referer ());
The method also supports name based parameters.
If you want to redirect to a URL like: http://www.example.com/orders/confirm/product:pizza/quantity:5 you can use:
$this -> redirect (
array
( ’controller’ => ’orders’ , ’action’ => ’confirm’ , ’product’ => ’pizza’ , ’quantity’ => 5 ));
Controller::flash( string $message
, string|array $url, integer $pause, string $layout)
Like redirect(), the flash() method is used to direct a user to a new page after an operation.
The flash() method is different in that it shows a message before passing the user on to another
URL.
The first parameter should hold the message to be displayed, and the second parameter is a CakePHPrelative URL. CakePHP will display the $message for $pause seconds before forwarding the user on.
If there’s a particular template you’d like your flashed message to use, you may specify the name of that layout in the $layout parameter.
For in-page flash messages, be sure to check out SessionComponent’s setFlash() method.
48 Chapter 4. Controllers
CakePHP Cookbook Documentation, Release 2.x
Callbacks
In addition to the
Request Life-cycle callbacks . CakePHP also supports callbacks related to scaffolding.
Controller::beforeScaffold(
$method)
$method name of method called example index, edit, etc.
Controller::afterScaffoldSave(
$method)
$method name of method called either edit or update.
Controller::afterScaffoldSaveError(
$method)
$method name of method called either edit or update.
Controller::scaffoldError(
$method)
$method name of method called example index, edit, etc.
Other Useful Methods
Controller::constructClasses()
This method loads the models required by the controller. This loading process is done by CakePHP normally, but this method is handy to have when accessing controllers from a different perspective. If you need CakePHP in a command-line script or some other outside use, constructClasses() may come in handy.
Controller::referer( mixed $default = null , boolean $local = false)
Returns the referring URL for the current request. Parameter $default can be used to supply a default URL to use if HTTP_REFERER cannot be read from headers. So, instead of doing this:
class UserController extends
AppController {
public function
delete ( $id ) {
// delete code goes here, and then...
if
( $this -> referer () != ’/’ ) {
$this -> redirect ( $this -> referer ());
}
else
{
$this -> redirect (
array
( ’action’ => ’index’ ));
}
}
} you can do this:
class UserController extends
AppController {
public function
delete ( $id ) {
// delete code goes here, and then...
$this -> redirect ( $this -> referer (
array
( ’action’ => ’index’ )));
}
}
If $default is not set, the function defaults to the root of your domain - ‘/’.
Parameter $local if set to true, restricts referring URLs to local server.
Controller Methods 49
CakePHP Cookbook Documentation, Release 2.x
Controller::disableCache()
Used to tell the user’s browser not to cache the results of the current request. This is different than view caching, covered in a later chapter.
The headers sent to this effect are:
Expires : Mon, 26 Jul 1997 05 : 00 : 00 GMT
Last Modified : [ current datetime] GMT
Cache Control : no store, no cache, must revalidate
Cache Control : post check = 0 , pre check = 0
Pragma : no cache
Controller::postConditions( array $data , mixed $op, string $bool, boolean $exclusive)
Use this method to turn a set of POSTed model data (from HtmlHelper-compatible inputs) into a set of find conditions for a model. This function offers a quick shortcut on building search logic. For example, an administrative user may want to be able to search orders in order to know which items need to be shipped. You can use CakePHP’s
and
to create a quick form based on the Order model. Then a controller action can use the data posted from that form to craft find conditions:
public function
index () {
$conditions = $this -> postConditions ( $this -> request -> data );
$orders = $this -> Order -> find ( ’all’ , compact ( ’conditions’ ));
$this -> set ( ’orders’ , $orders );
}
If $this->request->data[’Order’][’destination’] equals “Old Towne Bakery”, postConditions converts that condition to an array compatible for use in a Model->find() method.
In this case, array(’Order.destination’ => ’Old Towne Bakery’).
If you want to use a different SQL operator between terms, supply them using the second parameter:
/*
Contents of $this->request->data array(
’Order’ => array(
’num_items’ => ’4’,
’referrer’ => ’Ye Olde’
)
)
*/
// Let’s get orders that have at least 4 items and contain ’Ye Olde’
$conditions = $this -> postConditions (
$this -> request -> data ,
array
(
’num_items’ => ’>=’ ,
’referrer’ => ’LIKE’
)
);
$orders = $this -> Order -> find ( ’all’ , compact ( ’conditions’ ));
The third parameter allows you to tell CakePHP what SQL boolean operator to use between the find conditions. Strings like ‘AND’, ‘OR’ and ‘XOR’ are all valid values.
50 Chapter 4. Controllers
CakePHP Cookbook Documentation, Release 2.x
Finally, if the last parameter is set to true, and the $op parameter is an array, fields not included in $op will not be included in the returned conditions.
Controller::paginate()
This method is used for paginating results fetched by your models. You can specify page sizes, model find conditions and more. See the
section for more details on how to use paginate.
Controller::requestAction( string $url , array $options)
This function calls a controller’s action from any location and returns data from the action. The $url passed is a CakePHP-relative URL (/controllername/actionname/params). To pass extra data to the receiving controller action add to the $options array.
Note: You can use requestAction() to retrieve a fully rendered view by passing ‘return’ in the options: requestAction($url, array(’return’));. It is important to note that making a requestAction using ‘return’ from a controller method can cause script and css tags to not work correctly.
Warning: If used without caching requestAction can lead to poor performance. It is rarely appropriate to use in a controller or model.
requestAction is best used in conjunction with (cached) elements – as a way to fetch data for an element before rendering. Let’s use the example of putting a “latest comments” element in the layout.
First we need to create a controller function that will return the data:
// Controller/CommentsController.php
class CommentsController extends
AppController {
public function
latest () {
if
(
empty
( $this -> request -> params [ ’requested’ ])) {
throw new
ForbiddenException();
}
return
$this -> Comment -> find ( ’all’ ,
array
( ’order’ => ’Comment.created DESC’ , ’limit’ => 10 ));
}
}
You should always include checks to make sure your requestAction methods are actually originating from requestAction. Failing to do so will allow requestAction methods to be directly accessible from a URL, which is generally undesirable.
If we now create a simple element to call that function:
// View/Elements/latest_comments.ctp
$comments = $this -> requestAction ( ’/comments/latest’ );
foreach
( $comments
as
$comment ) {
echo
$comment [ ’Comment’ ][ ’title’ ];
}
We can then place that element anywhere to get the output using:
echo
$this -> element ( ’latest_comments’ );
Controller Methods 51
CakePHP Cookbook Documentation, Release 2.x
Written in this way, whenever the element is rendered, a request will be made to the controller to get the data, the data will be processed, and returned. However in accordance with the warning above it’s best to make use of element caching to prevent needless processing. By modifying the call to element to look like this:
echo
$this -> element ( ’latest_comments’ ,
array
( ’cache’ => ’+1 hour’ ));
The requestAction call will not be made while the cached element view file exists and is valid.
In addition, requestAction now takes array based cake style urls:
echo
$this -> requestAction (
array
( ’controller’ => ’articles’ , ’action’ => ’featured’ ),
array
( ’return’ )
);
This allows the requestAction call to bypass the usage of Router::url which can increase performance.
The url based arrays are the same as the ones that
uses with one difference
- if you are using named or passed parameters, you must put them in a second array and wrap them with the correct key. This is because requestAction merges the named args array (requestAction’s 2nd parameter) with the Controller::params member array and does not explicitly place the named args array into the key ‘named’; Additional members in the $option array will also be made available in the requested action’s Controller::params array:
echo
$this -> requestAction ( ’/articles/featured/limit:3’ );
echo
$this -> requestAction ( ’/articles/view/5’ );
As an array in the requestAction would then be:
echo
$this -> requestAction (
array
( ’controller’ => ’articles’ , ’action’ => ’featured’ ),
array
( ’named’ =>
array
( ’limit’ => 3 ))
);
echo
$this -> requestAction (
array
( ’controller’ => ’articles’ , ’action’ => ’view’ ),
array
( ’pass’ =>
array
( 5 ))
);
Note: Unlike other places where array urls are analogous to string urls, requestAction treats them differently.
When using an array url in conjunction with requestAction() you must specify all parameters that you will need in the requested action. This includes parameters like $this->request->data. In addition to passing all required parameters, named and pass parameters must be done in the second array as seen above.
Controller::loadModel( string $modelClass , mixed $id)
The loadModel function comes handy when you need to use a model which is not the controller’s default model or its associated model:
52 Chapter 4. Controllers
CakePHP Cookbook Documentation, Release 2.x
$this -> loadModel ( ’Article’ );
$recentArticles = $this -> Article -> find ( ’all’ ,
array
( ’limit’ => 5 , ’order’ => ’Article.created DESC’ ));
$this -> loadModel ( ’User’ , 2 );
$user = $this -> User -> read ();
Controller Attributes
For a complete list of controller attributes and their descriptions visit the CakePHP API. Check out http://api20.cakephp.org/class/controller .
property Controller::$name
The $name attribute should be set to the name of the controller. Usually this is just the plural form of the primary model the controller uses. This property is not required, but saves CakePHP from inflecting it:
// $name controller attribute usage example
class RecipesController extends
AppController {
public
$name = ’Recipes’ ;
}
$components, $helpers and $uses
The next most often used controller attributes tell CakePHP what helpers, components, and models you’ll be using in conjunction with the current controller.
Using these attributes make
MVC classes given by $components and $uses available to the controller as class variables
($this->ModelName, for example) and those given by $helpers to the view as an object reference variable ($this->{$helpername}).
Note: Each controller has some of these classes available by default, so you may not need to configure your controller at all.
property Controller::$uses
Controllers have access to their primary model available by default. Our RecipesController will have the Recipe model class available at $this->Recipe, and our ProductsController also features the
Product model at $this->Product. However, when allowing a controller to access additional models through the $uses variable, the name of the current controller’s model must also be included.
This is illustrated in the example below.
If you do not wish to use a Model in your controller, set public $uses = array(). This will allow you to use a controller without a need for a corresponding Model file. However, the models defined in the AppController will still be loaded. You can also use false to not load any models at all. Even those defined in the AppController Changed in version 2.1: Uses now has a new default value, it also handles false differently.
property Controller::$helpers
The Html, Form, and Session Helpers are available by default, as is the SessionComponent. But if you
Controller Attributes 53
CakePHP Cookbook Documentation, Release 2.x
choose to define your own $helpers array in AppController, make sure to include Html and Form if you want them still available by default in your Controllers. To learn more about these classes, be sure to check out their respective sections later in this manual.
Let’s look at how to tell a CakePHP controller that you plan to use additional MVC classes:
class RecipesController extends
AppController {
public
$uses =
array
( ’Recipe’ , ’User’ );
public
$helpers =
array
( ’Js’ );
public
$components =
array
( ’RequestHandler’ );
}
Each of these variables are merged with their inherited values, therefore it is not necessary (for example) to redeclare the Form helper, or anything that is declared in your App controller.
property Controller::$components
The components array allows you to set which
a controller will use. Like $helpers and $uses components in your controllers are merged with those in AppController. As with
$helpers you can pass settings into components. See
for more information.
Other Attributes
While you can check out the details for all controller attributes in the API, there are other controller attributes that merit their own sections in the manual.
More on controllers
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
Dispatcher and
. There was no authoritative object on what information the request
contained. For 2.0,
and
are used for this purpose.
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.
54 Chapter 4. Controllers
CakePHP Cookbook Documentation, Release 2.x
• 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 object properties, the second is array indexes, and the third is through $this->request->params:
$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
are accessed through this interface.
In addition to
you also often need access to
and
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’ ];
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
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
// url is /posts/index?page=1&sort=title
$this -> request -> query [ ’page’ ];
// You can also access it via array access
$this -> request [ ’url’ ][ ’page’ ]; // BC accessor, will be deprecated in future versions
More on controllers 55
CakePHP Cookbook Documentation, Release 2.x
You can either directly access the query property, or you can use
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
. 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
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
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
often exchange data in non URL encoded post bodies. You can read input data in any format using
. 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’ );
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,
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’ ));
Accessing path information
CakeRequest also provides useful information about the paths in your application.
and
are useful for generating urls, and determining whether or not your application is in a subdirectory.
56 Chapter 4. Controllers
CakePHP Cookbook Documentation, Release 2.x
Inspecting the request
Detecting various request conditions used to require using
ods have been moved to CakeRequest, and offer a new interface alongside a more backwards compatible usage:
$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
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
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
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
and
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.
More on controllers 57
CakePHP Cookbook Documentation, Release 2.x
• 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
some rethinking was required to figure out how it still fits into the picture.
For 2.0,
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
. 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(
$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.
58 Chapter 4. Controllers
CakePHP Cookbook Documentation, Release 2.x
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 New in version 2.3.
CakeRequest::referer(
$local = false)
Returns the referring address for the request.
CakeRequest::clientIp( $safe = true)
Returns the current visitor’s IP address.
CakeRequest::header(
$name)
Allows you to access any of the HTTP_* headers that were used for the request:
$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. Additional parameters for the decoding function can be passed as arguments to input().
CakeRequest::data(
$name)
Provides dot notation access to request data. Allows for reading and modification of request data, 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’ );
New in version 2.3.
CakeRequest::is(
$type)
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(
$name , $options)
Add a detector to be used with is(). See
for more information.
CakeRequest::accepts(
$type = null)
Find out which content types the client accepts or check if they accept a particular type of content.
Get all types:
More on controllers 59
CakePHP Cookbook Documentation, Release 2.x
$this -> request -> accepts ();
Check for a single type:
$this -> request -> accepts ( ’application/json’ ); static CakeRequest::acceptLanguage($language = null)
Get either all the languages accepted by the client, or check if a specific language is accepted.
Get the list of accepted languages:
CakeRequest :: acceptLanguage ();
Check if a specific language is accepted:
CakeRequest :: acceptLanguage ( ’es-es’ ); property CakeRequest::$data
An array of POST data. You can use
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
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
consolidates a number of methods previously found on
and Dispatcher. The old methods are deprecated in favour of using
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.
60 Chapter 4. Controllers
CakePHP Cookbook Documentation, Release 2.x
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
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
for more information.
Dealing with content types
You can control the Content-Type of your application’s responses with using
If your application needs to deal with content types that are not built into CakeResponse, you can map those types with 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
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
to accomplish that. As of 2.3 MediaView is deprecated and you can use
to send a file as response:
public function
sendFile ( $id ) {
$file = $this -> Attachment -> getFile ( $id );
$this -> response -> file ( $file [ ’path’ ]);
//Return reponse object to prevent controller from trying to render a view
return
$this -> response ;
}
As shown in above example as expected you have to pass the file path to the method. Cake will send proper content type header if it’s a known file type listed in CakeReponse::$_mimeTypes. You can add new types prior to calling
by using the
method.
If you want you can also force a file to be downloaded instead of being displayed in the browser by specifying the options:
$this -> response -> file ( $file [ ’path’ ],
array
( ’download’ =>
true
, ’name’ => ’foo’ ));
More on controllers 61
CakePHP Cookbook Documentation, Release 2.x
Setting headers
Setting headers is done with the
method. It can be called with a few different parameter configurations:
// 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
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.
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
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.
62 Chapter 4. Controllers
CakePHP Cookbook Documentation, Release 2.x
Apart from using
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
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.:
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
method:
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.
More on controllers 63
CakePHP Cookbook Documentation, Release 2.x
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
included in your controller:
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
included in your controller:
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:
64 Chapter 4. Controllers
CakePHP Cookbook Documentation, Release 2.x
$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:
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(
$header = null , $value = null)
Allows you to directly set one or many headers to be sent with the response.
CakeResponse::charset(
$charset = null)
Sets the charset that will be used in the response.
CakeResponse::type(
$contentType = null)
Sets the content type for 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 New in version 2.1.
CakeResponse::expires(
$time = null)
Allows to set the Expires header to a specific date. New in version 2.1.
CakeResponse::etag( $tag = null , $weak = false)
Sets the Etag header to uniquely identify a response resource. New in version 2.1.
More on controllers 65
CakePHP Cookbook Documentation, Release 2.x
CakeResponse::modified(
$time = null)
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(
$filename)
Allows you to send the response as an attachment and set the filename.
CakeResponse::statusCode( $code = null)
Allows you to set the status code for the response.
CakeResponse::body( $content = null)
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
CakeResponse::file( $path
, $options = array())
Allows you to set a file for display or download New in version 2.3.
Scaffolding
Application scaffolding is a technique that allows a developer to define and create a basic application that can create, retrieve, update and delete objects. Scaffolding in CakePHP also allows developers to define how objects are related to each other, and to create and break those links.
All that’s needed to create a scaffold is a model and its controller. Once you set the $scaffold variable in the controller, you’re up and running.
CakePHP’s scaffolding is pretty cool. It allows you to get a basic CRUD application up and going in minutes.
It’s so cool that you’ll want to use it in production apps. Now, we think it’s cool too, but please realize that scaffolding is... well... just scaffolding. It’s a loose structure you throw up real quick during the beginning of a project in order to get started. It isn’t meant to be completely flexible, it’s meant as a temporary way to get up and going. If you find yourself really wanting to customize your logic and your views, it’s time to pull your scaffolding down in order to write some code. CakePHP’s Bake console, covered in the next section, is a great next step: it generates all the code that would produce the same result as the most current scaffold.
Scaffolding is a great way of getting the early parts of developing a web application started. Early database schemas are subject to change, which is perfectly normal in the early part of the design process. This has a downside: a web developer hates creating forms that never will see real use. To reduce the strain on the developer, scaffolding has been included in CakePHP. Scaffolding analyzes your database tables and creates standard lists with add, delete and edit buttons, standard forms for editing and standard views for inspecting a single item in the database.
66 Chapter 4. Controllers
CakePHP Cookbook Documentation, Release 2.x
To add scaffolding to your application, in the controller, add the $scaffold variable:
class CategoriesController extends
AppController {
public
$scaffold ;
}
Assuming you’ve created even the most basic Category model class file (in /app/Model/Category.php), you’re ready to go. Visit http://example.com/categories to see your new scaffold.
Note: Creating methods in controllers that are scaffolded can cause unwanted results. For example, if you create an index() method in a scaffolded controller, your index method will be rendered rather than the scaffolding functionality.
Scaffolding is knowledgeable about model associations, so if your Category model belongsTo a User, you’ll see related User IDs in the Category listings. While scaffolding “knows” about model associations, you will not see any related records in the scaffold views until you manually add the association code to the model.
For example, if Group hasMany User and User belongsTo Group, you have to manually add the following code in your User and Group models. Before you add the following code, the view displays an empty select input for Group in the New User form. After you add the following code, the view displays a select input populated with IDs or names from the Group table in the New User form:
// In Group.php
public
$hasMany = ’User’ ;
// In User.php
public
$belongsTo = ’Group’ ;
If you’d rather see something besides an ID (like the user’s first name), you can set the $displayField variable in the model. Let’s set the $displayField variable in our User class so that users related to categories will be shown by first name rather than just an ID in scaffolding. This feature makes scaffolding more readable in many instances:
class User extends
AppModel {
public
$displayField = ’first_name’ ;
}
Creating a simple admin interface with scaffolding
If you have enabled admin routing in your app/Config/core.php, with
Configure::write(’Routing.prefixes’, array(’admin’)); you can use scaffolding to generate an admin interface.
Once you have enabled admin routing assign your admin prefix to the scaffolding variable:
public
$scaffold = ’admin’ ;
You will now be able to access admin scaffolded actions: http :// example .
com / admin / controller / index http :// example .
com / admin / controller / view http :// example .
com / admin / controller / edit
More on controllers 67
CakePHP Cookbook Documentation, Release 2.x
http :// example .
com / admin / controller / add http :// example .
com / admin / controller / delete
This is an easy way to create a simple backend interface quickly. Keep in mind that you cannot have both admin and non-admin methods scaffolded at the same time. As with normal scaffolding you can override individual methods and replace them with your own:
public function
admin_view ( $id =
null
) {
// custom code here
}
Once you have replaced a scaffolded action you will need to create a view file for the action as well.
Customizing Scaffold Views
If you’re looking for something a little different in your scaffolded views, you can create templates. We still don’t recommend using this technique for production applications, but such a customization may be useful during prototyping iterations.
Custom scaffolding views for a specific controller (PostsController in this example) should be placed like so:
/ app / View / Posts / scaffold .
index .
ctp
/ app / View / Posts / scaffold .
form .
ctp
/ app / View / Posts / scaffold .
view .
ctp
Custom scaffolding views for all controllers should be placed like so:
/ app / View / Scaffolds / index .
ctp
/ app / View / Scaffolds / form .
ctp
/ app / View / Scaffolds / view .
ctp
The Pages Controller
CakePHP ships with a default controller PagesController.php. This is a simple and optional controller for serving up static content. The home page you see after installation is generated using this controller. If you make the view file app/View/Pages/about_us.ctp you can access it using the url http://example.com/pages/about_us
. You are free to modify the Pages Controller to meet your needs.
When you “bake” an app using CakePHP’s console utility the Pages Controller is created in your app/Controller/ folder.
You can also copy the file from lib/Cake/Console/Templates/skel/Controller/PagesController.php
.
Changed in version 2.1: With CakePHP 2.0 the Pages Controller was part of lib/Cake.
Since 2.1 the Pages Controller is no longer part of the core but ships in the app folder.
Warning: Do not directly modify ANY file under the lib/Cake folder to avoid issues when updating the core in future.
68 Chapter 4. Controllers
CakePHP Cookbook Documentation, Release 2.x
Components
Components are packages of logic that are shared between controllers. If you find yourself wanting to copy and paste things between controllers, you might consider wrapping some functionality in a component.
CakePHP also comes with a fantastic set of core components you can use to aid in:
• Security
• Sessions
• Access control lists
• Emails
• Cookies
• Authentication
• Request handling
• Pagination
Each of these core components are detailed in their own chapters. For now, we’ll show you how to create your own components. Creating components keeps controller code clean and allows you to reuse code between projects.
Configuring Components
Many of the core components require configuration. Some examples of components requiring configuration are
and
. Configuration for these components, and for components
in general, is usually done in the $components array or your controller’s beforeFilter() method:
class PostsController extends
AppController {
public
$components =
array
(
’Auth’ =>
array
(
’authorize’ =>
array
( ’controller’ ),
’loginAction’ =>
array
( ’controller’ => ’users’ , ’action’ => ’login’ )
),
’Cookie’ =>
array
( ’name’ => ’CookieMonster’ )
);
Would be an example of configuring a component with the $components array. All core components allow their configuration settings to be set in this way. In addition you can configure components in your controller’s beforeFilter() method. This is useful when you need to assign the results of a function to a component property. The above could also be expressed as:
public function
beforeFilter () {
$this -> Auth -> authorize =
array
( ’controller’ );
$this -> Auth -> loginAction =
array
( ’controller’ => ’users’ , ’action’ => ’login’ );
$this -> Cookie -> name = ’CookieMonster’ ;
}
More on controllers 69
CakePHP Cookbook Documentation, Release 2.x
It’s possible, however, that a component requires certain configuration options to be set before the controller’s beforeFilter() is run. To this end, some components allow configuration options be set in the
$components array:
public
$components =
array
(
’DebugKit.Toolbar’ =>
array
( ’panels’ =>
array
( ’history’ , ’session’ ))
);
Consult the relevant documentation to determine what configuration options each component provides.
One common setting to use is the className option, which allows you to alias components. This feature is useful when you want to replace $this->Auth or another common Component reference with a custom implementation:
// app/Controller/PostsController.php
class PostsController extends
AppController {
public
$components =
array
(
’Auth’ =>
array
(
’className’ => ’MyAuth’
)
);
}
// app/Controller/Component/MyAuthComponent.php
App :: uses ( ’AuthComponent’ , ’Controller/Component’ );
class MyAuthComponent extends
AuthComponent {
// Add your code to override the core AuthComponent
}
The above would alias MyAuthComponent to $this->Auth in your controllers.
Note: Aliasing a component replaces that instance anywhere that component is used, including inside other
Components.
Using Components
Once you’ve included some components in your controller, using them is pretty simple. Each component you use is exposed as a property on your controller. If you had loaded up the
and the
in your controller, you could access them like so:
class PostsController extends
AppController {
public
$components =
array
( ’Session’ , ’Cookie’ );
public function
delete () {
if
( $this -> Post -> delete ( $this -> request -> data ( ’Post.id’ )) {
$this -> Session -> setFlash ( ’Post deleted.’ );
$this -> redirect (
array
( ’action’ => ’index’ ));
}
}
70 Chapter 4. Controllers
CakePHP Cookbook Documentation, Release 2.x
Note: Since both Models and Components are added to Controllers as properties they share the same
‘namespace’. Be sure to not give a component and a model the same name.
Loading components on the fly
You might not need all of your components available on every controller action. In situations like this you can load a component at runtime using the
Component Collection . From inside a controller you can do the
following:
$this -> OneTimer = $this -> Components -> load ( ’OneTimer’ );
$this -> OneTimer -> getTime ();
Component Callbacks
Components also offer a few request life-cycle callbacks that allow them to augment the request cycle. See the base
for more information on the callbacks components offer.
Creating a Component
Suppose our online application needs to perform a complex mathematical operation in many different parts of the application. We could create a component to house this shared logic for use in many different controllers.
The first step is to create a new component file and class.
Create the file in
/app/Controller/Component/MathComponent.php
.
The basic structure for the component would look something like this:
App :: uses ( ’Component’ , ’Controller’ );
class MathComponent extends
Component {
public function
doComplexOperation ( $amount1 , $amount2 ) {
return
$amount1 + $amount2 ;
}
}
Note: All components must extend
. Failing to do this will trigger an exception.
Including your component in your controllers
Once our component is finished, we can use it in the application’s controllers by placing the component’s name (minus the “Component” part) in the controller’s $components array. The controller will automatically be given a new attribute named after the component, through which we can access an instance of it:
More on controllers 71
CakePHP Cookbook Documentation, Release 2.x
/* Make the new component available at $this->Math, as well as the standard $this->Session */
public
$components =
array
( ’Math’ , ’Session’ );
Components declared in AppController will be merged with those in your other controllers. So there is no need to re-declare the same component twice.
When including Components in a Controller you can also declare a set of parameters that will be passed on to the Component’s constructor. These parameters can then be handled by the Component:
public
$components =
array
(
’Math’ =>
array
(
’precision’ => 2 ,
’randomGenerator’ => ’srand’
),
’Session’ , ’Auth’
);
The above would pass the array containing precision and randomGenerator to
MathComponent::__construct() as the second parameter.
By convention, any settings that have been passed that are also public properties on your component will have the values set based on the settings.
Using other Components in your Component
Sometimes one of your components may need to use another component. In this case you can include other components in your component the exact same way you include them in controllers - using the
$components var:
// app/Controller/Component/CustomComponent.php
App :: uses ( ’Component’ , ’Controller’ );
class CustomComponent extends
Component {
// the other component your component uses
public
$components =
array
( ’Existing’ );
public function
initialize (Controller $controller ) {
$this -> Existing -> foo ();
}
}
}
public function
bar () {
// ...
// app/Controller/Component/ExistingComponent.php
App :: uses ( ’Component’ , ’Controller’ );
class ExistingComponent extends
Component {
public function
foo () {
// ...
}
}
72 Chapter 4. Controllers
CakePHP Cookbook Documentation, Release 2.x
Component API
class Component
The base Component class offers a few methods for lazily loading other Components through
ComponentCollection as well as dealing with common handling of settings. It also provides prototypes for all the component callbacks.
Component::__construct(
ComponentCollection $collection , $settings = array())
Constructor for the base component class. All $settings that are also public properties will have their values changed to the matching value in $settings.
Callbacks
Component::initialize(
Controller $controller)
The initialize method is called before the controller’s beforeFilter method.
Component::startup( Controller $controller)
The startup method is called after the controller’s beforeFilter method but before the controller executes the current action handler.
Component::beforeRender( Controller $controller)
The beforeRender method is called after the controller executes the requested action’s logic but before the controller’s renders views and layout.
Component::shutdown(
Controller $controller)
The shutdown method is called before output is sent to browser.
Component::beforeRedirect( Controller $controller , $url, $status=null, $exit=true)
The beforeRedirect method is invoked when the controller’s redirect method is called but before any further action. If this method returns false the controller will not continue on to redirect the request.
The $url, $status and $exit variables have same meaning as for the controller’s method. You can also return a string which will be interpreted as the url to redirect to or return associative array with key
‘url’ and optionally ‘status’ and ‘exit’.
More on controllers 73
CakePHP Cookbook Documentation, Release 2.x
74 Chapter 4. Controllers
Download
Advertisement