Table of Contents : The Manual

Controllers

 

Introduction

A controller is used to manage the logic for a part of your application. Most commonly, controllers are used to manage the logic for a single model. For example, if you were building a site for an online bakery, you might have a RecipesController and a IngredientsController managing your recipes and their ingredients. In CakePHP, controllers are named after the model they handle, in plural form.

The Recipe model is handled by the RecipesController, the Product model is handled by the ProductsController, and so on.

Your application's controllers are classes that extend the CakePHP AppController class, which in turn extends a core Controller class. The AppController class can be defined in /app/app_controller.php and it should contain methods that are shared between all of your application’s controllers. It extends the Controller class which is a standard CakePHP library.

Controllers can include any number of methods which are usually referred to as actions. Actions are controller methods used to display views. An action is a single method of a controller. CakePHP’s dispatcher calls actions when an incoming request matches a URL to a controller’s action. Returning to our online bakery example, our RecipesController might contain the view(), share(), and search() actions. The controller would be found in /app/controllers/recipes_controller.php and contain:

    <?php
    
    # /app/controllers/recipes_controller.php

    class RecipesController extends AppController {
        function view($id)     {
            //action logic goes here..
        }

        function share($customer_id, $recipe_id) {
            //action logic goes here..
        }

        function search($query) {
            //action logic goes here..
        }
    }

    ?>
  1. <?php
  2. # /app/controllers/recipes_controller.php
  3. class RecipesController extends AppController {
  4. function view($id) {
  5. //action logic goes here..
  6. }
  7. function share($customer_id, $recipe_id) {
  8. //action logic goes here..
  9. }
  10. function search($query) {
  11. //action logic goes here..
  12. }
  13. }
  14. ?>

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.

Controller Attributes

For a complete list of controller attributes and their descriptions visit the CakePHP API. Check out http://api.cakephp.org/1.2/class_controller.html.

$name

PHP4 users should start out their controller definitions using the $name attribute. 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 takes care of some PHP4 classname oddities and helps CakePHP resolve naming.

<?php

#   $name controller attribute usage example

class RecipesController extends AppController {
   var $name = 'Recipes';
}

?>	
  1. <?php
  2. # $name controller attribute usage example
  3. class RecipesController extends AppController {
  4. var $name = 'Recipes';
  5. }
  6. ?>

$components, $helpers and $uses

The next most oft used controller attributes tell CakePHP what helpers, components, and models you’ll be using in conjunction with the current controller. Using these attributes make these MVC classes available to the controller as a class variable ($this->ModelName, for example).

Please note that each controller has some of these classes available by default, so you may not need to configure your controller at all.

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.

The Html- and SessionHelpers are always available by default, as is the SessionComponent. 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.

<?php

class RecipesController extends AppController {
    var $name = 'Recipes';

    var $uses = array('Recipe', 'User');
    var $helpers = array('Html', 'Ajax');
    var $components = array('Session', 'Email');
}

?>   
  1. <?php
  2. class RecipesController extends AppController {
  3. var $name = 'Recipes';
  4. var $uses = array('Recipe', 'User');
  5. var $helpers = array('Html', 'Ajax');
  6. var $components = array('Session', 'Email');
  7. }
  8. ?>

When defining these attributes, make sure to include the default classes (like including the HtmlHelper in the $helpers array, for example) if you intend to use them.

A few attributes exist in CakePHP controllers that give you control over how your views set inside of a layout.

The $layout attribute can be set to the name of a layout saved in /app/views/layouts. You specify a layout by setting $layout equal to the name of the layout file minus the .ctp extension. If this attribute has not been defined, CakePHP renders the default layout. If you haven’t defined one at /app/views/default.ctp, CakePHP’s core default layout will be rendered.

<?php

#   Using $layout to define an alternate layout

class RecipesController extends AppController {
    function quickSave() {
        $this->layout = 'ajax';
    }
}

?>
  1. <?php
  2. # Using $layout to define an alternate layout
  3. class RecipesController extends AppController {
  4. function quickSave() {
  5. $this->layout = 'ajax';
  6. }
  7. }
  8. ?>

The $pageTitle controller attribute allows you to set the title of the rendered page. In order for this to work properly, your layout needs to include the $title_for_layout variable, at least between <title> tags in the head of the HTML document.

Just set $pageTitle to a string you’d like to see in the <title> of your document.

By bmauter 1 week ago

1 - default.ctp

Looks like in Cake 1.2 that default.ctp has to be at /app/views/layouts/default.ctp NOT /app/views/default.ctp like the manual says.

The Parameters Attribute ($params)

Controller parameters are available at $this->params in your CakePHP controller. This variable is used to provide access to information about the current request. The most common usage of $this->params is to get access to information that has been handed to the controller via POST or GET operations.

form
$this->params['form']
  1. $this->params['form']

Any POST data from any form is stored here, including information also found in $_FILES.

bare
$this->params['bare']
  1. $this->params['bare']

Stores 1 if the current layout is empty, 0 if not.

isAjax
$this->params['ajax']
  1. $this->params['ajax']

