Controllers. CakePHP CakePHP framework
Below you will find brief information for CakePHP framework. CakePHP framework is a robust base for your application. It can handle every aspect, from the user’s initial request all the way to the final rendering of a web page. And since the framework follows the principles of MVC, it allows you to easily customize and extend most aspects of your application.
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, a controller is used to manage the logic around a single model. For example, if you were building a site for an online bakery, you might have a RecipesController managing your recipes and an
IngredientsController managing your ingredients. However, it’s also possible to have controllers work with more than one model. In CakePHP, a controller is named after the primary model it handles.
Your application’s controllers extend the 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 that handle requests. These are called actions. By default, each public method in a controller is an action, and is accessible from a URL. An action is 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
class included in the CakePHP core library.
AppController is defined in /app/Controller/AppController.php as follows: class AppController extends Controller {
}
Controller attributes and methods created in your AppController will be available to all of your application’s controllers. Components (which you’ll learn about later) are best used for code that is used in many
(but not necessarily all) controllers.
47
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 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 into your application’s controllers:
•
•
•
Remember to add the default Html and Form helpers if you define the
property in your
AppController .
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 in 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 boilerplate 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..
48 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 lowercased 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 bypass 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 you use controller methods with
requestAction() , 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
and normal requests. Returning array data to a non-requestAction request will cause errors and should be avoided.
See the section on
for more tips on using
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
Request Life-cycle callbacks 49
CakePHP Cookbook Documentation, Release 2.x
session or inspect user permissions.
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
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
1
Interacting with Views
Controllers interact with views 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
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
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:
$data = array (
'color' => 'pink' ,
'type' => 'sugar' ,
'base_price' => 23.95
);
// make $color, $type, and $base_price
// available to the view:
1 http://api.cakephp.org/2.4/class-Controller.html
50 Chapter 4. Controllers
CakePHP Cookbook Documentation, Release 2.x
$this -> set ( $data );
The attribute $pageTitle no longer exists. Use
to set the title:
$this -> set ( 'title_for_layout' , 'This is the page title' );
As of 2.5 the variable $title_for_layout is deprecated, use view blocks instead.
Controller::render( string $view , string $layout)
The
method is automatically called at the end of each requested controller action. This method performs all the view logic (using the data you’ve submitted using the
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 after every action’s logic (unless you’ve set
$this->autoRender to false), you can use it to specify an alternate view file by specifying a view name in the controller using $view.
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
parameter allows you to specify the layout with which the view is rendered.
Rendering a specific view
In your controller, you may want to render a different view than the conventional one. You can do this by calling
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
You can also render views inside plugins using the following syntax:
$this->render(’PluginName.PluginController/custom_file’) . For example:
Controller Methods 51
CakePHP Cookbook Documentation, Release 2.x
class PostsController extends AppController { public function my_action () {
$this -> render ( 'Users.UserDetails/custom_file' );
}
}
This would render app/Plugin/Users/View/UserDetails/custom_file.ctp
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 ) { return $this -> redirect ( array ( 'controller' => 'orders' , 'action' => 'thanks' )
);
} return $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
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' ,
52 Chapter 4. Controllers
CakePHP Cookbook Documentation, Release 2.x
'product' => 'pizza' ,
'quantity' => 5 )
);
An example using query strings and hash would look like:
$this -> redirect ( array (
'controller' => 'orders' ,
'action' => 'confirm' ,
'?' => array (
'product' => 'pizza' ,
'quantity' => 5
),
'#' => 'top' )
);
The generated URL would be: http :// www .
example .
com / orders / confirm ?
product = pizza & quantity = 5 #top
Controller::flash( string $message , string|array $url, integer $pause, string $layout)
Like
method is used to direct a user to a new page after an operation.
The
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
parameter.
For in-page flash messages, be sure to check out
method.
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.
Controller Methods 53
CakePHP Cookbook Documentation, Release 2.x
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,
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 () != '/' ) { return $this -> redirect ( $this -> referer ());
} return $this -> redirect ( array ( 'action' => 'index' ));
}
} you can do this: class UserController extends AppController { public function delete ( $id ) {
// delete code goes here, and then...
return $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::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
54 Chapter 4. Controllers
CakePHP Cookbook Documentation, Release 2.x
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.
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
to retrieve a fully rendered view by passing ‘return’ in the options: requestAction($url, array(’return’));. It is important to note that making a
using return from a controller method can cause script and CSS tags to not work correctly.
Controller Methods 55
CakePHP Cookbook Documentation, Release 2.x
56
Warning: If used without caching
can lead to poor performance. It is rarely appropriate to use in a controller or model.
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
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' );
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 (), array ( 'cache' => true ));
The
call will not be made while the cached element view file exists and is valid.
In addition,
now takes array based cake style URLs: echo $this -> requestAction ( array ( 'controller' => 'articles' , 'action' => 'featured' ), array ( 'return' )
);
Chapter 4. Controllers
CakePHP Cookbook Documentation, Release 2.x
This allows the
call to bypass the usage of
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
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
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,
treats them differently.
When using an array url in conjunction with
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
function comes handy when you need to use a model which is not the controller’s default model or its associated model:
$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
2
2 http://api.cakephp.org/2.4/class-Controller.html
Controller Attributes 57
CakePHP Cookbook Documentation, Release 2.x
property Controller::$name
The
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 can be omitted, 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
models you’ll be using in conjunction with the current controller.
Using these attributes make
MVC classes given by
and
available to the controller as class variables
($this->ModelName, for example) and those given by
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
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:
now has a new default value, it also handles false differently.
property Controller::$helpers
The
are available by default, as is the
But if you choose to define your own
array in
AppController , make sure to include
and
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
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' );
}
58 Chapter 4. Controllers
CakePHP Cookbook Documentation, Release 2.x
Each of these variables are merged with their inherited values, therefore it is not necessary (for example) to redeclare the
FormHelper , or anything that is declared in your AppController.
property Controller::$components
The components array allows you to set which
a controller will use. Like
and
components in your controllers are merged with those in AppController. As with
you can pass settings into
for more information.
Other Attributes
While you can check out the details for all controller attributes in the API
3
, there are other controller at-
tributes that merit their own sections in the manual.
property Controller::$cacheAction
The cacheAction attribute is used to define the duration and other information about full page caching.
You can read more about full page caching in the
documentation.
property Controller::$paginate
The paginate attribute is a deprecated compatibility property. Using it loads and configures the
PaginatorComponent . It is recommended that you update your code to use normal component
settings: class ArticlesController extends AppController { public $components = array (
'Paginator' => array (
'Article' => array (
'conditions' => array ( 'published' => 1 )
)
)
);
}
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
Controller . 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
is created and then passed
3 http://api.cakephp.org
More on controllers 59
CakePHP Cookbook Documentation, Release 2.x
by reference to the various layers of an application that use request data. By default,
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
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
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
are accessed through this interface.
In addition to
Route Elements , you also often need access to
and
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
for more information.
• bare Present when the request came from
and included the bare option. Bare requests do not have layouts rendered.
• requested Present and set to true when the action came from
60 Chapter 4. Controllers
CakePHP Cookbook Documentation, Release 2.x
Accessing Querystring parameters
Querystring parameters can be read using
// 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
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
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
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
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' );
More on controllers 61
CakePHP Cookbook Documentation, Release 2.x
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,
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
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.
Inspecting the request
Detecting various request conditions used to require using
RequestHandlerComponent . These meth-
ods 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 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 - Compares a value fetched from
for equality with 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' ,
62 Chapter 4. Controllers
CakePHP Cookbook Documentation, Release 2.x
); 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 );
})
);
also includes methods like
and
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 = XML-
HttpRequest.
• 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
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,
provides a layer of sugar, such as switching layout and views based on content, on top of the utility that
affords. This separation of utility and sugar between the two classes lets you more easily choose what you want.
More on controllers 63
CakePHP Cookbook Documentation, Release 2.x
Interacting with other aspects of the request
You can use
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
New in version 2.3.
Deprecated since version 2.5: Use
instead.
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
New in version 2.5.
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. For example:
$this -> request -> header ( 'User-Agent' ); would return the user agent used for the request.
64 Chapter 4. Controllers
CakePHP Cookbook Documentation, Release 2.x
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' );
New in version 2.3.
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( $name , $options)
Add a detector to be used with
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:
More on controllers 65
CakePHP Cookbook Documentation, Release 2.x
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.
New in version 2.4.
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
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
by default.
is a flexible and transparent class. If you need to override it with your own application-specific class, you can replace
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
66 Chapter 4. Controllers
CakePHP Cookbook Documentation, Release 2.x
allows you to stub out the methods that interact with
for more information.
Dealing with content types
You can control the Content-Type of your application’s responses with
your application needs to deal with content types that are not built into
them with
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
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
MediaView . 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 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
by using the
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:
More on controllers 67
CakePHP Cookbook Documentation, Release 2.x
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 ;
}
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
multiple times will result in overwriting the previous values, just as regular header calls do. Headers are not sent when
is called; instead they are buffered until the response is actually sent.
New in version 2.4.
You can now use the convenience method
to directly set or get the redirect location header.
Interacting with browser caching
You sometimes need to force browsers not to cache the results of a controller action.
is intended for just that: public function index () {
// do something.
$this -> response -> disableCache ();
}
68 Chapter 4. Controllers
CakePHP Cookbook Documentation, Release 2.x
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.
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.
The Cache Control header
New in version 2.1.
Used under the expiration model, this header contains multiple indicators that 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
class helps you set this header with some utility methods that will produce a final valid
Cache-Control header. The first is the
method, which indicates whether a response is to be considered sharable across different users or clients. 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, the control directive must be set as public.
The 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 );
More on controllers 69
CakePHP Cookbook Documentation, Release 2.x
} public function my_data () {
...
// set the Cache-Control as private for 3600 seconds
$this -> response -> sharable ( false , 3600 );
}
exposes separate methods for setting each of the directives in the Cache-Control header.
The Expiration header
New in version 2.1.
You can set the Expires header to a date and 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 instance 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 it asks the application every time whether the resource has changed, instead of using it directly. This is commonly used with static resources such as images and other assets.
The
method (called entity tag) is a string that uniquely identifies the requested resource, as a checksum does for a file, in order to determine whether it matches a cached resource.
To take advantage of this header, you must either call the
CakeResponse::checkNotModified()
method manually or include the
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 ;
}
...
}
70 Chapter 4. Controllers
CakePHP Cookbook Documentation, Release 2.x
The Last Modified header
New in version 2.1.
Under the HTTP cache validation model, you can also 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 tell caching clients whether the response was modified or not based on their cache.
To take advantage of this header, you must either call the
CakeResponse::checkNotModified()
method manually or include the
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 content using the same URL. This is often the case if you have a multilingual page or respond with different HTML depending on the browser. Under such circumstances you can use the Vary header:
$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
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.
More on controllers 71
CakePHP Cookbook Documentation, Release 2.x
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 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 ();
New in version 2.4.
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
New in version 2.1.
CakeResponse::expires( $time = null)
Allows the Expires header to be set 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.
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 deter-
72 Chapter 4. Controllers
CakePHP Cookbook Documentation, Release 2.x
mines whether it can still be considered fresh. If so, deletes the response content, 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 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
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.
New in version 2.3.
Scaffolding
Deprecated since version 2.5: Dynamic scaffolding will be removed and replaced in 3.0
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.
More on controllers 73
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 aware of model’s associations; so, if your Category model belongsTo User, you’ll see related User IDs in the Category listings. While scaffolding “knows” about model’s 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 to your User and Group models. Before you do it, the view displays an empty select input for Group in the New User form; after – 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 by 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
74 Chapter 4. Controllers
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.
More on controllers 75
CakePHP Cookbook Documentation, Release 2.x
Components
Components are packages of logic that are shared between controllers. CakePHP comes with a fantastic set of core components you can use to aid in various common tasks. You can also create your own components.
If you find yourself wanting to copy and paste things between controllers, you should consider creating your own component to contain the functionality. Creating components keeps controller code clean and allows you to reuse code between projects.
Each of the core components is detailed in its own chapter. See
Components . This section describes how to
configure and use components, and how to create your own components.
Configuring Components
Many of the core components require configuration. Some examples of components requiring configuration are
and
Cookie . 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' )
);
The previous fragment of code 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' ;
}
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' ))
);
76 Chapter 4. Controllers
CakePHP Cookbook Documentation, Release 2.x
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.' ); return $this -> redirect ( array ( 'action' => 'index' ));
}
}
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’s method you
More on controllers 77
CakePHP Cookbook Documentation, Release 2.x
can do the following:
$this -> OneTimer = $this -> Components -> load ( 'OneTimer' );
$this -> OneTimer -> getTime ();
Note: Keep in mind that loading a component on the fly will not call its initialize method. If the component you are calling has this method you will need to call it manually after load.
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
Component . 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 (without 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:
/* 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.
78 Chapter 4. Controllers
CakePHP Cookbook Documentation, Release 2.x
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, if array keys match component’s public properties, the properties will be set to the values of these keys.
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 () {
// ...
}
}
Note: In contrast to a component included in a controller no callbacks will be triggered on a component’s component.
More on controllers 79
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)
Is called before the controller’s beforeFilter method.
Component::startup( Controller $controller)
Is called after the controller’s beforeFilter method but before the controller executes the current action handler.
Component::beforeRender( Controller $controller)
Is called after the controller executes the requested action’s logic, but before the controller’s renders views and layout.
Component::shutdown( Controller $controller)
Is called before output is sent to the browser.
Component::beforeRedirect( Controller $controller , $url, $status=null, $exit=true)
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 an associative array with the key ‘url’ and optionally
‘status’ and ‘exit’.
80 Chapter 4. Controllers
Download
Advertisement
Key features
Robust base for applications
Handles every aspect of request processing
MVC architecture for easy customization
Consistent and logical organization
Database interaction with models
View helpers for efficient presentation
Form validation and error handling
Session management capabilities
Routing for URL mapping
Console for development tasks
Frequently asked questions
CakePHP is a free, open-source, rapid development framework for PHP. It is a powerful tool for building web applications quickly and efficiently.
CakePHP offers many benefits, including its MVC architecture, database interaction capabilities, built-in security features, and a large community of developers. It makes development faster and easier.
You can download CakePHP from the CakePHP project on GitHub and follow the installation instructions provided in the documentation.