Documentação do Symfony2
Renderizada do repositório symfony-docs-pt-BR no Github

Bastidores

Parece que você quer entender como funciona o Symfony2 e como extendê-lo. Isso me deixa muito feliz! Esta seção explica detalhadamente os bastidores do Symfony2.

Note

Você precisa ler esta seção apenas se quer entender como o Symfony2 funciona seu miolo, ou se quer extendê-lo.

Visão Geral

O código do Symfony2 é feito de várias camadas independentes. Cada camada é construída em cima da anterior.

Tip

O Autoloading não é gerenciado diretamente pelo framework; é feito independentemente com a ajuda da classe Symfony\Component\ClassLoader\UniversalClassLoader e o arquivo src/autoload.php. Leia o Capítulo dedicado para mais informações.

Componente HttpFoundation

O nível mais profundo é o componente :namespace:`Symfony\\Component\\HttpFoundation`. HttpFoundation fornece os principais objetos necessários para lidar com HTTP. É um objeto que abstrai algumas funções nativas do PHP e variáveis:

  • A classe Symfony\Component\HttpFoundation\Request abstrai as principais variáveis globais do PHP como: $_GET, $_POST, $_COOKIE, $_FILES, e $_SERVER;
  • A classe Symfony\Component\HttpFoundation\Response abstrai algumas funções do PHP como: header(), setcookie(), e echo;
  • A classe Symfony\Component\HttpFoundation\Session e a interface Symfony\Component\HttpFoundation\SessionStorage\SessionStorageInterface abstraem o gerenciamento da sessão, com uso das funções session_*().

Note

Leia mais sobre o Componente HttpFoundation.

Componente HttpKernel

No topo do HttpFoundation está o componente :namespace:`Symfony\\Component\\HttpKernel`. HttpKernel manuseia a parte dinâmica do HTTP; é um sutíl que envolve as classes Request e Response para padronizar as formas como as requisições são manipuladas. Ele também oferece pontos de extensão e ferramentas ideais para criar um framework Web sem muito trabalho.

Também, opcionalmente, adiciona conigurabilidade e extensibilidade, obrigado ao componente de Injeção de Dependência e um poderoso sistema de plugins (bundles).

See also

Leia mais sobre o Componente HttpKernel, Dependency Injection e Bundles.

O Bundle FrameworkBundle

O bundle :namespace:`Symfony\\Bundle\\FrameworkBundle` é um pacote que amarra os principais componentes e bibliotecas para fazer um leve e rápido framework MVC. Ele vem com uma configuração padrão e convenções para facilitar a curva de aprendizado.

Kernel

A classe Symfony\Component\HttpKernel\HttpKernel é a classe central do Symfony2 e é responsável por tratar os peedidos do cliente. Seu principal objetivo é “converter” um objeto Symfony\Component\HttpFoundation\Request para um objeto Symfony\Component\HttpFoundation\Response.

Cada Kernel do Symfony2 implementa Symfony\Component\HttpKernel\HttpKernelInterface:

function handle(Request $request, $type = self::MASTER_REQUEST, $catch = true)

Controladores

Para converter um Request para um Response, o Kernel se baseia em um “Controlador”. Um Controlador pode ser qualquer código PHP válido.

O Controlador deve ser uma implementação de Symfony\Component\HttpKernel\Controller\ControllerResolverInterface:

public function getController(Request $request);

public function getArguments(Request $request, $controller);

e o Kernel poderá executá-lo.

O método :method:`Symfony\\Component\\HttpKernel\\Controller\\ControllerResolverInterface::getController` retorna o Controlador (um código PHP) associado com o dado Request. A implementação padrão (Symfony\Component\HttpKernel\Controller\ControllerResolver) procura pelo atributo _controller do pedido que representa o nome do controlador (uma string “classs::método”, como Bundle\BlogBundle\PostController:indexAction).

Tip

A implementação padrão utiliza o Symfony\Bundle\FrameworkBundle\EventListener\RouterListener para definir o atributo _controller do Request (veja Evento kernel.request).