Stores 1 if the current layout is set to ‘ajax’, 0 if not. This variable is only set if the RequestHandler Component is being used in the controller.

controller
$this->params['controller']
  1. $this->params['controller']

Stores the name of the current controller handling the request. For example, if the URL /posts/view/1 was requested, $this->params['controller'] would equal "posts".

action
$this->params['action']
  1. $this->params['action']

Stores the name of the current action handling the request. For example, if the URL /posts/view/1 was requested, $this->params['action'] would equal "view".

pass
$this->params['pass']
  1. $this->params['pass']

Stores the GET query string passed with the current request. For example, if the URL /posts/view/?var1=3&var2=4 was requested, $this->params['pass'] would equal "?var1=3&var2=4".

url
$this->params['url']
  1. $this->params['url']

Stores the current URL requested, along with key-value pairs of get variables. For example, if the URL /posts/view/?var1=3&var2=4 was called, $this->params['url'] would contain:

[url] => Array
(
    [url] => posts/view
    [var1] => 3
    [var2] => 4
)
  1. [url] => Array
  2. (
  3. [url] => posts/view
  4. [var1] => 3
  5. [var2] => 4
  6. )
data
$this->data
  1. $this->data

Used to handle POST data sent from the FormHelper forms to the controller.

<?php

// The FormHelper is used to create a form element:

$form->text('User.first_name');

// When rendered, it looks something like:

<input name="data[User][first_name]" value="" type="text" />

// When the form is submitted to the controller via POST,
// the data shows up in $this->data.

//The submitted first name can be found here:
$this->data['User']['first_name'];

?>
  1. <?php
  2. // The FormHelper is used to create a form element:
  3. $form->text('User.first_name');
  4. // When rendered, it looks something like:
  5. <input name="data[User][first_name]" value="" type="text" />
  6. // When the form is submitted to the controller via POST,
  7. // the data shows up in $this->data.
  8. //The submitted first name can be found here:
  9. $this->data['User']['first_name'];
  10. ?>

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.

The $cacheAction attribute aids in caching views, and the $paginate attribute is used to set pagination defaults for the controller. For more information on how to use these attributes, check out their respective sections later on in this manual.

Controller Methods

For a complete list of controller methods and their descriptions visit the CakePHP API. Check out http://api.cakephp.org/1.2/class_controller.html.

Interacting with Views

set
set(string $var, mixed $value)
  1. set(string $var, mixed $value)

The set() method is the main way to get data from your controller to your view. Once you've used set(), the variable can be accessed in your view.

<?php
    
//First you pass data from the controller:

$this->set('color', 'pink');

//Then, in the view, you can utilize the data:

You have selected  icing for the cake.

?>
  1. <?php
  2. //First you pass data from the controller:
  3. $this->set('color', 'pink');
  4. //Then, in the view, you can utilize the data:
  5. You have selected <?php echo $color; ?> icing for the cake.
  6. ?>

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. Note that your array keys will be inflected before they get assigned to the view (‘underscored_key’ becomes ‘underscoredKey’, etc.):

<?php
    
$data = array(
    'color' => 'pink',
    'type' => 'sugar',
    'base_price' => 23.95
);

//make $color, $type, and $basePrice 
//available to the view:

$this->set($data);  

?>
  1. <?php
  2. $data = array(
  3. 'color' => 'pink',
  4. 'type' => 'sugar',
  5. 'base_price' => 23.95
  6. );
  7. //make $color, $type, and $basePrice
  8. //available to the view:
  9. $this->set($data);
  10. ?>
render
render(string $action, string $layout, string $file)
  1. render(string $action, string $layout, string $file)

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/views/recipes/search.ctp will be rendered.

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. You can also specify an alternate view file using the third parameter, $file. When using $file, don’t forget to utilize a few of CakePHP’s global constants (such as VIEWS).

The $layout parameter allows you to specify the layout the view is rendered in.

Flow Control

By Sake on 22/2/08

1 - Arrays as parameters

I have been advised >

$this->redirect('/my_controller/my_action/param1/param2/'); should be replaced with

</pre>

<pre>

$this->redirect(array('controller'=>'my_controller','action'=>'action','param1','param2'));

</pre>

