diff --git a/docs/en/controllers.md b/docs/en/controllers.md index 01976a3892..da901077f3 100644 --- a/docs/en/controllers.md +++ b/docs/en/controllers.md @@ -7,32 +7,47 @@ description: "Learn CakePHP controllers: handle requests, render views, manage c `class` Cake\\Controller\\**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 layer between the Model and View. You want to keep your -controllers thin, and your models fat. This will help you 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 `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. +Controllers are the 'C' in MVC. After routing is applied and the correct +controller is found, your controller's action is called. Your controller +should interpret the request, ensure the right models are called, and return +the appropriate response or view. Controllers sit between Model and View. + +::: tip Keep Controllers Thin +Move heavy business logic into models and services. Thin controllers are easier +to test and reuse. +::: + +Commonly, a controller manages logic around a single model. For example, for +an online bakery you might have a RecipesController managing recipes and an +IngredientsController managing 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. + +::: info At a Glance + +- Controllers coordinate request handling, model calls, and responses. +- Each public method is an action by default. +- Shared logic goes into `AppController`. + +::: + +Your application's controllers extend the `AppController` class, which extends +the core `Controller` class. The `AppController` class can be defined in +**src/Controller/AppController.php** and should contain methods shared between +all of your application's controllers. + +Controllers provide 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 interprets the request and creates the response. Usually +responses are rendered views, but there are other response types as well. + +::: details Naming and Conventions + +- Controller names are plural, e.g. `RecipesController`. +- Action names map to view templates by convention. +- Use `AppController` for shared behavior. + +::: @@ -88,6 +103,14 @@ CakePHP puts all the important request information into the `$this->request` property. See the section on [Cake Request](controllers/request-response#cake-request) for more information on the CakePHP request object. +::: info Request Flow Summary + +- Routes map URLs to a controller/action. +- The request data is available via `$this->request`. +- The action returns a response (often a rendered view). + +::: + ## Controller Actions Controller actions are responsible for converting the request parameters into a @@ -138,6 +161,11 @@ If for some reason you'd like to skip the default behavior, you can return a `Cake\Http\Response` object from the action with the fully created response. +::: tip Explicit Responses +Return a `Response` when you need full control (JSON, file downloads, or +custom status codes). +::: + 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. @@ -158,17 +186,20 @@ 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: -```php -// First you pass data from the controller: +::: code-group +```php [Controller] +// First you pass data from the controller: $this->set('color', 'pink'); +``` +```php [Template] // Then, in the view, you can utilize the data: -?> - You have selected 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: @@ -190,6 +221,11 @@ 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 and all elements inside the former two. +::: tip View Data Scope +View variables are shared with the layout and elements. Prefer specific keys +to avoid accidental collisions. +::: + ### Setting View Options If you want to customize the view class, layout/template paths, helpers or the @@ -228,6 +264,13 @@ Available strategies are: You can retrieve the current strategy using `getConfigMergeStrategy()`. +::: details When to Change Merge Strategy + +- Use shallow merges for small, explicit overrides. +- Use deep merges when you want to extend nested defaults. + +::: + ::: info Added in version 5.3.0 `ViewBuilder::setConfigMergeStrategy()` and `ViewBuilder::getConfigMergeStrategy()` were added. ::: @@ -265,25 +308,22 @@ Although CakePHP will automatically call it after every action's logic an alternate view file by specifying a view file name as first argument of `Controller::render()` method. +::: tip Skipping Auto-Render +Call `$this->disableAutoRender()` when the action fully handles the response. +::: + If `$view` starts with '/', it is assumed to be a view or element file relative to the **templates** folder. This allows direct rendering of elements, very useful in AJAX calls: -```php +::: code-group + +```php [Element] // Render the element in templates/element/ajaxreturn.php -$this->render('/element/ajaxreturn'); +return $this->render('/element/ajaxreturn'); ``` -The second parameter `$layout` of `Controller::render()` allows you to specify the layout -with which the view is rendered. - -#### Rendering a Specific Template - -In your controller, you may want to render a different view than the -conventional one. You can do this by calling `Controller::render()` directly. Once you -have called `Controller::render()`, CakePHP will not try to re-render the view: - -```php +```php [Custom Template] namespace App\Controller; class PostsController extends AppController @@ -295,14 +335,7 @@ class PostsController extends AppController } ``` -This would render **templates/Posts/custom_file.php** instead of -**templates/Posts/my_action.php**. - -You can also render views inside plugins using the following syntax: -`$this->render('PluginName.PluginController/custom_file')`. -For example: - -```php +```php [Plugin Template] namespace App\Controller; class PostsController extends AppController @@ -314,7 +347,22 @@ class PostsController extends AppController } ``` -This would render **plugins/Users/templates/UserDetails/custom_file.php** +::: + +The second parameter `$layout` of `Controller::render()` allows you to specify the layout +with which the view is rendered. + +#### Rendering a Specific Template + +In your controller, you may want to render a different view than the +conventional one. You can do this by calling `Controller::render()` directly. +Once you have called `Controller::render()`, CakePHP will not try to re-render +the view. + +This renders **templates/Posts/custom_file.php** instead of +**templates/Posts/my_action.php**. Rendering plugin templates uses the syntax +`$this->render('Users.UserDetails/custom_file')` and renders +**plugins/Users/templates/UserDetails/custom_file.php**. @@ -330,6 +378,10 @@ render an HTML view or render a JSON or XML response. To define the list of supported view classes for a controller is done with the `addViewClasses()` method: +::: info Content Negotiation +Use `addViewClasses()` to serve multiple formats from the same action. +::: + ```php namespace App\Controller; @@ -450,7 +502,9 @@ controller action and rendering a view. You can redirect using `routing array` values: -```php +::: code-group + +```php [Array URL] return $this->redirect([ 'controller' => 'Orders', 'action' => 'confirm', @@ -463,20 +517,20 @@ return $this->redirect([ ]); ``` -Or using a relative or absolute URL: - -```php +```php [Relative URL] return $this->redirect('/orders/confirm'); +``` +```php [Absolute URL] return $this->redirect('https://www.example.com'); ``` -Or to the referer page: - -```php +```php [Referer] return $this->redirect($this->referer()); ``` +::: + By using the second parameter you can define a status code for your redirect: ```php @@ -573,9 +627,9 @@ public function initialize(): void ## Request Life-cycle Callbacks CakePHP controllers trigger several events/callbacks that you can use to insert -logic around the request life-cycle: +logic around the request life-cycle. -### Event List +::: details Event List - `Controller.initialize` - `Controller.startup` @@ -583,10 +637,12 @@ logic around the request life-cycle: - `Controller.beforeRender` - `Controller.shutdown` +::: + ### Controller Callback Methods -By default, the following callback methods are connected to related events if the -methods are implemented by your controllers +By default, the following callback methods are connected to related events if +the methods are implemented by your controllers. #### beforeFilter() @@ -623,13 +679,12 @@ To redirect from within a controller callback method you can use the following: ```php public function beforeFilter(EventInterface $event): void { - if (...) { + if ($this->request->getParam('prefix') !== 'Admin') { $event->setResult($this->redirect('/')); return; } - - ... + // Normal request handling continues. } ```