Componentes (components) são pacotes com funções lógicas que são usadas para serem compartilhadas entre os controladores. Se você está querendo copiar e colar coisas entre os controladores, você pode criar funcionalidades em componentes para isso.
O CakePHP já vem com um conjunto de componentes para os mais diversos usos, por exemplo:
Segurança
Sessões
Lista de controle de acessos (ACL)
E-mails
Cookies
Autenticação
Manipulação de requisições
Cada um dos componentes será explicado em outros capítulos. Por enquanto, mostraremos apenas como criar seus próprios componentes. Criando componentes ajuda a manter o código do controlador limpo e permite que você reuse o código entre os projetos ou controladores.
Muitos dos componentes núcleo precisam ser configurados. Alguns exemplos
desses tipos de componentes são
Auth,
Cookie e
Email. Toda configuração
desses componentes, e de outros componentes em geral, é feita no método
beforeFilter()
do seu controlador.
function beforeFilter() {
$this->Auth->authorize = 'controller';
$this->Auth->loginAction = array('controller' => 'users', 'action' => 'login');
$this->Cookie->name = 'CookieMonster';
}
Um exemplo de como configurar as variáveis do componente no
beforeFilter()
do seu controller.
É possível, no entanto, um componente requerir certas opções de
configuração para ser ajustado antes do beforeFilter
do controller
ser executado. Para este fim, alguns componentes permitem opções de
configuração sejam ajustados no array $components
.
var $components = array('DebugKit.toolbar' => array('panels' => array('history', 'session'));
Consulte a documentação relevante para determinar qual opção de configuração cada componente provê.
Os componentes podem ter os callbacks
beforeRender
e
beforeRedirect
que são chamados antes da sua página ser renderizada
e antes de ser redirecionado, respectivamente.
Você pode desabilitar as chamadas destes callbacks
ajustando a
propriedade do componente desejado como false
Embora os componentes fornecem uma maneira de criar o código controlador
reutilizável, isso executa uma taréfa especifica. Componentes igualmente
oferecem uma maneira de enganchar no fluxo geral da aplicação. Há 5
ganchos pré definidos, e muito mais podem ser criados dinamicamente
usando Component::triggerCallback
.
Os core callbacks são:
initialize() é acionado antes beforeFilter do controlador, mas depois que os modelos forem construídos.
startup() é acionado após beforeFilter dos controladores, mas antes da ação do controlador.
beforeRender() é acionado antes da view ser renderizada.
beforeRedirect()é acionado antes de um redirecionamento é feito a partir de um controlador. Você pode usar o retorno da chamada para substituir a url a ser utilizada para o redirecionamento.
shutdown() é acionado após rendereziar a view e é processado antes que a resposta é retornada.
Você pode adicionar métodos adicionais para os seus componentes, e
chamar esses métodos, a qualquer momento, usando
Component::triggerCallback()
. Se você tivesse acrescentado um
onAccess
callback para os seus componentes. Você pode disparar
aquele callback a partir do controlador chamando
$this->Component->triggerCallback('onAccess', $this);
Você pode desativar o o retorno do callback, definindo para false
.
Suponha que sua aplicação online precisa utilizar funções complexas de matemática em diversas partes da aplicação. Poderíamos, então, criar um componente para que esta lógica seja compartilhada entre diversos controladores.
O primeiro passo é criar um arquivo para o componente e uma classe. Crie o arquivo em /app/controllers/components/math.php. A estrutura básica do arquivo do componente é similar a apresentada abaixo.
<?php
class MathComponent extends Object {
function doComplexOperation($amount1, $amount2) {
return $amount1 + $amount2;
}
}
?>
Quando seu componente estiver criado, nós podemos utilizá-lo nos controladores da aplicação colocando o nome do componente no vetor da variável $components:
// Isso faz com que o novo componente possa ser acessado usando $this->Math
var $components = array('Math', 'Session');
Uma vez que o componente está finalizado, nós podemos usar ele nos controladores de nossa aplicação colocando o nome do componente (sem a parte «Component«) na variável $components do controlador, permitindo que possamos acessar uma instância do mesmo.
/* Fazendo com que o componente esteja disponível através
de $this->Math, bem como o padrão $this->Session */
var $components = array('Math', 'Session');
Componente declarados em AppController
serão mesclados com os outros
de seus controladores. Então não é necessário redeclarar o mesmo
componente duas vezes.
Quando estiver incluindo Componentes em um Controlador você também pode
declarar parâmetros que serão passadas para o método initialize()
do
Componente. Estes parâmetros podem ser tratados pelo Componente.
var $components = array(
'Math' => array(
'precision' => 2,
'randomGenerator' => 'srand'
),
'Session', 'Auth'
);
Acima será passado um vetor contendo os parâmetros precision e randomGenerator para o método initialize() do componente MathComponent’s.
Esta sintaxe não esta implementada em nenhum Componente padrão do CakePHP até o momento
Os componentes possuem um número de callbacks usados pela classe controller pai. O uso sensato destes callbacks podem fazer criar e usar compomentes muito fácil
initialize($controller, $settings=array())
O método initialize é chamado antes do método beforeFilter do controller
startup($controller)
O método startup é chamado depois do método beforeFilter do controle, mas antes do controller executar a action corrente.
beforeRender($controller)
O método beforeRender é chamado depois do método beforeRender do controller, mas antes do controller renderizar a view e o layout.
shutdown($controller)
O método shutdown é chamado antes da saída ser enviada ao browser.
beforeRedirect($controller, $url, $status=null, $exit=true)
O método beforeRedirect é invocado quando o método redirect do controller é chamado, mas antes de qualquer outra action. Se este método retornar false o controller não continuará na requisição de redirecionamento. As variáveis $url, $status e $exit tem os mesmos significados como o método do controller.
Aqui está um component esqueleto que você pode usar como um template para seus próprios components personalizados.
<?php
class SkeletonComponent extends Object {
//chamado antes do Controller::beforeFilter()
function initialize($controller, $settings = array()) {
// salvando a referência do controller para uso posterior
$this->controller = $controller;
}
//chamado depois do Controller::beforeFilter()
function startup($controller) {
}
//chamado depois do Controller::beforeRender()
function beforeRender($controller) {
}
//chamado depois do Controller::render()
function shutdown($controller) {
}
//chamado antes do Controller::redirect()
function beforeRedirect($controller, $url, $status=null, $exit=true) {
}
function redirectSomewhere($value) {
// utilizando um método de controller
$this->controller->redirect($value);
}
}
?>
Você deve também querer utilizar outro componente dentro de um componente personalizado. Para fazer isso, apenas crie uma variável de classe $components (exatamente como você faria em um controller) como um array que contém os nomes dos components que você deseja utilizar.
<?php
class MyComponent extends Object {
// Este componente usa outros componentes
var $components = array('Session', 'Math');
function doStuff() {
$result = $this->Math->doComplexOperation(1, 2);
$this->Session->write('stuff', $result);
}
}
?>
Acessar ou usar um model em um component não é muito recomendado; Se você acabar precisando usar um, você precisa instanciar sua model class e usá-la manualmente. Aqui vai um exemplo:
<?php
class MathComponent extends Object {
function doComplexOperation($amount1, $amount2) {
return $amount1 + $amount2;
}
function doReallyComplexOperation ($amount1, $amount2) {
$userInstance = ClassRegistry::init('User');
$totalUsers = $userInstance->find('count');
return ($amount1 + $amount2) / $totalUsers;
}
}
?>
Em alguns momentos um de seus componentes precisa usar outro componente.
Você pode incluir outro componente em seu componente da mesma maneira
que você inclui eles nos controladores: Use a variável $components
.
<?php
class CustomComponent extends Object {
var $name = "Custom"; // o nome do componente
var $components = array( "Existing" ); // o outro componente que você deseja usar
function initialize(&$controller) {
$this->Existing->foo();
}
function bar() {
// ...
}
}
?>
<?php
class ExistingComponent extends Object {
var $name = "Existing";
function initialize(&$controller) {
$this->Parent->bar();
}
function foo() {
// ...
}
}
?>