redirect
redirect(string $url, integer $status, boolean $exit)
  1. redirect(string $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.

<?php
	
function placeOrder() {

    //Logic for finalizing order goes here

    if($success) {
        $this->redirect('/orders/thanks');
    } else {
        $this->redirect('/orders/confirm');
    }
}

?>
  1. <?php
  2. function placeOrder() {
  3. //Logic for finalizing order goes here
  4. if($success) {
  5. $this->redirect('/orders/thanks');
  6. } else {
  7. $this->redirect('/orders/confirm');
  8. }
  9. }
  10. ?>

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.

flash
flash(string $message, string $url, integer $pause)
  1. flash(string $message, string $url, integer $pause)

Similarly, 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 CakePHP-relative URL. CakePHP will display the $message for $pause seconds before forwarding the user on.

For in-page flash messages, be sure to check out SessionComponent’s setFlash() method.

Callbacks

CakePHP controllers come fitted with callbacks you can use to insert logic just before or after controller actions are rendered.

beforeFilter()

This function is executed before every action in the controller. Its a handy place to check for an active session or inspect user permissions.

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.

afterFilter()

Called after every controller action.

afterRender()

Called after an action has been rendered.

Other Useful Methods

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.

referrer

Returns the referring URL for the current request.

By alex.buchanan 1 day, 11 hours ago

1 - Typo

I believe that's referer(), not referrer()

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.

postConditions
postConditions(array $data, mixed $op, string $bool, boolean $exclusive)
  1. 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 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 Form- and HtmlHelpers 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:

function index() {
    $o = $this->Orders->findAll($this->postConditions($this->data));
    $this->set('orders', $o);
}
  1. function index() {
  2. $o = $this->Orders->findAll($this->postConditions($this->data));
  3. $this->set('orders', $o);
  4. }

If $this->data[‘Order’][‘destination’] equals “Old Towne Bakery”, postConditions converts that condition to an array compatible for use in a Model->findAll() method. In this case, array(“Order.destination” => “Old Towne Bakery”).

If you want use a different SQL operator between terms, supply them using the second parameter.

/*
Contents of $this->data
array(
    'Order' => array(
        'num_items' => '4',
        'referrer' => 'Ye Olde'
    )
)
*/

//Let’s get orders that have at least 4 items and contain ‘Ye Olde’
$o = $this->Order->findAll($this->postConditions(
    $this->data,
    array('>=', 'LIKE')
));
  1. /*
  2. Contents of $this->data
  3. array(
  4. 'Order' => array(
  5. 'num_items' => '4',
  6. 'referrer' => 'Ye Olde'
  7. )
  8. )
  9. */
  10. //Let’s get orders that have at least 4 items and contain ‘Ye Olde’
  11. $o = $this->Order->findAll($this->postConditions(
  12. $this->data,
  13. array('>=', 'LIKE')
  14. ));

The key in specifying the operators is the order of the columns in the $this->data array. Since num_items is first, the >= operator applies to it.

The third parameter allows you to tell CakePHP what SQL boolean operator to use between the find conditions. String 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.

By peterwebtrax 1 week, 3 days ago

1 - Is the $op description correct?

I've tried doing postconditions with a $op array according to the description and just got errors.

Looking at the controller code it appears to require a keyed array with the key being the field names, and the values being the operators, eg: postConditions($this->data, array('Individual.name' => 'LIKE').

If this is the case, I'm happy to edit the doc.

Cheers

Peter

paginate

This method is used for paginating results fetched by your models. You can specify page sizes, model find conditions and more. Details on this method follow later. Check out the pagination chapter later on in this manual.

requestAction
requestAction(string $url, array $options)
  1. 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). If the $options array includes a 'return' value, AutoRender is automatically set to true for the controller action, having requestAction hand you back a fully rendered view.

Note: while you can use requestAction() to retrieve a fully rendered view, the performance hit you take on running through the whole view layer another time isn't often worth it. The requestAction() method is best used in conjunction with elements–as a way to fetch business logic for an element before rendering.

First, let's look at how to get data from a controller action. First, we need to set up a controller action that returns some data we might need in various places throughout the application:

// Here is our simple controller:

class UsersController extends AppController {
    function getUserList() {
        return $this->User->findAll('User.active = 1');
    }
}
  1. // Here is our simple controller:
  2. class UsersController extends AppController {
  3. function getUserList() {
  4. return $this->User->findAll('User.active = 1');
  5. }
  6. }

Imagine that we needed to create a simple table showing the active users in the system. Instead of duplicating list-generating code in another controller, we can get the data from UsersController->getUserList() instead by using requestAction().

class ProductsController extends AppController {
    function showUserProducts() {
        $this->set(
            'users', 
            $this->requestAction('/users/getUserList')
        );

        // Now the $users variable in the view will have the data from
        // UsersController::getUserList().
    }
}   
  1. class ProductsController extends AppController {
  2. function showUserProducts() {
  3. $this->set(
  4. 'users',
  5. $this->requestAction('/users/getUserList')
  6. );
  7. // Now the $users variable in the view will have the data from
  8. // UsersController::getUserList().
  9. }
  10. }

If you have an element in your application that is not static, you might want to use requestAction() to grab controller-like logic for the element as you inject it into your views. While elements always have access to any view variables the controller has passed, this is one way to get element data from another controller.

If you have created a controller action that supplies the logic needed, you can grab that data and pass it to the second parameter of the view's renderElement() method using requestAction().

renderElement(
    'users',
    $this->requestAction('/users/getUserList')
);
?>
  1. <?php
  2. echo $this->renderElement(
  3. 'users',
  4. $this->requestAction('/users/getUserList')
  5. );
  6. ?>

If the $options array contains a 'return' value, the controller action is rendered inside an empty layout and returned. In this way, the requestAction() function is also useful in Ajax situations where a small element of a view needs to be populated before or during an Ajax update.