O método :method:`Symfony\\Component\\HttpKernel\\Controller\\ControllerResolverInterface::getArguments` retorna um arrau de argumentos para passar para o Controlador. A implementação padrão automaticamente resolve os argumentos dos métodos, baseado nos atributos do Request.

atributos do Request

Para cada argumento, o Symfony2 tenta pegar o valor do atributo do Request com o mesmo nome. Se este não estiver definido, o valor do argumento padrão é usado se definido:

// Symfony2 vai olhar para um atributo 'id' (obrigatório)
// e um 'admin' (opcional)
public function showAction($id, $admin = true)
{
    // ...
}

Trantando os Requests

O método :method:`Symfony\\Component\\HttpKernel\\HttpKernel::handle` pega um Request e sempre retorna um Response. Para converter o Request, o handle() depende do Resolver e uma cadeia ordenada de notificações de eventos (veja a próxima seção para mais informações sobre cada Event):

  1. Antes de qualquer coisa, o evento kernel.request é notificado – se um dos listeners retorna um Response, pula diretamente para o passo 8;
  2. O Resolver é chamado para determinar qual Controlador executar;
  3. Os listeners do evento kernel.controller podem manipular o Controlador chamado como queiram (alterá-lo, envolvê-lo, ...);
  4. O Kernel verifica se o Controlador é um código PHP válido;
  5. O Resolver é chamado para determinar os argumentos para passar para o Controlador;
  6. O Kernel chama o Controlador;
  7. Se o Controlador não retorna um Response, os listeners do evento kernel.view podem converter o valor de retorno do Controlador para um Response;
  8. Os listeners do evento kernel.response podem manipular o Response (conteúdo e cabeçalho);
  9. O Response é retornado.

Se uma Exception é lançada durante o processamento, o kernel.exception é notificado e os listeners têm a oportundade de converter a Exception em um Response. Se isso funcionar, o evento kernel.reponse é notificado; se não, a Exception é relançada.

Se você não quer ser pego por uma Exception (para pedidos embutido por exemplo), desabilite o evento kernel.exception pasando false como o terceiro argumento do método handle().

Requests Internos

A qualquer momento durante o tratamento de um pedido (o ‘master’), um sub-pedido pode ser manipulado. Você pode passar o tipo do pedido para o método handle() (segundo argumento):

  • HttpKernelInterface::MASTER_REQUEST;
  • HttpKernelInterface::SUB_REQUEST.

O tipo é passado para todos os eventos e os listeners podem agir de acordo (alguns processamentos só devem ocorrer no pedido principal).

Eventos

Cada evento acionado pelo Kernel é uma subclasse do Symfony\Component\HttpKernel\Event\KernelEvent. Isto significa que cada evento tem acesso para a mesma informação básica:

getRequestType()

O método getRequestType() permite os listeners para a saber o tipo do pedido. Por exemple, se um listener só deve estar ativo para um pedidos principais, adicione o seguinte código no início do seu método listener:

use Symfony\Component\HttpKernel\HttpKernelInterface;

if (HttpKernelInterface::MASTER_REQUEST !== $event->getRequestType()) {
    // return immediately
    return;
}

Tip

Se você ainda não está familiarizado com o Dispatcher de Evento do Symfony2, leia primeiro seção Documentação do Compoenente Dispatcher de Evento .

Evento kernel.request

Classe do Evento: Symfony\Component\HttpKernel\Event\GetResponseEvent

O objetivo deste evento é retornar um objeto Response ou variáveis de configuração de um Controlador podem ser chamadas depois do evento. Qualquer listener pode returnar um objeto Reponse através do métod setResponse() no evento. Neste caso, todos os outros listeners não serão chamados.

Este evento é usado pelo FrameworkBundle para popular o _controller do atributo do Request, através do Symfony\Bundle\FrameworkBundle\EventListener\RouterListener. RequestListener usa um objeto Symfony\Component\Routing\RouterInterface para combinar o Request e determinar o nome do Controlador (armazenado no atributo _controller do Request).

See also

