This document is for a version of CakePHP that is no longer supported. Please upgrade to a newer release!
Los componentes son paquetes de lógica que son compartidos entre los controladores. Si tiene ganas de copiar y pegar código de un controlador a otro, debería antes considerar agrupar algunas funcionalidades en un componente.
CakePHP incluye un conjunto fantástico de componentes listos para usar para conseguir ayuda con:
Seguridad
Sesiones
Lista de control de acceso (ACL)
Emails
Cookies
Autenticación
Manejo de pedidos (Requests)
Cada uno de estos componentes del núcleo (Core) son detallados en su propio capitulo. Por el momento, veremos como crear sus propios componentes. Con esto ayudará a mantener el código de los controladores limpio y le será mas sencillo reusar código entre proyectos.
Muchos de los componentes básicos requieren ser configurados. Algunos
ejemplos de componentes que requieren ser configurados son:
Auth,
Cookie e
Email. Toda la configuración
de estos componentes y los componentes en general se hacen en el método
del controlador beforeFilter()
.
function beforeFilter() {
$this->Auth->authorize = 'controller';
$this->Auth->loginAction = array('controller' => 'users', 'action' => 'login');
$this->Cookie->name = 'CookieMonster';
}
El código anterior sería un ejemplo de configuración de las variables de
componente del controlador beforeFilter()
While components provide a way to create reusable controller code, that
performs a specific task. Components also offer a way to hook into the
general application flow. There are 5 built-in hooks, and more can be
created dynamically using Component::triggerCallback
.
The core callbacks are:
initialize() is fired before the controller’s beforeFilter, but after models have been constructed.
startup() is fired after the controllers” beforeFilter, but before the controller action.
beforeRender() is fired before a view is rendered.
beforeRedirect() is fired before a redirect is done from a controller. You can use the return of the callback to replace the url to be used for the redirect.
shutdown() is fired after the view is rendered and before the response is returned.
You can add additional methods to your components, and call those
methods at any time by using Component::triggerCallback()
. If you
had added a onAccess
callback to your components. You could fire
that callback from within the controller by calling
$this->Component->triggerCallback('onAccess', $this);
You can disable the callbacks triggering by setting the enabled
property of a component to false
.
Supongamos que nuestra aplicación online necesita efectuar una compleja operación matemática en muchas partes de la aplicación. Creariamos un componente que albergara esa lógica compartida para poder ser usada en diferentes controladores
El primer paso es crear una nueva clase y fichero de componente. Crea el fichero en /app/controllers/components/math.php. La estructura básica para el componente quedaría así.
<?php
class MathComponent extends Object {
function doComplexOperation($amount1, $amount2) {
return $amount1 + $amount2;
}
}
?>
Una vez finalizado nuestro componente, podemos usarlo en los controladores de la aplicación añadiendo su nombre (excepto la parte «Component» al array $components del controlador. Automáticamente, el controlador recibirá un nuevo atributo con un nombre a partir del nombre del componente, a través del cual podremos acceder a una instancia del mismo:
/* Hace el nuevo componente accesible en $this->Math,
al igual que el standard $this->Session */
var $components = array('Math', 'Session');
Los componentes declarados en AppController serán combinados con los de tus otros controladores, así que no hay necesidad de redeclarar el mismo componente dos veces.
Cuando se incluyen Componentes a un Controlador tambien puedes declarar un conjunto de parámetros que serán pasados al método intialize() de los Componentes. Estos parámetros pueden ser manejados por el Componente.
var $components = array(
'Math' => array(
'precision' => 2,
'randomGenerator' => 'srand'
),
'Session', 'Auth'
);
Este código pasaría el array conteniendo precision y randomGenerator al método intialize() de MathComponent como segundo parámetro.
Por ahora, esta sintaxis no está implementada por ninguno de los Componentes Core
Para acceder a la instancia del controlador desde tu recien creado componente, necesitarás implementar el método initialize() o el startup(). Estos métodos especiales llevan una referencia al controlador como primer parámetro y son llamados automáticamente. El método initialize() es llamado antes del método beforeFilter(), y el método startup() después del método beforeFilter. Si por algún motivo no deseas que el método startup() sea llamado cuando el controlador está inicializando cosas, dale el valor true a la variable $disableStartup.
Si deseas insertar algún código de lógica antes de que el controlador beforeFilter() sea llamado, necesitarás usar el método initialize() del componente.
<?php
class CheckComponent extends Object {
//llamado antse de Controller::beforeFilter()
function initialize(&$controller) {
// salvando la referencia al controlador para uso posterior
$this->controller =& $controller;
}
//llamado tras Controller::beforeFilter()
function startup(&$controller) {
}
function redirectSomewhere($value) {
// ulizando un método de controlador
$this->controller->redirect($value);
}
}
?>
También podrias querer utilizar otros componentes dentro del componente a medida. Para ello, simplemente crea una variable de clase $components (tal como lo harías en un controlador ) como un array que contenga los nombres de los componentes que quieres utilizar.
<?php
class MyComponent extends Object {
// Este componente usa otros componentes
var $components = array('Session', 'Math');
function doStuff() {
$result = $this->Math->doComplexOperation(1, 2);
$this->Session->write('stuff', $result);
}
}
?>
No es muy recomendable acceder o usar un modelo en un componente, pero si tras sopesar las posibilidades eso es lo que quieres hacer, tendrás que instanciar tu clase modelo y usarla manualmente. Aquí tienes un ejemplo:
<?php
class MathComponent extends Object {
function doComplexOperation($amount1, $amount2) {
return $amount1 + $amount2;
}
function doUberComplexOperation ($amount1, $amount2) {
$userInstance = ClassRegistry::init('User');
$totalUsers = $userInstance->find('count');
return ($amount1 + $amount2) / $totalUsers;
}
}
?>
A veces uno de tus componentes puede depender de otro. Si las funcionalidades que estos componentes proveen no están relacionados, excepto por su dependencia el uno del otro, entonces no querrás ponerlos dentro de un solo componente.
En cambio puedes hacer que tu componente sea un «Padre» e indicarle con
el array $components
la lista de sus «Hijos». Los componentes padres
se cargan antes que sus componentes hijos, y cada componente hijo tiene
acceso a su padre.
Declaración del padre:
<?php
class PadreComponent extends Object {
var $name = "Padre";
var $components = array( "Hijo" );
function initialize(&$controller) {
$this->Hijo->foo();
}
function bar() {
// ...
}
}
Declaración del hijo:
<?php
class HijoComponent extends Object {
var $name = "Hijo";
function initialize(&$controller) {
$this->Padre->bar();
}
function foo() {
// ...
}
}