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 invarious common tasks. You can also create your own components. If you findyourself wanting to copy and paste things between controllers, you shouldconsider creating your own component to contain the functionality. Creatingcomponents keeps controller code clean and allows you to reuse code betweendifferent controllers.

For more information on the components included in CakePHP, check out thechapter for each component:

Configuring Components

Many of the core components require configuration. Some examples of componentsrequiring configuration are AuthComponent andCookie. Configuration for these components,and for components in general, is usually done via loadComponent() in yourController’s initialize() method or via the $components array:

  1. class PostsController extends AppController
  2. {
  3. public function initialize()
  4. {
  5. parent::initialize();
  6. $this->loadComponent('Auth', [
  7. 'authorize' => 'Controller',
  8. 'loginAction' => ['controller' => 'Users', 'action' => 'login']
  9. ]);
  10. $this->loadComponent('Cookie', ['expires' => '1 day']);
  11. }
  12.  
  13. }

You can configure components at runtime using the config() method. Often,this is done in your controller’s beforeFilter() method. The above couldalso be expressed as:

  1. public function beforeFilter(Event $event)
  2. {
  3. $this->Auth->config('authorize', ['controller']);
  4. $this->Auth->config('loginAction', ['controller' => 'Users', 'action' => 'login']);
  5.  
  6. $this->Cookie->config('name', 'CookieMonster');
  7. }

Like helpers, components implement a config() method that is used to get andset any configuration data for a component:

  1. // Read config data.
  2. $this->Auth->config('loginAction');
  3.  
  4. // Set config
  5. $this->Csrf->config('cookieName', 'token');

As with helpers, components will automatically merge their $_defaultConfigproperty with constructor configuration to create the $_config propertywhich is accessible with config().

Aliasing Components

One common setting to use is the className option, which allows you toalias components. This feature is useful when you want toreplace $this->Auth or another common Component reference with a customimplementation:

  1. // src/Controller/PostsController.php
  2. class PostsController extends AppController
  3. {
  4. public function initialize()
  5. {
  6. $this->loadComponent('Auth', [
  7. 'className' => 'MyAuth'
  8. ]);
  9. }
  10. }
  11.  
  12. // src/Controller/Component/MyAuthComponent.php
  13. use Cake\Controller\Component\AuthComponent;
  14.  
  15. class MyAuthComponent extends AuthComponent
  16. {
  17. // Add your code to override the core AuthComponent
  18. }

The above would alias MyAuthComponent to $this->Auth in yourcontrollers.

Note

Aliasing a component replaces that instance anywhere that component is used,including inside other Components.

Loading Components on the Fly

You might not need all of your components available on every controlleraction. In situations like this you can load a component at runtime using theloadComponent() method in your controller:

  1. // In a controller action
  2. $this->loadComponent('OneTimer');
  3. $time = $this->OneTimer->getTime();

Note

Keep in mind that components loaded on the fly will not have missedcallbacks called. If you rely on the beforeFilter or startupcallbacks being called, you may need to call them manually depending on whenyou load your component.

Using Components

Once you’ve included some components in your controller, using them is prettysimple. Each component you use is exposed as a property on your controller. Ifyou had loaded up the Cake\Controller\Component\FlashComponentin your controller, you could access it like so:

  1. class PostsController extends AppController
  2. {
  3. public function initialize()
  4. {
  5. parent::initialize();
  6. $this->loadComponent('Flash');
  7. }
  8.  
  9. public function delete()
  10. {
  11. if ($this->Post->delete($this->request->getData('Post.id')) {
  12. $this->Flash->success('Post deleted.');
  13. return $this->redirect(['action' => 'index']);
  14. }
  15. }

Note

Since both Models and Components are added to Controllers asproperties they share the same ‘namespace’. Be sure to not give acomponent and a model the same name.

Creating a Component

Suppose our application needs to perform a complex mathematical operation inmany different parts of the application. We could create a component to housethis shared logic for use in many different controllers.

The first step is to create a new component file and class. Create the file insrc/Controller/Component/MathComponent.php. The basic structure for thecomponent would look something like this:

  1. namespace App\Controller\Component;
  2.  
  3. use Cake\Controller\Component;
  4.  
  5. class MathComponent extends Component
  6. {
  7. public function doComplexOperation($amount1, $amount2)
  8. {
  9. return $amount1 + $amount2;
  10. }
  11. }

Note

All components must extend Cake\Controller\Component. Failingto do this will trigger an exception.

Including your Component in your Controllers

Once our component is finished, we can use it in the application’scontrollers by loading it during the controller’s initialize() method.Once loaded, the controller will be given a new attribute named after thecomponent, through which we can access an instance of it:

  1. // In a controller
  2. // Make the new component available at $this->Math,
  3. // as well as the standard $this->Csrf
  4. public function initialize()
  5. {
  6. parent::initialize();
  7. $this->loadComponent('Math');
  8. $this->loadComponent('Csrf');
  9. }

When including Components in a Controller you can also declare aset of parameters that will be passed on to the Component’sconstructor. These parameters can then be handled bythe Component:

  1. // In your controller.
  2. public function initialize()
  3. {
  4. parent::initialize();
  5. $this->loadComponent('Math', [
  6. 'precision' => 2,
  7. 'randomGenerator' => 'srand'
  8. ]);
  9. $this->loadComponent('Csrf');
  10. }

The above would pass the array containing precision and randomGenerator toMathComponent::initialize() in the $config parameter.

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 sameway you include them in controllers - using the $components var:

  1. // src/Controller/Component/CustomComponent.php
  2. namespace App\Controller\Component;
  3.  
  4. use Cake\Controller\Component;
  5.  
  6. class CustomComponent extends Component
  7. {
  8. // The other component your component uses
  9. public $components = ['Existing'];
  10.  
  11. // Execute any other additional setup for your component.
  12. public function initialize(array $config)
  13. {
  14. $this->Existing->foo();
  15. }
  16.  
  17. public function bar()
  18. {
  19. // ...
  20. }
  21. }
  22.  
  23. // src/Controller/Component/ExistingComponent.php
  24. namespace App\Controller\Component;
  25.  
  26. use Cake\Controller\Component;
  27.  
  28. class ExistingComponent extends Component
  29. {
  30.  
  31. public function foo()
  32. {
  33. // ...
  34. }
  35. }

Note

In contrast to a component included in a controllerno callbacks will be triggered on a component’s component.

Accessing a Component’s Controller

From within a Component you can access the current controller through theregistry:

  1. $controller = $this->_registry->getController();

You can access the controller in any callback method from the eventobject:

  1. $controller = $event->getSubject();

Component Callbacks

Components also offer a few request life-cycle callbacks that allow them toaugment the request cycle.

  • beforeFilter(Event $event)
  • Is called before the controller’sbeforeFilter method, but after the controller’s initialize() method.

  • startup(Event $event)

  • Is called after the controller’s beforeFiltermethod but before the controller executes the current actionhandler.

  • beforeRender(Event $event)

  • Is called after the controller executes the requested action’s logic,but before the controller renders views and layout.

  • shutdown(Event $event)

  • Is called before output is sent to the browser.

  • beforeRedirect(Event $event, $url, Response $response)

  • Is invoked when the controller’s redirectmethod is called but before any further action. If this methodreturns false the controller will not continue on to redirect therequest. The $url, and $response parameters allow you to inspect and modifythe location or any other headers in the response.