Leia mais em evento kernel.request.

Evento kernel.controller

Classe do Evento: Symfony\Component\HttpKernel\Event\FilterControllerEvent

Este evento não é usado pelo FrameworkBundle, mas pode ser ponto de entrada usado para modificar o controlador que será executado:

use Symfony\Component\HttpKernel\Event\FilterControllerEvent;

public function onKernelController(FilterControllerEvent $event)
{
    $controller = $event->getController();
    // ...

    // o controlador pode ser trocado por qualquer código PHP válido
    $event->setController($controller);
}

See also

Leio mais em evento kernel.controller.

Evento kernel.view

Classe do Evento: Symfony\Component\HttpKernel\Event\GetResponseForControllerResultEvent

Este evento não é usado pelo FrameworkBundle, mas pode ser usado para implementar um sub-sistema de view. Este evento é chamado apenas se o Controlador não retornar um objeto Response. A proposta deste evento é permitir que qualquer outro valor possa ser convertido em um Response.

O valor retornado pelo Controlador é acessível através do método getControllerResult:

use Symfony\Component\HttpKernel\Event\GetResponseForControllerResultEvent;
use Symfony\Component\HttpFoundation\Response;

public function onKernelView(GetResponseForControllerResultEvent $event)
{
    $val = $event->getControllerResult();
    $response = new Response();

    // ... uma maneria de customizar o Response a partir de um valor de retorno

    $event->setResponse($response);
}

See also

Leio mais no evento kernel.view.

Evento kernel.response

Classe do Evento: Symfony\Component\HttpKernel\Event\FilterResponseEvent

A proposta deste evento é permitir outros sistemas de modificar ou substituir o objeto Response depois de criado:

public function onKernelResponse(FilterResponseEvent $event)
{
    $response = $event->getResponse();

    // ... modifique o objeto response
}

O``FrameworkBundle`` registra vários listeners:

  • Symfony\Component\HttpKernel\EventListener\ProfilerListener: coleta dados para o pedido atual;
  • Symfony\Bundle\WebProfilerBundle\EventListener\WebDebugToolbarListener: injeta a Web Debug Toolbar;
  • Symfony\Component\HttpKernel\EventListener\ResponseListener: fixes the Responde Content-Type baseado no formato do pedido;
  • Symfony\Component\HttpKernel\EventListener\EsiListener: adds a Cabeçalho HTTP Surrogate-Control quando o Response precisa ser transformado para tags ESI.

See also

Leia mais no evento kernel.response.

Evento kernel.exception

Classe de Evento: Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent

FrameworkBundle registra um Symfony\Component\HttpKernel\EventListener\ExceptionListener que encaminha o Request para um dado Controlador (o valor do parâmetro exception_listener.controller – deve ser uma notação class::method).

Um listener deste evento pode criar e definir um objeto Response, criar e definir um novo objeto Exception, ou fazer nada:

use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
use Symfony\Component\HttpFoundation\Response;

public function onKernelException(GetResponseForExceptionEvent $event)
{
    $exception = $event->getException();
    $response = new Response();
    // configura o objeto Response baseado na exception capturada
    $event->setResponse($response);

    // você também pode definir uma nova Exception
    // $exception = new \Exception('Some special exception');
    // $event->setException($exception);
}

O Dispatcher de Evento

O dispatcher de evento é um componente autônomo que é responsável por grande parte da lógica subjacente e do fluxo por trás de um pedido Symfony. Para mais informações, veja a

Documentação do Componente Dispatcher de Evento.

See also

Leia mais no evento kernel.exception.

Profiler

Quando ativado, o profiler do Symfony2 coleta informações úteis sobre cada pedido feito à sua aplicação e armazenadas para uma análise posterior. Utilize o profiler no ambiente de desenvolvimento para ajudar a depurar seu código e melhorar o desempenho; utilize-o em produção para problemas quando acontecerem.

Você raramente precisa lidar com o profiler diretamente, como o Symfony2 oferece ferramentas como Web Debug Toolbar e o Web Profiler. Se você utilizar o Symfony2 Standard Edition, o profiler, o web debug toolbar, e o web profiler estão configurados com configurações razoáveis.

