Controllers

  • class Cake\Controller\Controller
  • Controllers are the ‘C’ in MVC. After routing has been applied and the correctcontroller has been found, your controller’s action is called. Your controllershould handle interpreting the request data, making sure the correct modelsare called, and the right response or view is rendered. Controllers can bethought of as middle layer between the Model and View. You want to keep yourcontrollers thin, and your models fat. This will help you reuseyour code and makes your code easier to test.

Commonly, a controller is used to manage the logic around a single model. Forexample, if you were building a site for an online bakery, you might have aRecipesController managing your recipes and an IngredientsController managing youringredients. However, it’s also possible to have controllers work with more thanone model. In CakePHP, a controller is named after the primary model ithandles.

Your application’s controllers extend the AppController class, which in turnextends the core Controller class. The AppControllerclass can be defined in src/Controller/AppController.php and it shouldcontain methods that are shared between all of your application’s controllers.

Controllers provide a number of methods that handle requests. These are calledactions. By default, each public method ina controller is an action, and is accessible from a URL. An action is responsiblefor interpreting the request and creating the response. Usually responses arein the form of a rendered view, but there are other ways to create responses aswell.

The App Controller

As stated in the introduction, the AppController class is the parent classto all of your application’s controllers. AppController itself extends theCake\Controller\Controller class included in CakePHP.AppController is defined in src/Controller/AppController.php asfollows:

  1. namespace App\Controller;
  2.  
  3. use Cake\Controller\Controller;
  4.  
  5. class AppController extends Controller
  6. {
  7. }

Controller attributes and methods created in your AppController will beavailable in all controllers that extend it. Components (which you’lllearn about later) are best used for code that is used in many (but notnecessarily all) controllers.

You can use your AppController to load components that will be used in everycontroller in your application. CakePHP provides a initialize() method thatis invoked at the end of a Controller’s constructor for this kind of use:

  1. namespace App\Controller;
  2.  
  3. use Cake\Controller\Controller;
  4.  
  5. class AppController extends Controller
  6. {
  7.  
  8. public function initialize()
  9. {
  10. // Always enable the CSRF component.
  11. $this->loadComponent('Csrf');
  12. }
  13.  
  14. }

In addition to the initialize() method, the older $components propertywill also allow you to declare which components should be loaded. While normalobject-oriented inheritance rules apply, the components and helpers used bya controller are treated specially. In these cases, AppController propertyvalues are merged with child controller class arrays. The values in the childclass will always override those in AppController.

Request Flow

When a request is made to a CakePHP application, CakePHP’sCake\Routing\Router and Cake\Routing\Dispatcherclasses use Connecting Routes to find and create the correctcontroller instance. The request data is encapsulated in a request object.CakePHP puts all of the important request information into the $this->requestproperty. See the section on Request for more information on theCakePHP request object.

Controller Actions

Controller actions are responsible for converting the request parameters into aresponse for the browser/user making the request. CakePHP uses conventions toautomate this process and remove some boilerplate code you would otherwise needto write.

By convention, CakePHP renders a view with an inflected version of the actionname. Returning to our online bakery example, our RecipesController might contain theview(), share(), and search() actions. The controller would be foundin src/Controller/RecipesController.php and contain:

  1. // src/Controller/RecipesController.php
  2.  
  3. class RecipesController extends AppController
  4. {
  5. public function view($id)
  6. {
  7. // Action logic goes here.
  8. }
  9.  
  10. public function share($customerId, $recipeId)
  11. {
  12. // Action logic goes here.
  13. }
  14.  
  15. public function search($query)
  16. {
  17. // Action logic goes here.
  18. }
  19. }

The template files for these actions would be src/Template/Recipes/view.ctp,src/Template/Recipes/share.ctp, and src/Template/Recipes/search.ctp. Theconventional view file name is the lowercased and underscored version of theaction name.

Controller actions generally useController::set() to create a context thatView uses to render the view layer. Because of the conventions thatCakePHP uses, you don’t need to create and render the view manually. Instead,once a controller action has completed, CakePHP will handle rendering anddelivering the View.

If for some reason you’d like to skip the default behavior, you can return aCake\Http\Response object from the action with the fullycreated response.

In order for you to use a controller effectively in your own application, we’llcover some of the core attributes and methods provided by CakePHP’s controllers.

Interacting with Views

Controllers interact with views in a number of ways. First, theyare able to pass data to the views, using Controller::set(). You can alsodecide which view class to use, and which view file should berendered from the controller.

Setting View Variables

  • Cake\Controller\Controller::set(string $var, mixed $value)
  • The Controller::set() method is the main way to send data from yourcontroller to your view. Once you’ve used Controller::set(), the variablecan be accessed in your view:
  1. // First you pass data from the controller:
  2.  
  3. $this->set('color', 'pink');
  4.  
  5. // Then, in the view, you can utilize the data:
  6. ?>
  7.  
  8. You have selected <?= h($color) ?> icing for the cake.

