.. index::
single: Symfony2 Fundamentals
Fundamentos de Symfony e HTTP
=============================
Parabéns! Aprendendo sobre o Symfony2, você está no caminho certo para ser um
desenvolvedor web mais *produtivo*, *bem preparado* e *popular* (na verdade,
este último é por sua própria conta). O Symfony2 foi criado para voltar ao básico:
desenvolver ferramentas para ajuda-lo a criar aplicações mais robustas de
uma maneira mais rápida sem ficar no seu caminho. Ele foi construído baseando-se
nas melhores ideias de diversas tecnologias: as ferramentas e conceitos que você
está prestes a aprender representam o esforço de milhares de pessoas, realizado
durante muitos anos. Em outras palavras, você não está apenas aprendendo o "Symfony",
você está aprendendo os fundamentos da web, boas práticas de desenvolvimento e
como usar diversas biblotecas PHP impressionantes, dentro e fora do Symfony2. Então,
prepare-se.
Seguindo a filosofia do Symfony2, este capítulo começa explicando o conceito fundamental
para o desenvolvimento web: o HTTP. Independente do seu conhecimento anterior ou
linguagem de programação preferida, esse capítulo é uma **leitura obrigatória**
para todos.
HTTP é simples
--------------
HTTP (Hypertext Transfer Protocol, para os geeks) é uma linguagem textual que
permite que duas máquinas se comuniquem entre si. É só isso! Por exemplo, quando
você vai ler a última tirinha do `xkcd`_, acontece mais ou menos a seguinte conversa:
.. image:: /images/http-xkcd.png
:align: center
Apesar da linguagem real ser um pouco mais formal, ainda assim ela é bastante simples.
HTTP é o termo usado para descrever essa linguagem simples baseada em texto. Não
importa como você desenvolva para a web, o objetivo do seu servidor *sempre* será
entender simples requisições de texto e enviar simples respostas de texto.
O Symfony2 foi criado fundamentado nessa realidade. Você pode até não perceber,
mas o HTTP é algo que você utilizada todos os dias. Com o Symfony2 você irá
aprender a domina-lo.
.. index::
single: HTTP; Request-response paradigm
Primeiro Passo: O Cliente envia uma Requisição
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Toda comunicação na web começa com uma *requisição*. Ela é uma mensagem de texto
criada por um cliente (por exemplo, um navegador, um app para iPhone etc) em um
formato especial conhecido como HTTP. O cliente envia essa requisição para um
servidor e, então, espera pela resposta.
Veja a primeira parte da interação (a requisição) entre um navegador e o servidor
web do xkcd:
.. image:: /images/http-xkcd-request.png
:align: center
No linguajar do HTTP, essa requisição se parece com isso:
.. code-block:: text
GET / HTTP/1.1
Host: xkcd.com
Accept: text/html
User-Agent: Mozilla/5.0 (Macintosh)
Essa simples mensagem comunica *tudo* o que é necessário sobre o recurso exato
que o cliente está requisitando. A primeira linha de uma requisição HTTP é a mais
importante e contém duas coisas: a URI e o método HTTP.
A URI (por exemplo, ``/``, ``/contact`` etc) é um endereço único ou localização que
identifica o recurso que o cliente quer. O método HTTP (por exemplo, ``GET``)
define o que você quer *fazer* com o recurso. Os métodos HTTP são os *verbos* da
requisição e definem algumas maneiras comuns de agir em relação ao recurso:
+----------+---------------------------------------+
| *GET* | Recupera o recurso do servidor |
+----------+---------------------------------------+
| *POST* | Cria um recurso no servidor |
+----------+---------------------------------------+
| *PUT* | Atualiza um recurso no servidor |
+----------+---------------------------------------+
| *DELETE* | Exclui um recurso do servidor |
+----------+---------------------------------------+
Tendo isso em mente, você pode imaginar como seria uma requisição HTTP para excluir
uma postagem específica de um blog, por exemplo:
.. code-block:: text
DELETE /blog/15 HTTP/1.1
.. note::
Existem na verdade nove métodos definidos pela especificação HTTP, mas
a maioria deles não são muito utilizados ou suportados. Na realidade, muitos dos
navegadores modernos não suportam os métodos ``PUT`` e ``DELETE``.
Além da primeira linha, uma requisição HTTP invariavelmente contém outras linhas
de informação chamadas de cabeçalhos da requisição. Os cabeçalhos podem fornecer
uma vasta quantidade de informações, tais como o ``Host`` que foi requisitado, os
formatos de resposta que o cliente aceita (``Accept``) e a aplicação que o
cliente está utilizando para enviar a requisição (``User-Agent``). Muitos outros
cabeçalhos existem e podem ser encontrados na Wikipedia, no artigo
`List of HTTP header fields`_
Segundo Passo: O Servidor envia uma resposta
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Uma vez que o servidor recebeu uma requisição, ele sabe exatamente qual recurso
o cliente precisa (através do URI) e o que o cliente quer fazer com ele (através
do método). Por exemplo, no caso de uma requisição GET, o servidor prepara o
o recurso e o retorna em uma resposta HTTP. Considere a resposta do servidor web
do xkcd:
.. image:: /images/http-xkcd.png
:align: center
Traduzindo para HTTP, a resposta enviada para o navegador será algo como:
.. code-block:: text
HTTP/1.1 200 OK
Date: Sat, 02 Apr 2011 21:05:05 GMT
Server: lighttpd/1.4.19
Content-Type: text/html
A resposta HTTP contém o recurso requisitado (nesse caso, o conteúdo HTML), bem
como outras informações. A primeira linha é especialmente importante e contém o
código de status da resposta HTTP (nesse caso, 200). Esse código de status é uma
representação geral da resposta enviada à requisição do cliente. A requisição
foi bem sucedida? Ocorreu algum erro? Existem diferentes códigos de status para
indentificar sucesso, um erro, ou que o cliente precisa fazer alguma coisa (por
exemplo, redirecionar para outra página). Uma lista completa pode ser encontrada
na Wikipedia, no artigo `List of HTTP status codes`_.
Assim como uma requisição, uma resposta HTTP também contém informações adicionais
conhecidas como cabeçalhos HTTP. Por exemplo, um cabeçalho importante nas respostas
HTTP é o ``Content-Type``. O conteúdo de um mesmo recurso pode ser retornado em
vários formatos diferentes, incluindo HTML, XML ou JSON, só para citar alguns.
O cabeçalho ``Content-Type`` diz ao cliente qual é o formato que está sendo
retornado.
Existem diversos outros cabeçalhos, alguns deles bastante poderosos. Certos
cabeçalhos, por exemplo, podem ser utilizados para criar um poderoso sistema de
cache.
Requisições, Respostas e o Desenvolvimento Web
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Essa conversação de requisição-resposta é o processo fundamental que dirige toda a
comunicação na web. Apesar de tão importante e poderoso esse processo, ainda assim,
é inevitavelmente simples.
O fato mais importante é: independente da linguagem que você utiliza, o tipo de
aplicação que você desenvolva (web, mobile, API em JSON) ou a filosofia de
desenvolvimento que você segue, o objetivo final da aplicação **sempre** será
entender cada requisição e criar e enviar uma resposta apropriada.
O Symfony foi arquitetado para atender essa realidade.
.. tip::
Para aprender mais sobre a especificação HTTP, leia o original `HTTP 1.1 RFC`_
ou `HTTP Bis`_, que trata-se de um esforço para facilitar o entendimento da
especificação original. Para verificar as requisições e respostas enviadas
enquanto navega em um site, você pode utilizar a extensão do Firefox chamada
`Live HTTP Headers`_.
.. index::
single: Symfony2 Fundamentals; Requests and responses
Requisições e Respostas no PHP
------------------------------
Como interagir com a "requisição" e criar uma "resposta" utilizando o PHP? Na
verdade, o PHP abstrai um pouco desse processo:
.. code-block:: php
getPathInfo();
// retrieve GET and POST variables respectively
$request->query->get('foo');
$request->request->get('bar');
// retrieves an instance of UploadedFile identified by foo
$request->files->get('foo');
$request->getMethod(); // GET, POST, PUT, DELETE, HEAD
$request->getLanguages(); // an array of languages the client accepts
Como um bônus, a classe ``Request`` faz um monte de trabalho com o qual você
nunca precisará se preocupar. Por exemplo, o método ``isSecure()`` verifica os
três valores diferentes que o PHP utiliza para indicar ser o usuário está
utilizando uma conexão segura (``https``, por exemplo).
O Symfony também fornece a classe ``Response``: uma simples representação em PHP de
uma resposta HTTP. Assim é possível que sua aplicação utilize uma interface
orientada a objetos para construir a resposta que precisa ser enviada ao cliente::
use Symfony\Component\HttpFoundation\Response;
$response = new Response();
$response->setContent('
Hello world!
');
$response->setStatusCode(200);
$response->headers->set('Content-Type', 'text/html');
// prints the HTTP headers followed by the content
$response->send();
Com tudo isso, mesmo que o Symfony não oferecesse mais nada, você já teria um kit de
ferramentas para facilmente acessar informações sobre a requisição e uma interface
orientada a objetos para criar a resposta. Mesmo depois de aprender muitos dos
poderosos recursos do Symfony, tenha em mente que o objetivo da sua aplicação
sempre será *interpretar uma requisição e criar a resposta apropriada baseada na
lógica da sua aplicação*.
.. tip::
As classes ``Request`` e ``Response`` fazem parte de um componente do Symfony
chamado ``HttpFoundation``. Esse componente pode ser utilizado de forma
independente ao framework e também possui classes para tratar sessões e
upload de arquivos.
A Jornada da Requisição até a Resposta
--------------------------------------
Como o próprio HTTP, os objetos ``Request`` e ``Response`` são bastante simples.
A parte difícil de se construir uma aplicação é escrever o que acontece entre eles.
Em outras palavras, o trabalho de verdade é escrever o código que interpreta a
a requisição e cria a resposta.
A sua aplicação provavelmente faz muitas coisas como enviar emails, tratar do
envio de formulários, salvar coisas no banco de dados, renderizar páginas HTML e
proteger o conteúdo com segurança. Como cuidar de tudo isso e ainda ter um código
organizado e de fácil manutenção?
O Symfony foi criado para que ele resolva esses problemas, não você.
O Front Controller
~~~~~~~~~~~~~~~~~~~~
Tradicionalmente, aplicações são construídas para que cada página do site seja
um arquivo físico:
.. code-block:: text
index.php
contact.php
blog.php
Existem diversos problemas para essa abordagem, incluindo a falta de flexibilidade
das URLs (e se você quiser mudar o arquivo ``blog.php`` para ``news.php`` sem
quebrar todos os seus links?) e o fato de que cada arquivo *deve* ser alterado
manualmente para incluir um certo conjunto de arquivos essenciais de forma que a
segurança, conexões com banco de dados e a "aparência" do site continue consistente.
Uma solução muito melhor é utilizar um :term:`front controller`: um único arquivo
PHP que trata todas as requisições enviadas para a sua aplicação. Por exemplo:
+------------------------+------------------------+
| ``/index.php`` | executa ``index.php`` |
+------------------------+------------------------+
| ``/index.php/contact`` | executa ``index.php`` |
+------------------------+------------------------+
| ``/index.php/blog`` | executa ``index.php`` |
+------------------------+------------------------+
.. tip::
Utilizando o ``mod_rewrite`` do Apache (ou o equivalente em outros servidores
web), as URLs podem ser simplificadas facilmente para ser somente ``/``, ``/contact``
e ``/blog``.
Agora, cada requisição é tratada exatamente do mesmo jeito. Em vez de arquivos
PHP individuais para executar cada URL, o front controller *sempre* será executado,
e o roteamento de cada URL para diferentes partes da sua aplicação é feito internamente.
Assim resolve-se os dois problemas da abordagem original. Quase todas as aplicações
modernas fazem isso - incluindo apps como o Wordpress.
Mantenha-se Organizado
~~~~~~~~~~~~~~~~~~~~~~
Dentro do front controller, como você sabe qual página deve ser renderizada e como
renderiza-las de uma maneira sensata? De um jeito ou de outro, você precisará
verificar a URI requisitada e executar partes diferentes do seu código dependendo
do seu valor. Isso pode acabar ficando feio bem rápido:
.. code-block:: php
// index.php
$request = Request::createFromGlobals();
$path = $request->getPathInfo(); // the URL being requested
if (in_array($path, array('', '/')) {
$response = new Response('Welcome to the homepage.');
} elseif ($path == '/contact') {
$response = new Response('Contact us');
} else {
$response = new Response('Page not found.', 404);
}
$response->send();
Resolver esse problema pode ser difícil. Felizmente é *exatamente* o que o Symfony
foi projetado para fazer.
O Fluxo de uma Aplicação Symfony
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Quando você deixa que o Symfony cuide de cada requisição, sua vida fica muito mais
fácil. O framework segue um simples padrão para toda requisição:
.. _request-flow-figure:
.. figure:: /images/request-flow.png
:align: center
:alt: Symfony2 request flow
As requisições recebidas são interpretadas pelo roteamento e passadas para as
funções controller que retornam objetos do tipo ``Response``.
Cada "página" do seu site é definida no arquivo de configuração de roteamento que
mapeia diferentes URLs para diferentes funções PHP. O trabalho de cada função,
chamadas de :term:`controller`, é usar a informação da requisição - junto com
diversas outras ferramentas disponíveis no Symfony - para criar e retornar um
objeto ``Response``. Em outras palavras, o *seu* código deve estar nas funções controller:
lá é onde você interpreta a requisição e cria uma resposta.
É fácil! Vamos fazer uma revisão:
* Cada requisição executa um arquivo front controller;
* O sistema de roteamento determina qual função PHP deve ser executada, baseado
na informação da requisição e na configuração de roteamento que você criou;
* A função PHP correta é executada, onde o seu código cria e retorna o objeto
``Response`` apropriado.
Uma Requisição Symfony em Ação
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Sem entrar em muitos detalhes, vamos ver esse processo em ação. Suponha que
você quer adicionar a página ``/contact`` na sua aplicação Symfony. Primeiro,
adicione uma entrada para ``/contact`` no seu arquivo de configuração de roteamento:
.. code-block:: yaml
contact:
pattern: /contact
defaults: { _controller: AcmeDemoBundle:Main:contact }
.. note::
Esse exemplo utiliza :doc:`YAML` para definir a configuração de
roteamento. Essa configuração também pode ser escrita em outros formatos, tais
como XML ou PHP.
Quando alguém visitar a página ``/contact``, essa rota será encontrada e o
controller específico será executado. Como você irá aprender no :doc:`capítulo sobre roteamento`,
a string ``AcmeDemoBundle:Main:contact`` é uma sintaxe encurtada para apontar para
o método ``contactAction`` dentro de uma classe chamada ``MainController``:
.. code-block:: php
class MainController
{
public function contactAction()
{
return new Response('Contact us!
');
}
}
Nesse exemplo extremamente simples, o controller simplesmente cria um objeto
``Response`` com o HTML "Contact us!
". No :doc:`capítulo sobre controller`,
você irá aprender como um controller pode renderizar templates, fazendo com que o seu código de
"apresentação" (por exemplo, qualquer coisa que gere HTML) fique em um arquivo de
template separado. Assim deixamos o controller livre para se preocupar apenas com
a parte complicada: interagir com o banco de dados, tratar os dados enviados ou
enviar emails.
Symfony2: Construa sua aplicação, não suas Ferramentas
------------------------------------------------------
Agora você sabe que o objetivo de qualquer aplicação é interpretar cada requisição
recebida e criar uma resposta apropriada. Conforme uma aplicação cresce, torna-se
mais difícil de manter o seu código organizado e de fácil manutenção. Invariavelmente,
as mesmas tarefas complexas continuam a aparecer: persistir dados no banco,
renderizar e reutilizar templates, tratar envios de formulários, enviar emails,
validar entradas dos usuários e cuidar da segurança.
A boa notícia é que nenhum desses problemas é único. O Symfony é um framework cheio
de ferramentas para você construir a sua aplicação e não as suas ferramentas.
Com o Symfony2, nada é imposto: você é livre para utilizar o framework completo ou
apenas uma parte dele.
.. index::
single: Symfony2 Components
Ferramentas Independentes: Os *Componentes* do Symfony2
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Então, o que *é* o Symfony2? Primeiramente, trata-se de uma coleção de vinte
bibliotecas independentes que podem ser utilizadas dentro de *qualquer* projeto
PHP. Essas bibliotecas, chamadas de *Components do Symfony2*, contém coisas úteis
para praticamente qualquer situação, independente de como o seu projeto é desenvolvido.
Alguns desses componentes são:
* `HttpFoundation`_ - Contém as classes ``Request`` e ``Response``, bem como outras
classes para tratar de sessões e upload de arquivos;
* `Routing`_ - Um poderoso e rápido sistema de roteamento que permite mapear uma
URI específica (por exemplo, ``/contact``) para uma informação sobre como a
requisição deve ser tratada (por exemplo, executar o método ``contactAction()``);
* `Form`_ - Um framework completo e flexível para criar formulários e tratar os
dados enviados por eles;
* `Validator`_ Um sistema para criar regras sobre dados e validar se os dados
enviados pelos usuários seguem ou não essas regras;
* `ClassLoader`_ Uma biblioteca de autoloading que faz com que classes PHP possam
ser utilizadas sem precisar adicionar manualmente um ``require`` para cada arquivo
que as contém;
* `Templating`_ Um conjunto de ferramentas para renderizar templates, tratar da
herança de templates (por exemplo, um template decorado com um layout) e executar
outras tarefas comuns relacionadas a templates;
* `Security`_ - Uma biblioteca poderosa para tratar qualquer tipo de segurança
dentro de sua aplicação;
* `Translation`_ Um framework para traduzir strings na sua aplicação.
Cada um desses componentes funcionam de forma independente e podem ser utilizados
em *qualquer* projeto PHP, não importa se você utiliza o Symfony2 ou não. Cada
parte foi feita para ser utilizada e substituída quando for necessário.
A solução completa: O *framework* Symfony2
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Então, o que *é* o *framework* Symfony2? Ele é uma biblioteca PHP que realiza
duas tarefas distintas:
#. Fornecer uma seleção de componentes (os componentes do Symfony2, por exemplo) e
bibliotecas de terceiros (por exemplo, a ``Swiftmailer``, utilizada para enviar emails);
#. Fornecer as configurações necessárias e uma "cola" para manter todas as peças
juntas.
O objetivo do framework é integrar várias ferramentas independentes para criar
uma experiência consistente para o desenvolvedor. Até próprio próprio framework é
um pacote Symfony2 (um plugin, por exemplo) que pode ser configurado ou completamente
substituído.
O Symfony2 fornece um poderoso conjunto de ferramentas para desenvolver aplicações
web rapidamente sem impor nada. Usuários normais podem iniciar o desenvolvimento rapidamente
utilizando uma distribuição do Symfony2, que contém o esqueleto de um projeto com
as princpais itens padrão. Para os usuários mais avançados, o céu é o limite.
.. _`xkcd`: http://xkcd.com/
.. _`HTTP 1.1 RFC`: http://www.w3.org/Protocols/rfc2616/rfc2616.html
.. _`HTTP Bis`: http://datatracker.ietf.org/wg/httpbis/
.. _`Live HTTP Headers`: https://addons.mozilla.org/en-US/firefox/addon/3829/
.. _`List of HTTP status codes`: http://en.wikipedia.org/wiki/List_of_HTTP_status_codes
.. _`List of HTTP header fields`: http://en.wikipedia.org/wiki/List_of_HTTP_header_fields
.. _`HttpFoundation`: https://github.com/symfony/HttpFoundation
.. _`Routing`: https://github.com/symfony/Routing
.. _`Form`: https://github.com/symfony/Form
.. _`Validator`: https://github.com/symfony/Validator
.. _`ClassLoader`: https://github.com/symfony/ClassLoader
.. _`Templating`: https://github.com/symfony/Templating
.. _`Security`: https://github.com/symfony/Security
.. _`Translation`: https://github.com/symfony/Translation