Note

O profiler coleta informações sobre todo os pedidos (pedidos simples, redirecionamentos, exeçõec, pedidos Ajax, pedidos ESI; e para todos os métodos HTTP e todos formatos). Isso significa que para uma única URL, você pode ter vários dados de perfis associados (por pedido externo/resposta)

Visualizando os dados do Profiler

Usando a Web Debug Toolbar

No ambiente de desenvolvimento, a web debug toolbar está dispinível na parte de inferior de todas as páginas. Ela mostra um bom resumo do dados coletados e dá acesso instantâneo a uma grande quantidade de informações úteis quando algo não funciona como o esperado.

Se o resumo oferecido pela Web Debug Toolbar não é suficiente, clique no link do token (uma string feita de 13 caractéres randômicos) para acessar o Web Profiler.

Note

Se o token não está clicável, isso significa que a rota do profiler não está registrada (veja abaixo para obter informações de configuração)

Analisando os dados com o Web Profiler

O Web Profiler é uma ferramenta de visualização de dados que você pode usar no desenvolvimento para depurar seu código e melhor o desempenho; mas pode também ser usado para explorar problemas que ocorrem em produção. Ele expõe toda informação coletada pelo profiler na interface web.

Acessando a informação coletada

Você não precisa usar o visualizador padrão para acessar as informações coletadas. Mas como você pode recuperar informações para um pedido específico? Quando o profiler armazena os dados de um Request, também associa um token para ele; este token está disponível no cabeçalho HTTP X-Debug-Token do Response:

$profile = $container->get('profiler')->loadProfileFromResponse($response);

$profile = $container->get('profiler')->loadProfile($token);

Tip

Quando o profiler está ativado man não a web debug toolbar, ou quando você precisa pegar o token para um pedido Aja, utilize uma ferramenta como o Firebug para pegar o valor do cabeçalho HTTP X-Debug-Token.

Utilize o método :method:`Symfony\\Component\\HttpKernel\\Profiler\\Profiler::find` para acessar os tokens baseados em alguns critérios:

// pega os 10 últimos tokens
$tokens = $container->get('profiler')->find('', '', 10);

// pegue os 10 últimos tokens para todas URLs que contenham /admin/
$tokens = $container->get('profiler')->find('', '/admin/', 10);

// pegue os 10 últimos tokens para pedidos locais
$tokens = $container->get('profiler')->find('127.0.0.1', '', 10);

Se você precisa manipular os dados coletados em uma máquina diferente da em que os dados foram gerados, utilize os métodos :method:`Symfony\\Component\\HttpKernel\\Profiler\\Profiler::export` e :method:`Symfony\\Component\\HttpKernel\\Profiler\\Profiler::import`:

// na máquina de produção
$profile = $container->get('profiler')->loadProfile($token);
$data = $profiler->export($profile);

// na máquina de desenvolvimento
$profiler->import($data);

Configuração

A configuração padrão do Symfony2 vem com definições razoáveis para o profiler, a web debug toolbar, e o web profiler. Aqui está um exemplo de configuração para o ambiente de desenvolvimento:

Quando only-execptions está definida como true, o profiler apenas coleta dados quando uma exception é lançada pela aplicação.

Quando intercept-redirects é definido como true, o web profiler intercepta os redirecionamentos e dá a você a oportunidade de ver os dados coletados antes de seguir o redirecionamento.

Quando verbose é definido como true, o Web Debug Toolbar exibe muita informação. Definindo verbose para false esconde informações secundárias para deixar a barra menor.

Se você ativa o web profiler, você também precisa montar as rotas do profiler:

Como o profiler adiciona alguma sobrecarga, você pode querer ativar apenas em algumas circunstâncias no ambiente de desenvolvimento. O parâmetro only-exceptions limita para 500 páginas, mas se quiser obter informações quando um IP do cliente vier de um endereço específico, ou de uma parte limitada do site? Você pode usar um combinador de pedido: