.. php:namespace:: Cake\Controller
.. php:class:: Controller
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 :php:class:`Controller` class. The AppController
class can be defined in /src/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.
As stated in the introduction, the AppController
class is the parent class
to all of your application's controllers. AppController
itself extends the
:php:class:`Cake\\Controller\\Controller` class included in CakePHP.
AppController
is defined in /src/Controller/AppController.php
as
follows:
namespace App\Controller; use Cake\Controller\Controller; class AppController extends Controller { }
Controller attributes and methods created in your AppController
will be
available in all controllers that extend it. Components (which you'll
learn about later) are best used for code that is used in many (but not
necessarily all) controllers.
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
:php:attr:`~Cake\\Controller\\Controller::$helpers` property in your
AppController
.
Also remember to call AppController
's callbacks within child
controller callbacks for best results:
public function beforeFilter(Event $event) { parent::beforeFilter($event); }
When a request is made to a CakePHP application, CakePHP's
:php:class:`Cake\\Routing\\Router` and :php:class:`Cake\\Routing\\Dispatcher`
classes use :ref:`routes-configuration` to find and create the correct
controller instance. 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 :ref:`cake-request` for more information on the
CakePHP request object.
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 /src/Controller/RecipesController.php
and contain:
# /src/Controller/RecipesController.php class RecipesController extends AppController { public function view($id) { // Action logic goes here.. } public function share($customerId, $recipeId) { // Action logic goes here.. } public function search($query) { // Action logic goes here.. } }
The view files for these actions would be /src/Template/Recipes/view.ctp
,
/src/Template/Recipes/share.ctp
, and /src/Template/Recipes/search.ctp
. The
conventional view file name is the lowercased and underscored version of the
action name.
Controller actions generally use
Controller::set()
to create a context that
View
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, you can return a :php:class:`Cake\\Network\\Response` object from the action with the fully created response.
When you use controller methods with
:php:meth:`~Cake\\Routing\\RequestActionTrait::requestAction()`
you will typcially retun a Response
istance. 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->Recipes->find('popular'); if (!$this->request->is('requested')) { $this->response->body(json_encode($popular)); return $this->response; } $this->set('popular', $popular); } }
The above controller action is an example of how a method can be used with
:php:meth:`~Cake\\Routing\\RequestActionTrait::requestAction()` and normal
requests. See the :doc:`request-action` section for more tips on using
requestAction()
.
In order for you to use a controller effectively in your own application, we'll cover some of the core attributes and methods provided by CakePHP's controllers.
CakePHP controllers come fitted with callbacks you can use to insert logic around the request life-cycle:
.. php:method:: beforeFilter(Event $event) This function is executed before every action in the controller. It's a handy place to check for an active session or inspect user permissions. .. note:: The beforeFilter() method will be called for missing actions.
.. php:method:: beforeRender(Event $event) 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 :php:meth:`Cake\\Controller\\Controller::render()` manually before the end of a given action.
.. php:method:: afterFilter(Event $event) 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, :doc:`/controllers/components` also provide a similar set of callbacks.
Controllers interact with views in a number of ways. First, they
are able to pass data to the views, using Controller::set()
. You can also
decide which view class to use, and which view file should be
rendered from the controller.
.. php:method:: set(string $var, mixed $value)
The Controller::set()
method is the main way to send data from your
controller to your view. Once you've used Controller::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 <?= h($color) ?> icing for the cake.
The Controller::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:
$data = [ 'color' => 'pink', 'type' => 'sugar', 'base_price' => 23.95 ]; // Make $color, $type, and $base_price // available to the view: $this->set($data);
.. php:method:: render(string $view, string $layout)
The render()
method is automatically called at the end of each requested
controller action. This method performs all the view logic (using the data
you've submitted using the set()
method), places the view inside its
View::$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:
namespace App\Controller; class RecipesController extends AppController { // ... public function search() { // Render the view in /src/Template/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 file name as first argument of
render()
method.
If $view
starts with '/', it is assumed to be a view or
element file relative to the /src/Template
folder. This allows
direct rendering of elements, very useful in AJAX calls:
// Render the element in /src/Template/Element/ajaxreturn.ctp $this->render('/Element/ajaxreturn');
The second parameter $layout
of render()
allows you to specify the layout
with which the view is rendered.
In your controller, you may want to render a different view than the
conventional one. You can do this by calling render()
directly. Once you
have called render()
, CakePHP will not try to re-render the view:
namespace App\Controller; class PostsController extends AppController { public function my_action() { $this->render('custom_file'); } }
This would render /src/Template/Posts/custom_file.ctp
instead of
/src/Template/Posts/my_action.ctp
You can also render views inside plugins using the following syntax:
$this->render('PluginName.PluginController/custom_file')
.
For example:
namespace App\Controller; class PostsController extends AppController { public function my_action() { $this->render('Users.UserDetails/custom_file'); } }
This would render /plugins/Users/src/Template/UserDetails/custom_file.ctp
.. php:method:: 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 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( ['controller' => 'Orders', 'action' => 'thanks'] ); } return $this->redirect( ['controller' => 'Orders', 'action' => 'confirm'] ); }
The method will return the response instance with appropriate headers set. You should return the response instance from your action to prevent view rendering and let the dispatcher handle actual redirection.
You can also use a relative or absolute URL as the $url argument:
return $this->redirect('/orders/thanks'); return $this->redirect('http://www.example.com');
You can also pass data to the action:
return $this->redirect(['action' => 'edit', $id]);
The second parameter of redirect()
allows you to define an HTTP
status code to accompany the redirect. You may want to use 301
(moved permanently) or 303 (see other), depending on the nature of
the redirect.
If you need to redirect to the referer page you can use:
return $this->redirect($this->referer());
An example using query strings and hash would look like:
return $this->redirect([ 'controller' => 'Orders', 'action' => 'confirm', '?' => [ 'product' => 'pizza', 'quantity' => 5 ], '#' => 'top' ]);
The generated URL would be:
http://www.example.com/orders/confirm?product=pizza&quantity=5#top
.. php:method:: paginate()
This method is used for paginating results fetched by your models.
You can specify page sizes, model find conditions and more. See the
:doc:`pagination <core-libraries/components/pagination>` section for more details on
how to use paginate()
The paginate attribute gives you an easy way to customize how paginate()
behaves:
class ArticlesController extends AppController { public $paginate = [ 'Articles' => [ 'conditions' => ['published' => 1] ] ]; }
.. php:method:: loadModel(string $modelClass, string $type)
The loadModel
function comes handy when you need to use a model
table/collection that is not the controller's default one:
$this->loadModel('Articles'); $recentArticles = $this->Articles->find('all', [ 'limit' => 5, 'order' => 'Articles.created DESC' ]);
If you are using a table provider other than the built-in ORM you can link that table system into CakePHP's controllers by connecting its factory method:
$this->modelFactory( 'ElasticIndex', ['ElasticIndexes', 'factory'] );
After registering a table factory, you can use loadModel
to load
instances:
$this->loadModel('Locations', 'ElasticIndex');
Note
The built-in ORM's TableRegistry is connected by default as the 'Table' provider.
.. php:attr:: components
The $components
property on your controllers allows you to configure
components. Configured components and their dependencies will be created by
CakePHP for you. Read the :ref:`configuring-components` section for more
information. As mentioned earlier the $components
property will be merged
with the property defined in each of you controller's parent classes.
.. php:attr:: helpers
If you choose to define your own Controller::$helpers
array in
AppController
, make sure to include HtmlHelper
and
FormHelper
if you want them available by default in your
Views. To learn more about these classes, be sure to check out their
respective sections later in this manual.
Let's look at how to tell a CakePHP Controller that you plan to use additional MVC classes:
class RecipesController extends AppController { public $helpers = ['Form']; public $components = ['RequestHandler']; }
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
.
.. toctree:: :maxdepth: 1 controllers/request-response controllers/pages-controller controllers/components