The Controller::set() method also takes anassociative array as its first parameter. This can often be a quick way toassign a set of information to the view:

  1. $data = [
  2. 'color' => 'pink',
  3. 'type' => 'sugar',
  4. 'base_price' => 23.95
  5. ];
  6.  
  7. // Make $color, $type, and $base_price
  8. // available to the view:
  9.  
  10. $this->set($data);

Keep in mind that view vars are shared among all parts rendered by your view.They will be available in all parts of the view: the template, the layout andall elements inside the former two.

Setting View Options

If you want to customize the view class, layout/template paths, helpers or thetheme that will be used when rendering the view, you can use theviewBuilder() method to get a builder. This builder can be used to defineproperties of the view before it is created:

  1. $this->viewBuilder()
  2. ->helpers(['MyCustom'])
  3. ->theme('Modern')
  4. ->className('Modern.Admin');

The above shows how you can load custom helpers, set the theme and use a customview class.

New in version 3.1: ViewBuilder was added in 3.1

Rendering a View

  • Cake\Controller\Controller::render(string $view, string $layout)
  • The Controller::render() method is automatically called at the end of each requestedcontroller action. This method performs all the view logic (using the datayou’ve submitted using the Controller::set() method), places the view inside itsView::$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 src/Template/Recipes/search.ctp will be rendered:

  1. namespace App\Controller;
  2.  
  3. class RecipesController extends AppController
  4. {
  5. // ...
  6. public function search()
  7. {
  8. // Render the view in src/Template/Recipes/search.ctp
  9. $this->render();
  10. }
  11. // ...
  12. }

Although CakePHP will automatically call it after every action’s logic(unless you’ve set $this->autoRender to false), you can use it to specifyan alternate view file by specifying a view file name as first argument ofController::render() method.

If $view starts with ‘/’, it is assumed to be a view orelement file relative to the src/Template folder. This allowsdirect rendering of elements, very useful in AJAX calls:

  1. // Render the element in src/Template/Element/ajaxreturn.ctp
  2. $this->render('/Element/ajaxreturn');

The second parameter $layout of Controller::render() allows you to specify the layoutwith which the view is rendered.

Rendering a Specific Template

In your controller, you may want to render a different view than theconventional one. You can do this by calling Controller::render() directly. Once youhave called Controller::render(), CakePHP will not try to re-render the view:

  1. namespace App\Controller;
  2.  
  3. class PostsController extends AppController
  4. {
  5. public function my_action()
  6. {
  7. $this->render('custom_file');
  8. }
  9. }

This would render src/Template/Posts/custom_file.ctp instead ofsrc/Template/Posts/my_action.ctp.

You can also render views inside plugins using the following syntax:$this->render('PluginName.PluginController/custom_file').For example:

  1. namespace App\Controller;
  2.  
  3. class PostsController extends AppController
  4. {
  5. public function my_action()
  6. {
  7. $this->render('Users.UserDetails/custom_file');
  8. }
  9. }

This would render plugins/Users/src/Template/UserDetails/custom_file.ctp

Redirecting to Other Pages

  • Cake\Controller\Controller::redirect(string|array $url, integer $status)
  • The flow control method you’ll use most often is Controller::redirect().This method takes its first parameter in the form of aCakePHP-relative URL. When a user has successfully placed an order,you might wish to redirect him to a receipt screen.
  1. public function place_order()
  2. {
  3. // Logic for finalizing order goes here
  4. if ($success) {
  5. return $this->redirect(
  6. ['controller' => 'Orders', 'action' => 'thanks']
  7. );
  8. }
  9. return $this->redirect(
  10. ['controller' => 'Orders', 'action' => 'confirm']
  11. );
  12. }

The method will return the response instance with appropriate headers set.You should return the response instance from your action to preventview rendering and let the dispatcher handle actual redirection.

You can also use a relative or absolute URL as the $url argument:

  1. return $this->redirect('/orders/thanks');
  2. return $this->redirect('http://www.example.com');

You can also pass data to the action:

  1. return $this->redirect(['action' => 'edit', $id]);

The second parameter of Controller::redirect() allows you to define an HTTPstatus code to accompany the redirect. You may want to use 301(moved permanently) or 303 (see other), depending on the nature ofthe redirect.

If you need to redirect to the referer page you can use:

  1. return $this->redirect($this->referer());

An example using query strings and hash would look like:

  1. return $this->redirect([
  2. 'controller' => 'Orders',
  3. 'action' => 'confirm',
  4. '?' => [
  5. 'product' => 'pizza',
  6. 'quantity' => 5
  7. ],
  8. '#' => 'top'
  9. ]);

The generated URL would be:

  1. http://www.example.com/orders/confirm?product=pizza&quantity=5#top

Redirecting to Another Action on the Same Controller

  • Cake\Controller\Controller::setAction($action, $args…)
  • If you need to forward the current action to a different action on the _same_controller, you can use Controller::setAction() to update the request object, modify theview template that will be rendered and forward execution to the named action:
  1. // From a delete action, you can render the updated
  2. // list page.
  3. $this->setAction('index');

Loading Additional Models

  • Cake\Controller\Controller::loadModel(string $modelClass, string $type)
  • The loadModel() function comes handy when you need to use a modeltable/collection that is not the controller’s default one:
  1. // In a controller method.
  2. $this->loadModel('Articles');
  3. $recentArticles = $this->Articles->find('all', [
  4. 'limit' => 5,
  5. 'order' => 'Articles.created DESC'
  6. ]);

If you are using a table provider other than the built-in ORM you canlink that table system into CakePHP’s controllers by connecting itsfactory method:

  1. // In a controller method.
  2. $this->modelFactory(
  3. 'ElasticIndex',
  4. ['ElasticIndexes', 'factory']
  5. );

After registering a table factory, you can use loadModel to loadinstances:

  1. // In a controller method.
  2. $this->loadModel('Locations', 'ElasticIndex');

Note

The built-in ORM’s TableRegistry is connected by default as the ‘Table’provider.

Paginating a Model

  • Cake\Controller\Controller::paginate()
  • This method is used for paginating results fetched by your models.You can specify page sizes, model find conditions and more. See thepagination section for more details onhow to use paginate().

The $paginate attribute gives you an easy way to customize how paginate()behaves:

  1. class ArticlesController extends AppController
  2. {
  3. public $paginate = [
  4. 'Articles' => [
  5. 'conditions' => ['published' => 1]
  6. ]
  7. ];
  8. }

Configuring Components to Load

  • Cake\Controller\Controller::loadComponent($name, $config = [])
  • In your Controller’s initialize() method you can define any components youwant loaded, and any configuration data for them:
  1. public function initialize()
  2. {
  3. parent::initialize();
  4. $this->loadComponent('Csrf');
  5. $this->loadComponent('Comments', Configure::read('Comments'));
  6. }
  • property Cake\Controller\Controller::$components
  • The $components property on your controllers allows you to configurecomponents. Configured components and their dependencies will be created byCakePHP for you. Read the Configuring Components section for moreinformation. As mentioned earlier the $components property will be mergedwith the property defined in each of your controller’s parent classes.

Configuring Helpers to Load

  • property Cake\Controller\Controller::$helpers
  • Let’s look at how to tell a CakePHP Controller that you plan to useadditional MVC classes:
  1. class RecipesController extends AppController
  2. {
  3. public $helpers = ['Form'];
  4. }

Each of these variables are merged with their inherited values,therefore it is not necessary (for example) to redeclare theFormHelper, or anything that is declared in your AppController.

Deprecated since version 3.0: Loading Helpers from the controller is provided for backwards compatibilityreasons. You should see Configuring Helpers for how to load helpers.

Request Life-cycle Callbacks

CakePHP controllers trigger several events/callbacks that you can use to insertlogic around the request life-cycle:

Event List

  • Controller.initialize
  • Controller.startup
  • Controller.beforeRedirect
  • Controller.beforeRender
  • Controller.shutdown

Controller Callback Methods

By default the following callback methods are connected to related events if themethods are implemented by your controllers

  • Cake\Controller\Controller::beforeFilter(Event $event)
  • Called during the Controller.initialize event which occurs before everyaction in the controller. It’s a handy place to check for an active sessionor inspect user permissions.

Note

The beforeFilter() method will be called for missing actions.

Returning a response from a beforeFilter method will not prevent otherlisteners of the same event from being called. You must explicitlystop the event.

  • Cake\Controller\Controller::beforeRender(Event $event)
  • Called during the Controller.beforeRender event which occurs aftercontroller action logic, but before the view is rendered. This callback isnot used often, but may be needed if you are callingController\Controller::render() manually before the endof a given action.

  • Cake\Controller\Controller::afterFilter(Event $event)

  • Called during the Controller.shutdown event which is triggered afterevery controller action, and after rendering is complete. This is the lastcontroller method to run.

In addition to controller life-cycle callbacks, Componentsalso provide a similar set of callbacks.

Remember to call AppController’s callbacks within child controller callbacksfor best results:

  1. //use Cake\Event\Event;
  2. public function beforeFilter(Event $event)
  3. {
  4. parent::beforeFilter($event);
  5. }

More on Controllers