Capitulo 2 - Explorando o Código Symfony
À primeira vista, o código-fonte por detrás de uma aplicação gerenciada pelo symfony pode parecer assustador. Ele consiste de muitos diretórios e scripts, e os arquivos são uma mistura de classes PHP, HTML, ou mesmo uma mistura dos dois. Você tambem verá referencias para classes que não serão encontradas em lugar algum dentro da pasta da aplicação, e que a profundidade dos diretórios pode se estender até 6 níveis. Mas uma vez que você compreender a razão por detrás de toda esta complexidade, tudo parecerá tão natural para você que você não trocaria o symfony por qualquer outras estruturas de aplicação. Este capítulo tenta diminuir esta sensação intimidante.
O Padrão MVC
symfony é baseado no clássico padrão de design web conhecido como Arquitetura MVC (MVC Architecture), que consiste de três niveis:
- A modelagem representa as informações com que a aplicação opera -- sua lógica de negócio.
- A visualização renderiza a modelagem em uma página de internet pronta para interação com o usuário.
- O controlador responde às ações do usuario e invoca mudanças na modelagem ou visualização conforme necessário.
A figura 2-1 ilustra o padrão MVC.
A arquitetura MVC separa a lógica do negócio (modelagem) e a apresentação (visualização) resultando em grande manutencibilidade. Por exemplo, se sua aplicação deve rodar tanto em web browsers como em dispositivos móveis, você apenas precisa de uma nova visualização; você pode manter o controlador e modelagem original. O controlador ajuda a esconder os detalhes do protocolo utilizado para a requisição (HTTP, console de comandos, e-mail, entre outros) da modelagem e da visualização. A modelagem abstrai a lógica de dados, o que faz com que a visualização e a ação independente de, por exemplo, do tipo de banco de dados utilizado pela aplicação.
As camadas do MVC
Para ajudar você a compreender as vantagens do MVC, vamos ver como se converte uma aplicação básica em PHP para uma aplicação que se utilize da arquitetura MVC. Uma lista mensagens para um aplicação de weblog será um exemplo perfeito.
Programação Simples
Em um simples arquivo PHP, exibir uma lista de entradas de uma base de dados pode parecer com o script apresentado na lista 2-1.
Lista 2-1 - Um script simples
<?php // Conectando e selecionando o bando de dados $ligacao = mysql_connect('localhost', 'meu_usuario', 'minhasenha'); mysql_select_db('blog', $ligacao); // Realizando uma consulta SQL $resultado = mysql_query('SELECT data, titulo FROM recados', $ligacao); ?> <html> <head> <title>Lista de Recados</title> </head> <body> <h1>Lista de Recados</h1> <table> <tr><th>Data</th><th>Título</th></tr> <?php // Imprimindo os resultados em HTML while ($linha = mysql_fetch_array($resultado, MYSQL_ASSOC)) { echo " <tr> "; printf(" <td> %s </td> ", $linha['data']); printf(" <td> %s </td> ", $linha['titulo']); echo " </tr> "; } ?> </table> </body> </html> <?php // Fechando a conexão mysql_close($ligacao); ?>
Isto é rápido para escrever, rápido para executar e difícil de manter e atualizar. Os maiores problemas com este código são:
- Não há verificação de erros (o que acontece se a base de dados falha?)
- HTML e PHP estão misturados, inclusive entrelaçados entre si.
- O código está amarrado à uma base de de dados mySQL.
Isolando a apresentação
As funções echo e printf na lista 2-1 tornam o código difícil de ser lido. Modificar o código HTML para melhorar a apresentação é um problema com a atual sintaxe. Portanto o código pode ser dividido em duas partes. Primeiro, o código PHP puro, com todas as lógicas de negócio, vai em um script controlador, como exibido na lista 2-2.
Lista 2-2 - A parte Controladora, em index.php
<?php // Conectadno e selecionado o banco de dados $ligacao = mysql_connect('localhost', 'meu_usuario', 'minhasenha'); mysql_select_db('blog', $ligacao); // Realizando uma consulta SQL $resultado = mysql_query('SELECT data, titulo FROM recados', $ligacao); // Preenchendo um vetor para a apresentação $recados = array(); while ($linha = mysql_fetch_array($resultado, MYSQL_ASSOC)) { $recados[] = $linha; } // Fechando a conexão mysql_close($ligacao); // Requisitando a apresentação require('apresentacao.php'); ?>
O código HTML, contendo uma modelagem com sintaxes PHP, é armazenado no script de visualização, como exibido na lista 2-3;
Lista 2-3 - A parte de visualização, em apresentacao.php
Uma boa maneira de determinar se uma visualização esta limpa o suficiente é se esta contem apenas o mínimo de código PHP, de modo que possa ser compreendida por um designer HTML com o mínimo de conhecimento em PHP. Os comandos mais comuns em visualizações são echo, if/endifm, foreach/endforeach e só! Além disso, não deve haver nenhum código PHP invocando tags HTML.
Toda a lógica é movida para o script controlador, que contem apenas código PHP, sem nenhum HTML. De fato, você deveria imaginar que um mesmo controlador poderia ser reutilizado para uma apresentação completamente diferente, como em um arquivo PDF ou uma estrutura XML.
Isolando a Manipulação de Dados
Muitos dos scripts de controle são dedicados à manipulação de dados. Mas e se você precisar da lista de mensagens para outro controlador, um que alimente um RSS feed com as mensagens do weblog por exemplo? E se você quiser manter todos os comandos de acesso da base de dados em um lugar, e evitar duplicação de código? E se você decidir mudar a modelagem dos dados de modo a mudar o nome da tabela post para weblog_post? E se você quiser mudar para uma base de dados PostgreSQL ao invés do MySQL? Para tornar isto possível, você precisa remover todos os códigos que manipulam dados do controlador e pô-los em outro script, chamado de modelo, como ilustrado na lista 2-4.
Lista 2-4 - A parte de modelagem, em model.php
<?php function retornaTodosRecados() { // Conectando e selecionando o banco de dados $ligacao = mysql_connect('localhost', 'meu_usuario', 'minhasenha'); mysql_select_db('blog', $ligacao); // Realizando uma consulta SQL $resultado = mysql_query('SELECT data, titulo FROM recados', $ligacao); // Preenchendo um vetor $recados = array(); while ($linha = mysql_fetch_array($resultado, MYSQL_ASSOC)) { $recados[] = $linha; } // Closing connection mysql_close($ligacao); return $recados; } ?>
A lista 2-5 ilustra o controlador revisado.
Lista 2-5 - A parte de controle, revisada, em index.php
<?php // Requisitando o modelo require_once('modelo.php'); // Recuperando a lista de recados $recados = retornaTodosRecados(); // Requisitando a apresentação require('apresentacao.php'); ?>
O controlador se torna fácil para ler. Sua única tarefa é pegar os dados da modelagem e passá-los para o visualizador. Em aplicações mais complexas, o controlador também trata as requisições, as seções de usuário, as autenticações, entre outros. O uso de nomes explícitos para as funções da modelagem tornam os comentários desnecessários no controlador.
A modelagem é dedicada ao acesso de dados, e pode ser organizado de acordo. Todos os parâmetros que não precisam da camada de dados (como parâmetros de requisição) devem ser enviados ao controlador e não acessados diretamente pela modelagem. As funções de modelagem podem ser facilmente reutilizadas em outros controladores.
Separando camadas além do MVC
O princípio da arquitetura MVC é separar o código em três camadas, de acordo com suas naturezas. Códigos voltados aos dados são armazenados na modelagem, a interface na visualização, e a lógica da aplicação no controlador.
Outros padrões adicionais de design pode tornar a experiência de desenvolver códigos ainda mais simples. As camadas de modelagem, da visualização, e do controlador podem ser subdivididas em mais outras camadas.
Abstraindo a Base de Dados
A camada de modelagem pode ser dividida em uma camada de acesso aos dados e uma camada de abstração da base de dados. Deste modo, funções de acesso aos dados não utilizarão comandos dependentes do tipo de base de dados utilizada, mas outras funções que executarão os comandos em seu lugar. se você trocar a base de dados mais tarde, apenas a camada de abstração precisará ser atualizada.
Um exemplo de uma camada de acesso é exibida na lista 2-6, seguido de um exemplo de uma camada de abstração na lista 2-7.
Lista 2-6 - A camada de abstração da modelagem
<?php function open_connection($host, $user, $password) { return mysql_connect($host, $user, $password); } function close_connection($link) { mysql_close($link); } function query_database($query, $database, $link) { mysql_select_db($database, $link); return mysql_query($query, $link); } function fetch_results($result) { return mysql_fetch_array($result, MYSQL_ASSOC); }
Lista 2-7 - A camada de acesso da modelagem
function getAllPosts() { // Connecting to database $link = open_connection('localhost', 'myuser', 'mypassword'); // Performing SQL query $result = query_database('SELECT date, title FROM post', 'blog_db', $link); // Filling up the array $posts = array(); while ($row = fetch_results($result)) { $posts[] = $row; } // Closing connection close_connection($link); return $posts; } ?>
Como você pode ver, nenhuma função dependente de uma base de dados específica é encontrada na camada de acesso, tornando-a independente da base de dados. Além disto, as funções criadas na camada de abstração podem ser reutilizadas em muitos outras funções que acessam à base de dados.
Os exemplos na lists 2-6 e 2-7 podem não ser muitos satisfatórios, e há muito trabalho para se obter uma abstração completa de uma base de dados (abstrair o código SQL através de um construtor indepente de base de dados, movendo todas as funções para uma classe, entre outros). Mas o objetivo deste livro não é mostrar como escrever todo o código, e você irá perceber no [[Symfony:cap/8 capítulo 8]] que o symfony faz nativamente muito bem toda a abstração.
Elementos de Vizualização
A camada de visualização pode também se benefiar com alguma separação de códigos. Páginas web de uma mesma aplicação geralmente contém elementos comuns entre si: os cabeçalhos, o layout gráfico, o rodapé, e o modo de navegar. Apenas o conteúdo da página muda. Por isto que a visualização é separada em uma camada de layout e uma camada de modelo. O layout geralmente e global para a aplicação, ou à um grupo de páginas. O modelo apenas da forma ao modo como as variáveis são disponibilizadas pelo controlador. Um pouco de lógica é necessária para fazer com que estes componentes trabalhem em conjunto, e a camada lógica da visualização irá servir para esta função. De acordo com estes principios, a camada de visualização exibida na lista 2-3 pode ser separada em tres partes, como exibido nas listas 2-8, 2-9 e 2-10.
Lista 2-8 - A camada de modelo da visualização, em mytemplate.php
<h1>List of Posts</h1> <table> <tr><th>Date</th><th>Title</th></tr> <?php foreach ($posts as $post): ?> <tr> <td><?php echo $post['date'] ?></td> <td><?php echo $post['title'] ?></td> </tr> <?php endforeach; ?> </table>
Lista 2-9 - A camada lógica da visualização
<?php $title = 'List of Posts'; $content = include('mytemplate.php'); ?>
lista 2-10 - A camada de layout da visualização
<html> <head> <title><?php echo $title ?></title> </head> <body> <?php echo $content ?> </body> </html>
Ações e Controlador Principal
O controlador não faz muito no exemplo anterior, mas em aplicações reais o controlador tem muito trabalho por fazer. Uma importante parte deste trabalho geralmente é comum à todos os controladores de uma aplicação. As tarefas comuns de tratar requisições, garantir a segurança da aplicação, carregar as configurações da aplicação, entre outras atividades semelhantes. É por isto que que o controlador geralmente é dividido em uma camada principal, que é única para toda a aplicação, e uma camada de ações, que contem apenas os códigos expecificos de contrle de uma única página.
Uma das grandes vantagens do controlador principal é a de que ele oferece um modo único de acessar a aplicação inteira. Se você decidir fechar o acesso à aplicação, você precisa apenas editar o script do controlador principal. Em uma aplicação sem um controlador principal, cada controlador individual teria de ser desligado.
Orientação à Objeto
Todos os exemplos citados anteriormente utilizando uma programação procedural. As capacidades de programar orietado a objetos das linguagens atuais fazem a tarefa de programar ainda mais fácil, uma vez que ojetos pode encapsular código, herdar de outros, e permitir uma simples convenção de nomes.
Implementando uma arquitetura MVC em uma linguagem não-orientada à objetos gera problemas com a nomenclatura de variáveis e duplicação de código, e o código resultante tende a ser difícil de ler.
Orientação à objetos permite desenvolvedores à lidar com tais coisas como objetos de visualização, objetos de controle, e classes de modelagem, e transformar todas as funções dos exemplos anteriores em métodos. É um dos pontos altos das arquiteturas MVC.
{{tip| Se você deseja aprender mais sobre padrões de design para aplicações web utilizando orientação à objetos, leia Patterns of Enterprise Application Architecture, de Martin Fowler (Addison-Wesley, ISBN: 0-32112-742-0). Exemplos de códigos nos livros de Fowler são em java ou C#, mas ambas as linguagens são de fácil compreensão para um desenvolvedor PHP }}
Implementação MVC no Simfony
Só um pouco! Para apenas uma página listando mensagens de um weblog, quantos componentes são necessários ? Como ilustrado na figura 2-2, nós temos as seguintes partes:
* Camada de Modelagen ** Abstração ** Acesso * Camada de Visualização ** Lógica ** Modelo ** Layout * Camada de Controle ** Controle Principal ** Ações
Sete scripts -- um monte de arquivos para abrir e modificar cada vez que você criar uma nova página! Entretanto, symofony torna as coisas mais fáceis. Tirando o melhor da arquitetura MVC, Symfony as implementa de modo a tornar o desenvolvimento de aplicações uma atividade rápida e simples.
Primeiro, o controlador principal e o layout são comuns à todas as atividades da aplicação. Você pode ter diversos controladores e layouts, mas precisa apenas de um. O controlador principal é um componente com apenas lógica MVC pura, e você nunca irá precisar escrever um pois Symfony irá gerá-lo para você.
A outra boa notícia é que as classes da camada de modelagem também são geradas automaticamente, baseados na sua estrutura de dados. Este é um trabalho para a biblioteca [[Symfony:Propel|Propel]], que fornece esqueletos de classes e geração de código. Se o Propel encontrar atributos Foreign Key ou campos de dados, ele irá criar acessos especiais e métodos diferenciados que tornarão a manipulação dos dados algo simples como café da manhã. E a abstração da base de dados é algo completamente invisível para você, porque é tratada por outro componente, chamado [[Symfony:Creole|Creole]]. Portanto se você decidir trocar o tipo de base de dados a ser usada na sua aplicação, você terá de re-escrever nenhuma linha de código. Você apenas precisará trocar um parâmetro de configuração.
E a última coisa é que a camada de visualização pode ser facilmente traduzida com um simples arquivo de configuração, necessitando nenhuma programação adicional.
Isso significa que a lista de mensagens descrita em nosso exemplo irá precisar apenas tres arquivos para trabalhar com o symfony, como exibido nas listas 2-11, 2-12 e 2-13.
Lista 2-11 - Ações, na camada de controle, em <code>myproject/apps/myapp/modules/weblog/actions/actions.class.php</code> << insire aqui a lista 2-11 >>
Lista 2-12 - Modelo, na camada de visualização, em <code>myproject/apps/myapp/modules/weblog/templates/listSuccess.php</code> << insire aqui a lista 2-12 >>
Lista 2-13 - Lógica, em <code>myproject/apps/myapp/modules/weblog/config/view.yml</code> << insire aqui a lista 2-13 >>
Você ainda terá de definir um layout, mas uma vez definido este poderá ser reutilizado por todas as demais janelas da aplicação.
Lista 2-14 - Layout, em <code>myproject/apps/myapp/modules/weblog/layout/layout.php</code> << insire aqui a lista 2-14 >>
E é apenas isso que você precisa. Este é o código necessário para exibir a mesma página do simples script exibido na lista 2-1. O resto (fazer todos os componentes trabalharem juntos) é gerenciado pelo Symfony. Se você contar as linhas, você verá que criar a lista utilizando a arquitetura MVC com o Symfony não requer muito mais tempo ou código que escrevendo um arquivo simples. Entretanto, ele lhe fornece grandes vantagens: orgnização clara do código, reusabilidade, flexibilidade, e muito mais. Como um bônus, você possui conformidade XHTML, capacidades de debug, facilidade de configuração, abstração da base de dados, redirecionamento inteligente de URLs, múltiplos ambientes, e muitas ferramentas de desenvolvimento a mais.
Classes Principais do Symfony
A implementação do MVC no symfony utiliza diversas classes que você irá encontrar com alguma freqüência neste livro:
* sfController é a classe de controle. Ela decodifica as requisições e as entrega às Ações
* sfRequest armazena todas os elementos de requisição (parâmetros, cookies, cabeçalhos, entre outros)
* sfResponse contém os cabeçalhos de resposta e conteúdo. Este é o objeto que irá eventualmente ser convertido nos códigos HTML que serão enviados ao usuários.
* A singularidade de contexto (recebido de [[sfContext#getInstance|sfContext::getInstance()]]) armazena a referência para todos os objetos principais e configurações correntes, sendo acessível de qualquer lugar.
Você aprenderá mais sobre estes objetos no [[Symfony:Capitulo 6|Capítulo 6]].
Como você pode ver, todas as classes do symfony utilizam o prefixo sf, assim como as variáveis principais nos modelos do symfony. Isto deve ajudar a evitar colisão de nomes com suas classes e variáveis, e tornar as classes do framework faceis de serem reconhecidas.
{{FYI| Entre os padrões de códigos utilizados pelo Symfony, UpperCamelCase é o padrão utilizado para nomenclatura de variáveis e classes. Duas excessões existem: as classes do symfony iniciam com sf, o que é minisculo, e as variáveis encontrados nos modelos utilizam a sintaxe separada com underscore. }}
Organização de Código
Agora que você conhece os diferentes componentes de uma aplicação Symfony, você provavelmente deve estar se perguntando como estes são organizados. Symfony organiza o código em uma estrutura de projeto e põe os arquivos deste em uma estrutura em árvore padrão.
Estrutura de Pojeto
:Aplicacões, Módulos e Ações
No symfony, um projeto é um conjunto de serviços e operações disponíveis em um dado domínio, compartilhando o mesmo modelo de objetos.
Dentro de um projeto, as operações são agrupadas logicamente em aplicações. As aplicações podem ser executadas independentemente das outras aplicações de um mesmo projeto. Em muitos casos, um projeto irá conter duas aplicações: uma para aplicações front-office e outras para aplicações back-office, compartilhando uma mesma base de dados. Mas você também pode ter projetos contendo diversos pequenos sites, cada um como uma aplicação diferente. Perceba que os hyperlinks entre aplicações devem estar todos em formato absoluto (??).
cada aplicação é um conjunto de um ou mais módulos. Um módul geralmente representa uma página ou um grupo de páginas com um propósito similar. Por exemplom você pode ter os módulos <code>Home</code>, <code>artigos</code>, <code>ajuda</code>, <code>carrinhoDeCompras</code>, <code>conta</code>, entre outros.
Módulos guardam ações, que representam as várias ações que podem ser feitas em um módulo. Por exemplo, um módulo <code>carrinhoDeCompras</code> pode possuir ações do tipo <code>adicionar</code>, <code>exibir</code> e <code>atualizar</code>. Geralmente, ações podem ser descritas com um verbo. Trabalhar com ações é quase o mesmo que trabalhar com páginas de uma aplicação web clássica, apesar de que duas mesmas ações acabem resultando na mesma página (adicionar um comentário num weblog irá exibir a janela de comentários com o novo comentário)
{{tip| Se isto representa muitos níveis para um projeto inicial, é muito fácil agrupar todas as ações em um único módulo, de modo a manter a estrtura de arquivos simples. A medida que a aplicação se torna mais complexa, será necessário separar as ações em módulos separados. Como mencionado no [[Symfony:Capitulo 1|Capítulo 1]], reescrever código de modo a melhorar sua esturutra ou facilitar sua leitura (mas preservando seu comportamento) é chamado refactoring, e você irá fazer isso um monte quando aplicando os [[RAD|princípios RAD]]. }}
A figura 2-3 ilustra uma amostra da organização de um projeto para um weblog, com uma estrutura projeto/aplicaçao/módulo/ação. Mas esteje ciente de que a real estrutura em arvore do projeto será diferente da ilustrada na figura.
Estrutura de Arquivos
Todos os projetos geralmente compartilham o mesmo tipo de conteudo, como os seguintes:
* uma base de dados, como MySQL ou PostgreSQL * arquivos estáticos (HTML, imagens, códigos javascript, planilhas, entre outros) * arquivos enviados pelos uusários e administradores do site * classes e bilbliotecas PHP * bibliotecas adicionais (scripts desenvolvidos por terceiros) * [[batch|arquivos de batch]] (scripts que serão executados por uma linha de comando) * arquivos de log (registrados pelo aplicativo e/ou servidor) * arquivos de configuração
Symfony oferece uma estrutura padrão de arquivos em árvore para organizar todo este conteúdo de uma maneira lógica, consistente com as escolhas de arquitetura (padrões MVC e agrupamentos projeto/aplicação/módulo). Esta é a estrutura em árvores que será automaticamente criada quando inicializado um projeto, aplicacação ou módulo. É claro, você pode personalizar isto completamente, para reorganizar os arquivos e diretórios de acordo com sua conveniência ou para atender às necessidades dos clientes.
Raiz da Estrutura de Árvore
Estes são os diretórios encontrados na raiz de um projeto symfony. A tabela 2-1 descreve o conteúdo destes diretórios.
apps/ frontend/ backend/ batch/ cache/ config/ data/ sql/ doc/ lib/ model/ log/ plugins/ test/ unit/ functional/ web/ css/ images/ js/ uploads/
A Tabela 2-1 descreve o conteúdos destes diretórios.
Tabela 2-1 - Diretórios na Raiz
| Diretório | Descrição |
|---|---|
apps/ |
Contém um diretório para cada aplicação do projeto(tipicamente, `frontend` e `backend` para o controlador frontal e de administração). |
batch/ |
Contém os scripts PHP chamados a partir da linha de comando ou de um agendador de tarefas, para rodar como processo de lote. |
cache/ |
Contém a versão em cache da configuração, e (se você ativá-la) a versão cache das ações e templates do projeto. O mecanismo de cache (detalhado no Capítulo 12) usa estes arquivos para aumentar a velocidade de resposta das requisições web. Cada aplicação terá um subdiretório aqui, contendo arquivos pré-processados de PHP e HTML. |
config/ |
Contém a configuração geral do projeto. |
data/ |
Aqui, você pode armazenar arquivos de dados do projeto, como um esquema de banco de dados, um arquivo SQL que cria tabelas, ou até mesmo um pequno arquivo de banco de dados do SQLite. |
doc/ |
Armazena a documentação do projeto, incluindo seus próprios documentos e a documentação gerada pelo PHPdoc. |
lib/ |
Dedicado a classes e bibliotecas externas. Aqui, você pode adicionar o código que precisa ser compartilhado entre as suas aplicações. O subdiretório model/ armazena a modelagem objeto do projeto (descrito no Capítulo 8). |
log/ |
Armazena os arquivos de log gerados diretamente no symfony. Ele também pode conter arquivos de log do servidor web, arquivos de log de banco de dados, ou arquivos de log de qualquer parte do projeto. Symfony cria um arquivo de log por aplicação e por ambiente de desenvolvimento (arquivos de log são discutidos no Capítulo 16). |
plugins/ |
Armazena os plug-ins instalados na aplicação (plug-ins são discutidos no Capítulo 17). |
test/ |
Contém os testes de unidade e funcionalidade escritos em PHP e compatíveis com o framework de testes do symfony(discutida no Capítulo 15). Durante a configuração do projeto, symfony automaticamente adiciona arquivos temporários com alguns testes básicos. |
web/ |
A raiz para o servidor web. Os únicos arquivos acessíveis através da Internet são aqueles localizados neste diretório. |
Estrutura em Árvore da Aplicação
A estrutura em árvore dos diretórios de todas as aplicações é sempre a mesma. A tabela 2-2 decreve o conteúdo dos subdiretórios:
apps/
[nome da aplicação]/
config/
i18n/
lib/
modules/
templates/
layout.php
error.php
error.txt
A tabela 2-2 descreve os subdiretórios da aplicação.
Tabela 2-2 - Subdiretórios da Aplicação
| Diretório | Descrição |
|---|---|
config/ |
Armazena um poderoso conjunto de arquivos de configuração YAML. Aqui é o local em que se encontra a maior parte da configuração da aplicação, separado dos parâmetros padrões que podem ser encontrados no próprio framework. Repare que os parâmetros padrões podem ser sobrescritos aqui se necessário. Você irá aprender mais sobre como configurar uma aplicação no Capítulo 5 |
i18n/ |
Contém arquivos usados para a internacionalização(i17o) da aplicação--em sua maioria arquivos para a tradução (O capítulo 13 discorrerá sobre internacionalização). Você pode esquecer deste diretório se você usar um banco de dados para realizar a internacionalização. |
lib/ |
Contém classes e bibliotecas específicas para esta aplicação. |
modules/ |
Armazena todos os módulos que contém os recursos da aplicação. |
templates/ |
lista os modelos globais da aplicação -- aqueles que são compartilhados por todos os módulos. Por padrão, ele contém o arquivo layout.php, que é o layout principal em que os templates de todos os módulos são inseridos. |
{{FYI| Os diretórios <code>i18n/</code>, <code>i18n</code> e <code>modules/</code> se encontram vazios para cada nova aplicação. }}
As classes de uma aplicação não são capazes de acessar métodos e atributos de outras aplicações de um mesmo projeto. Perceba tambem que os hyperlinks entre duas aplicações de um mesmo projetos devem se encontrar no modo absoluto. Você tem de manter isto em mente durante as etapas iniciais, onde você decide em quantas aplicações o projeto será dividido.
Estrutura em Árvores dos Módulos
Cada aplicação possui um ou mais módulos. Cada módulo possui seu próprio subdiretório na pasta <code>modules/</code>.
Abaixo segue uma estrutura em árvore típica de um módulo. A tabela 2-3 descreve o conteúdo de cada diretório.
apps/
[nome da aplicação]/
modules/
[nome do módulo]/
actions/
actions.class.php
config/
lib/
templates/
indexSuccess.php
validate/
A Tabela 2-3 descreve os subdiretórios de um módulo.
Tabela 2-3 - Subdiretórios de um Módulo
| Diretório | Descrição |
|---|---|
actions/ |
Geralmente contém um arquivo de classe único nomeado de actions.class.php, no qual você pode armazenar todas as ações do módulo. Você pode também escrever diferente ações de um módulo em arquivos diferentes. |
config/ |
Pode conter arquivos de configuração personalizados com os parâmetros locais para o módulo. |
lib/ |
Armazena classes e bibliotecas específicas para o módulo. |
templates/ |
Contém os templates correspondentes as ações do módulo. Um template padrão chamado indexSuccess.php, é criado no momento da criação de um módulo. |
validate/ |
Dedicado aos arquivos de configuração usados para validação de formulários (discutido no Capítulo 10). |
{{FYI| Os diretórios <code>config/</code>, <code>lib/</code> e <code>validate/</code> se encontram vazios para cada novo módulo. }}
Estrutura em Árvore da Web
Existem poucas particularidades quanto ao diretório web, que é o diretório com as arquivos acessiveis publicamente. Seguinto umas poucas convenções de nomenclatura, é possível criar comportamentos padrões e atalhos úteis para os modelos. Abaixo segue um exemplo da estrutura de um diretório web. Por convenção, os artquivos estáticos são distribuidos nos diretórios listados na tabela 2-4.
web/ css/ images/ js/ uploads/
Convencionalmente, os arquivos estáticos são distribuídos nos diretórios listados na tabela 2-4.
Tabela 2-4 - Subdiretórios típicos da pasta Web
| Diretório | Descrição |
|---|---|
css/ |
Contém arquivos de folha de estilo com a extensão .css. |
images/ |
Contém imagens com a extensão .jpg, .png, ou .gif. |
js/ |
Contém arquivos JavaScript com a extensão .js. |
uploads/ |
Deve conter os arquivos carregados pelos usuários. Apesar do diretório geralmente conter imagens, ele se distingue do diretório de imagens de modo que a sincronização dos servidores de desenvolvimento e de produção não afetem as imagens enviadas. |
{{FYI| Mesmo sendo extremamente recomendado que você mantenha a estrutura em árvore padrão, é possível modificar esta de modo a anteder suas necessidades, como permitir que um projeto rode em um servidor com diferentes regras para estruturas e convenções de código. Leia o [[Symfony:Capitulo 19|Capítulo 19]] para maiores informações sobre modificar a estrutura de arquivos. }}
Instrumentos Comuns
Algumas técnicas são utilizadas repetidamente no symfony, e você as encontrará com certa freqüência neste livro e em seus próprios projetos. Isto inclui os parâmetros, constantes, e carregadores automáticos de classes.
Parâmetros
Muitas das classes do symfony contém um parâmetro. É um modo conveninente de encapsular atributos com métodos de busca e atribuição. Por exemplo, a classe sfResponse armazena os parâmetros que você pode recuperar chamando o método getParameterHolder(). Cara parâmetro armazena informação do mesmo modo, como ilustrado na Lista 2-15.
Lista 2-15 - Usando sfResponse << insira aqui a lista 2-15 >>
Muitas das classes utilizando um parâmetro disponibilizam métodos alternativos para encurtar o código necessário para operações get/set. Para isto se usa o objeto sfResponse, de modo que você consegue fazer o mesmo apresentando em Lista 2-15 com o código da Lista 2-16.
Lista 2-16 - Utilizando métodos alternativos do SfResponse? de acesso à parametros << insira aqui Lista 2-16 >>
A função get do parâmetro aceita valores default como segundo argumento. Isso oferece um útil mecanismo à prova de erros muito mais simples que o obtido com verificações condicionais. Veja a Lista 2-17 para um exemplo.
Lista 2-17 - Utilizando o valor default do get de um parâmetro. << insira aqui a função 2-17 >>
Parâmetros suportam inclusive [[namespace|namespaces]]. Se você especificar um terceiro argumento para uma função de set ou get, este é utilizado como namespace, e o parêmetro será definido apenas dentro deste. Veja a Lista 2-18 para um exemplo.
Lista 2-18 - Utilizando namespaces de um parâmetro sfResponse << insira aqui a lista 2-18 >>
É claro, você pode adicionar um parâmetro às suas classes de modo a tirar vantagem de suas facilidades de sintaxe. A lista 2-19 mostra como definir uma classe com um parâmetro.
Lista 2-19 - Adicionando um parâmetro à uma classe << insira aqui a lista 2-19 >>
Constantes
Surpreendentemente, você irá encontrar poucas constantes no Symfony. Isto porque constantes possuem um grave problema no PHP: uma vez definidas, você não pode modifica-las. Portanto o Symfony utiliza seu próprio objeto de configuração, chamado sfConfig, que substitui constantes. Ele oferece métodos estáticos para acesar parametros de qualquer lugar. A lista 2-20 demonstra a utilização de métodos da classe sfConfig.
Lista 2-20 - Utilizando métodos da classe sfConfig ao invés de constantes. << insira aqui a Lista 2-20 >>
Os métodos de sfConfig suportam valores default, e você pode invocar o método <code>sfCondig::set()</code> diversas vezes para um mesmo parâmetro para alterar seu valor. O [Capítulo 5?] explica os métodos de <code>sfConfig</code> com mais detalhes.
Listing 2-20 - Using the sfConfig Class Methods Instead of Constants
// Instead of PHP constants, define('SF_FOO', 'bar'); echo SF_FOO; // Symfony uses the sfConfig object sfConfig::set('sf_foo', 'bar'); echo sfConfig::get('sf_foo');
The sfConfig methods support default values, and you can call the sfConfig::set() method more than once on the same parameter to change its value. Chapter 5 discusses sfConfig methods in more detail. Class Autoloading
Classically, when you use a class method or create an object in PHP, you need to include the class definition first.
include 'classes/MyClass.php'; $myObject = new MyClass();
But on large projects with many classes and a deep directory structure, keeping track of all the class files to include and their paths takes a lot of time. By providing an autoload() function (or a spl_autoload_register() function), symfony makes include statements unnecessary, and you can write directly:
$myObject = new MyClass();
Symfony will then look for a MyClass? definition in all files ending with php in one of the project's lib/ directories. If the class definition is found, it will be included automatically.
So if you store all your classes in lib/ directories, you don't need to include classes anymore. That's why the symfony projects usually do not contain any include or require statements.
For better performance, the symfony autoloading scans a list of directories (defined in an internal configuration file) during the first request. It then registers all the classes these directories contain and stores the class/file correspondence in a PHP file as an associative array. That way, future requests don't need to do the directory scan anymore. This is why you need to clear the cache every time you add or move a class file in your project by calling the symfony clear-cache command. You will learn more about the cache in Chapter 12, and about the autoloading configuration in Chapter 19.
Summary
Using an MVC framework forces you to divide and organize your code according to the framework conventions. Presentation code goes to the view, data manipulation code goes to the model, and the request manipulation logic goes to the controller. It makes the application of the MVC pattern both very helpful and quite restricting.
Symfony is an MVC framework written in PHP 5. Its structure is designed to get the best of the MVC pattern, but with great ease of use. Thanks to its versatility and configurability, symfony is suitable for all web application projects.
Now that you understand the underlying theory behind symfony, you are almost ready to develop your first application. But before that, you need a symfony installation up and running on your development server.


