Objetos de Requisição e Resposta
Os objetos Request e Response são novos no CakePHP 2.0.
Anteriormente, estes objetos eram representados por arrays e os métodos
relacionados espalhados nas classes RequestHandlerComponent
,
Router
, Dispatcher
e Controller
.
Não havia nenhum objeto com autoridades sobre as informações contidas em uma
requisição. No CakePHP 2.0, as classes CakeRequest
e
CakeResponse
são usadas para este propósito.
CakeRequest
A classe CakeRequest
é o objeto padrão para requisições usadas no
CakePHP. Ela centraliza inúmeras funcionalidades para interagir com os dados das
requisições.
A cada requisição feita, um CakeRequest
é criado e passado por referência para
as várias camadas de uma aplicação que usam os dados de uma requisição. Por
padrão, CakeRequest
é atribuído em $this->request
e é disponibilizado
nos controller, views e helpers. Você pode também acessá-la em componentes
usando a referência do controller. Algumas das tarefas que o CakeRequest
executa inclui:
Processar os arrays GET, POST e FILES na estrutura de dados que você está
familiarizado.
Fornecer a introspecção do ambiente pertencente a requisição. Coisas como
cabeçalhos enviados, endereço IP dos clientes e informações de
domínio/subdomínio sobre o servidor que a aplicação está rodando.
Prover acesso aos parâmetros da requisição pelo uso de arrays ou propriedades
do objeto.
Acessando parâmetros de uma Requisição
O CakeRequest expõe várias maneiras de acessar os parâmetros de uma requisição.
A primeira é o acesso por índices de array, a segunda maneira é pelo
$this->request->params
e a terceira por propriedades do objeto:
$this->request['controller'];
$this->request->controller;
$this->request->params['controller']
Todas as alternativas acima irão acessar o mesmo valor.
Foram criadas várias maneiras de acessar os parâmetros para facilitar a migração
de aplicações existentes que utilizam versões antigas do Cake.
Todos os Route Elements podem ser acessados por esta interface.
além dos Route Elements, muitas vezes você precisará ter acesso aos
Passed Arguments e os Named Parameters. Ambos estarão disponíveis
no objeto da classe CakeRequest:
// Argumentos passados
$this->request['pass'];
$this->request->pass;
$this->request->params['pass'];
// Parâmetros nomeados
$this->request['named'];
$this->request->named;
$this->request->params['named'];
Todos irão lhe proporcionar o acesso aos argumentos passados e os parâmetros
nomeados. Existem diversos parâmetros que são importantes/úteis que o CakePHP
utiliza internamente e podem também ser encontrados nos parâmetros da
requisição:
plugin
O nome do plugin que trata a requisição. será null
quando não
for nenhum plugin.
controller
O nome do controller que trata a requisição corrente.
action
A ação responsável por manipular a requisição corrente.
prefix
O prefixo da ação corrente. Veja Prefix Routing para mais
informações.
bare
Presente quando uma requisição chega por meio do método
requestAction()
e inclui a opção bare
. Requisições despidas (bare)
não possuem layouts.
requested
Presente e definida como true
quando vindas de um uma
chamada do método requestAction()
.
Acessando parâmetros do tipo querystring
Parâmetros do tipo “query string” presentes tipicamente em requisições do tipo
GET podem ser lidos usando CakeRequest::$query
:
// Sendo a url /posts/index?page=1&sort=title
$this->request->query['page'];
// Você também pode acessar o valor via array
$this->request['url']['page'];
Acessando dados em requisições do tipo POST
Todos os dados encontrados em requisições do tipo POST podem ser acessados
usando o atributo CakeRequest::$data
. Qualquer dado passado por
formulários que contenha o prefixo data
terá este prefixo removido.
Por exemplo:
// Uma tag input com o atributo "name" igual a 'data[Post][title]' é
acessavel em:
$this->request->data['Post']['title'];
você pode acessar a propriedade data como também pode usar o método
CakeRequest::data()
para ler os dados do array de forma a evitar
erros. Qualquer chave que não exista irá retornar o valor null
. Desta
maneira não é preciso verificar se a chave existe antes de usá-la:
$foo = $this->request->data('Valor.que.nao.existe');
// $foo == null
Acessando dados XML ou JSON
Aplicações que empregam métodos REST muitas vezes
transferem dados em formatos não codificados no padrão URL. Você pode ler estas
entradas de dados com qualquer formato usando o método
CakeRequest::input()
. Fornecendo uma função de decodificação, você
pode receber o conteúdo em um formato desserializado:
// Obtém dados codificados no formato JSON submetidos por um método PUT/POST
$data = $this->request->input('json_decode');
Como alguns métodos de desserialização requerem parâmetros adicionais ao serem
chamados, como a opção “as array” da função json_decode
ou se você quiser
um XML convertido em um objeto DOMDocument
, o método
CakeRequest::input()
também suporta a passagem de parâmetros
adicionais:
// Obtém dados codificados em XML submetidos por um método PUT/POST
$data = $this->request->input('Xml::build', array('return' => 'domdocument'));
Inspecionando a Requisição
Anteriormente, era preciso utilizar o RequestHandlerComponent
para detectar vários aspectos de uma requisição. Estes métodos foram
transferidos para o CakeRequest
e esta classe oferece uma nova interface
enquanto mantem certa compatibilidade com as versões anteriores do Cake:
$this->request->is('post');
$this->request->isPost();
Ambas os métodos chamados irão retornar o mesmo valor. Por enquanto os métodos
ainda são disponibilizados no RequestHandler mas são depreciados e ainda podem
ser removidos futuramente. Você também pode facilmente estender os detectores
que estão disponíveis usando o método CakeRequest::addDetector()
para criar novos tipos de detectores. Existem quatro formas diferentes de
detectores que você pode criar:
Comparação de valores de ambiente - Uma comparação feita em valores do ambiente
compara valores encontrados pela função env()
no ambiente da
aplicação, com o valor fornecido.
Comparação por expressão regular - Permite comparar valores encontrados pela
função env()
com uma expressão regular fornecida.
Comparação baseada em opções - Usa uma lista de opções para criar expressões
regulares. Chamadas subsequentes para adicionar opções já fornecidas ao
detector serão mescladas.
Detectores do tipo Callback - Permitem fornecer um “callback” para tratar a
verificação. O callback irá receber o objeto de requisição como parâmetro
único.
Alguns exemplos de uso:
// Adiciona um detector baseado em variáveis do ambiente
$this->request->addDetector('post', array('env' => 'REQUEST_METHOD', 'value' => 'POST'));
// Adicionar um detector usando expressões regulares
$this->request->addDetector('iphone', array('env' => 'HTTP_USER_AGENT', 'pattern' => '/iPhone/i'));
// Adicionar um detector baseado em uma lista de opções
$this->request->addDetector('internalIp', array(
'env' => 'CLIENT_IP',
'options' => array('192.168.0.101, '192.168.0.100')
));
// Adiciona um detector callback. Pode ser tanto uma função anônima
// quanto o nome de uma função a ser chamada.
$this->request->addDetector('awesome', function ($request) {
return isset($request->awesome);
});
O CakeRequest
também inclui métodos como CakeRequest::domain()
,
CakeRequest::subdomains()
e CakeRequest::host()
para
ajudar em aplicações que utilizam subdomínios, tornando a vida um pouco mais
fácil.
Existem vários detectores inclusos no Cake que você já pode usar:
is('get')
Verifica se a requisição corrente é do tipo GET.
is('put')
Verifica se a requisição corrente é do tipo PUT.
is('post')
Verifica se a requisição corrente é do tipo POST.
is('delete')
Verifica se a requisição corrente é do tipo DELETE.
is('head')
Verifica se a requisição corrente é do tipo HEAD.
is('options')
Verifica se a requisição corrente é do tipo OPTIONS.
is('ajax')
Verifica se a requisição corrente acompanha o cabeçalho
X-Requested-With = XMLHttpRequest.
is('ssl')
Verifica se a requisição corrente é via SSL.
is('flash')
Verifica se a requisição foi feita por um objeto do Flash.
is('mobile')
Verifica se a requisição veio de uma lista comum de
dispositivos móveis.
CakeRequest e o RequestHandlerComponent
Como muitas das caracteristicas que o CakeRequest
oferece eram de domínio
do componente RequestHandlerComponent
, foi preciso repensar como
esta se encaixa no quadro atual. Para o CakePHP 2.0, a classe
RequestHandlerComponent
age como uma cereja em cima do bolo.
Provendo uma camada adicional de funcionalidades sobre o CakeRequest
, como
a mudança do layout baseado no tipo de conteúdo ou chamadas em ajax.
A separação destas duas classes permitem você escolher mais facilmente o que
você quer e precisa.
API do CakeRequest
-
class CakeRequest
A classe CakeRequest encapsula o tratamento e introspecção dos parâmetros
das requisições.
-
CakeRequest::domain()
Retorna o nome do domínio onde sua aplicação esta sendo executada.
-
CakeRequest::subdomains()
Retorna os subdomínios de onde sua aplicação está sendo executada em um
formato de array.
-
CakeRequest::host()
Retorna o host em que sua aplicação esta sendo executada.
-
CakeRequest::method()
Retorna o método HTTP em que a requisição foi feita.
-
CakeRequest::referer()
Retorna o endereço que referenciou a requisição.
-
CakeRequest::clientIp()
Retorna o endereço IP do visitante corrente.
Permite você acessar qualquer cabeçalho HTTP_*
que tenha sido usado na
requisição:
$this->request->header('User-Agent');
Retornaria o “user agent” utilizado para a solicitação.
-
CakeRequest::input($callback[, $options])
Resgata os dados de entrada de uma requisição. Opcionalmente o resultado
é passado por uma função de decodificação dos dados. Parâmetros adicionais
para a função de decodificação podem ser passadas como argumentos para
input()
.
-
CakeRequest::data($key)
Fornece acesso aos dados da requisição numa notação pontuada, permitindo a
leitura e modificação dos dados da requisição. Chamadas também podem ser
encadeadas:
// Modifica alguns dados da requisição, assim você pode popular
// previamente alguns campos dos formulários.
$this->request->data('Post.title', 'New post')
->data('Comment.1.author', 'Mark');
// Você também pode ler os dados.
$value = $this->request->data('Post.title');
-
CakeRequest::is($check)
Verifica se uma requisição corresponde a um certo critério. Utiliza
os detectores inclusos por padrão além das regras adicionadas com o
método CakeRequest::addDetector()
.
-
CakeRequest::addDetector($name, $callback)
Adiciona um detector para ser usado com o método is()
. Veja
Inspecionando a Requisição para mais informações.
-
CakeRequest::accepts($type)
Descobre quais os tipos de conteúdo que o cliente aceita ou verifica se
ele aceita um determinado tipo de conteúdo.
Obtém todos os tipos:
<?php
$this->request->accepts();
Verifica apenas um tipo:
$this->request->accepts('application/json');
-
static CakeRequest::acceptLanguage($language)
Obter todas os idiomas aceitos pelo cliente ou verifica se um determinado
idioma é aceito.
Obtém uma lista dos idiomas aceitos:
CakeRequest::acceptLanguage();
Verifica se um idioma específico é aceito:
CakeRequest::acceptLanguage('es-es');
-
property CakeRequest::$data
Um array de dados enviados pelo método POST. Você pode usar o método
CakeRequest::data()
para ler o conteúdo desta propriedade de
uma forma a suprimir avisos quando a chave informada não existir.
-
property CakeRequest::$query
Um array de parâmetros passados por “query strings”.
-
property CakeRequest::$params
Um array contendo os elementos da rota e os parâmetros da requisição.
-
property CakeRequest::$here
Contém a uri solicitada no momento da requisição.
-
property CakeRequest::$base
O caminho de base para a aplicação, geralmente equivale a /
, ao menos
que sua aplicação esteja em um subdiretório.
-
property CakeRequest::$webroot
O diretório web de sua aplicação.
CakeResponse
O CakeResponse
é a classe padrão para respostas no CakePHP. Ela
encapsula inúmeras características e funcionalidades para gerar respostas HTTP
em sua aplicação. Ela também auxilia nos testes da aplicação e pode ser
“forjada”, permitindo inspecionar os cabeçalhos que serão enviados.
Como na classe CakeRequest
, o CakeResponse
consolida
vários métodos encontrados previamente no Controller
,
RequestHandlerComponent
e Dispatcher
. Os métodos
antigos foram depreciados, favorecendo o uso do CakeResponse
.
CakeResponse
fornece uma interface para envolver as tarefas comuns
relacionadas ao envio de respostas para o cliente como:
Enviar cabeçalhos de redirecionamento.
Enviar cabeçalhos com o tipo de conteúdo.
Enviar qualquer outro cabeçalho.
Enviar o corpo da resposta.
Alterando a classe de Resposta
O CakePHP utiliza o CakeResponse
por padrão. O CakeResponse
é uma classe
de uso flexível e transparente, mas se você precisar alterá-la por uma classe
específica da aplicação, você poderá sobrescrevê-la e e substituí-la por sua
própria classe, alterando o CakeResponse usado no arquivo index.php.
Isto fará com que todos os controllers da sua aplicação use CustomResponse
ao invés de CakeResponse
. Você pode também substituir a instancia
utilizada, definindo o novo objeto em $this->response
nos seus controllers.
sobrescrever o objeto de resposta é útil durante os testes, permitindo você
simular os métodos que interagem com o header()
. Veja a seção
CakeResponse e Testes para mais informações.
Enviando Anexos
Poderá existir momentos em que você queira enviar respostas dos controllers como
sendo arquivos para downloads. Você pode conseguir este resultado usando
Media Views ou usando as funcionalidades do CakeResponse
.
O método CakeResponse::download()
permite você enviar respostas
como arquivos para download:
function sendFile($id) {
$this->autoRender = false;
$file = $this->Attachment->getFile($id);
$this->response->type($file['type']);
$this->response->download($file['name']);
$this->response->body($file['content']);
$this->response->send();
}
O exemplo acima demonstra como você pode utilizar o CakeResponse
para
gerar um arquivo para download sem precisar usar a classe
MediaView
. Em geral, você vai preferir utilizar a classe
MediaView
por possuir maiores funcionalidades que o CakeResponse
.
Definindo Cabeçalhos
É possível definir cabeçalhos para a resposta utilizando o método
CakeResponse::header()
. Podendo ser chamada de algumas formas
diferentes:
// Define um único cabeçalho
$this->response->header('Location', 'http://example.com');
// Define múltiplos cabeçalhos
$this->response->header(array('Location' => 'http://example.com', 'X-Extra' => 'My header'));
$this->response->header(array('WWW-Authenticate: Negotiate', 'Content-type: application/pdf'));
Definir o mesmo cabeçalho múltiplas vezes irá causar a sobrescrita do valor
anterior, como numa chamada comum ao método header()
do PHP. Os cabeçalhos
não serão enviados quando o método CakeResponse::header()
for
chamado. Os cabeçalhos são armazenados em buffer até que a resposta seja
efetivamente enviada.
CakeResponse e Testes
Provavelmente uma das grandes vitórias da classe CakeResponse
vem de como
ela torna mais fácil os testes de controllers e componentes. Ao invés de métodos
espalhados em diversos objetos, você precisa de apenas um simples objeto para
“forjar” e utilizar nos controllers e componentes. Isto lhe ajuda a criar seus
testes unitários mais rapidamente:
function testSomething() {
$this->controller->response = $this->getMock('CakeResponse');
$this->controller->response->expects($this->once())->method('header');
...
}
Adicionalmente, você consegue testar sua aplicação pela linha de comando mais
facilmente pois consegue “forjar” os cabeçalhos que quiser sem precisar ficar
tentando definir os cabeçalhos diretos na interface de linha de comandos.
API do CakeResponse
-
class CakeResponse
A classe CakeResponse
fornece vários métodos úteis para interagir com
as respostas que você envia para um cliente.
Permite você definir diretamente um ou muitos cabeçalhos para serem enviados
com a resposta.
-
CakeResponse::charset()
Define o mapa de caracteres (charset) que será usado na resposta.
-
CakeResponse::type($type)
Define o tipo de conteúdo para a resposta. Você pode usar um apelido de
um tipo conhecido de conteúdo ou usar um nome completo para o tipo
do conteúdo.
-
CakeResponse::cache()
Permite você definir os cabeçalhos de cache em sua resposta.
-
CakeResponse::disableCache()
Define os cabeçalhos apropriados para desabilitar o cache da resposta pelo
cliente.
-
CakeResponse::compress()
Habilita a compressão gzip para o envio da resposta.
-
CakeResponse::download()
Permite você enviar a resposta como um anexo e definir o nome do arquivo.
-
CakeResponse::statusCode()
Permite você alterar o código do status da resposta.
-
CakeResponse::body()
Define o conteúdo do corpo da resposta que será enviada.
-
CakeResponse::send()
Após ter criado a resposta, chamar o método send()
irá enviar os todos
cabeçalhos definidos assim como o corpo da resposta. Isto é feito
automaticamente no final de cada requisição pelo Dispatcher
.