Injeção de dependências e ORM com Symfony

André Chaves
Code Maestro
Published in
6 min readFeb 26, 2018

Um dos primeiros problemas a ser resolvido em qualquer sistema é a comunicação com o banco de dados. Nosso sistema TikTok® já possui um modelo de Funcionário mas ainda não conseguimos efetivamente criar e guardar funcionários.

Nesse post vamos aprofundar em como persistir instâncias de uma classe no banco de dados com Symfony.

Renderizando formulários

Para gente conseguir criar um Funcionario, precisamos saber qual é o nome e a data de nascimento dele. Normalmente, quando precisamos receber dados do usuário, criamos um formulário com os campos necessários.

Para mostrar esse formulário no navegador, vamos criar uma rota responsável por chamar o Twig:

Action formulario

Na própria rota podemos especificar os métodos HTTP aceitos! No nosso caso, como queremos apenas mostrar o formulário utilizamos o método GET.

E, finalmente, um Twig com o formulário que receba os dados:

novo.html.twig

Acessando a url /funcionario/novo temos a tela:

formulário renderizado

Recebendo os dados do formulário

Ao clickar no botão criar, precisamos enviar os dados do funcionário para a rota /funcionario/novo. Mas, dessa vez, o método HTTP ideal é o POST.

Para isso, podemos criar uma outra rota, com o mesmo nome, mas que receba post. Assim cada rota fica com uma responsabilidade bem definida.

Uma carrega o formulário e a outra persiste os dados. Com isso, teremos duas rotas:

Rotas com GET e POST

Acessando o request

Perfeito, criamos as duas rotas, cada uma com sua responsabilidade. Mas, precisamos criar um novo funcionário com todos os dados e ainda mandar ele pro banco!

Criar um funcionário é facil, basta dar new. Mas, como pegar os dados do formulário?

Todos os dados que enviamos, estão no Request. Graças a injeção de dependências do Symfony, conseguimos receber o Request inteiro como parâmetro na própria action!

injeção do request na action de criação

Injeção de dependência?

O processo parece bem mágico, certo? Quem criou esse request? como ele foi parar ai? A magía toda acontece por baixo dos panos.

Quando acessamos uma action, o Symfony verifica o tipo de cada parâmetro e da new pra gente. O Request é fácil porque esse o framework já tem na mão. Afinal, é o framework quem processa todas as requisições.

Mas, a injeção de dependências vai muito além. Podemos configurar o framework para que injete qualquer classe nossa também!

Persistência de entidades no banco

Tendo o Request em mãos, podemos pegar qualquer dado dentro dele a partir do método get

acessando os dados do request com o método get

Perfeito, temos o funcionário pronto. Mas, ainda falta mandar pro banco.

Conectando com o banco

Normalmente, quando falamos de conexão com banco de dados a primeira coisa que vem na cabeça é: mysqli ou PDO?

Aqui, poderíamos criar uma conexão (tanto com mysqli quanto com PDO), ir no banco, criar a tabela funcionário, escrever uma query para inserir um funcionário pela action, jogar os dados no banco e correr pro abraço.

Porém, o processo de escrever querys, criar tabelas e gerenciar o banco de dados costuma ocupar muito tempo do nosso dia-a-dia.

Doctrine

Para resolver toda essa parte de: criar as tabelas necessárias, os campos e gerar a gigantesca maioria das queries que precisaríamos escrever existem os ORMs (Object Relacional Mapper).

O Symfony trabalha muito bem com o Doctrine, um dos ORMs mais famosos para php, que na ultima versão veio bastante influenciado pela JPA, uma especificação bem famosa (e muito boa) do mundo Java para persistência de dados.

Como de costume, para adicionar o Doctrine no nosso sistema, basta pedir pro composer

instalando o doctrine pelo composer

Configurando o Doctrine

Ao terminar a instalação, ja temos nosso arquivo de configuração:

bin/config/doctrine.yaml

Aqui vão todas as configurações relacionadas a banco! Inclusive, a url de conexão definida em env(DATABASE_URL), que por padrão vem vazia.

É nessa url que vamos indicar pro doctrine aonde se conectar, com qual usuário e senha. Algo como:

mysql://usuario_do_banco:senha@ipDoBanco:3306/nomeDaBase

Como essa variável é uma variável de ambiente(environment), podemos sobrescreve-la no arquivo .env, disponível na raiz do projeto:

arquivo .env

No nosso caso, vamos conectar local mesmo com usuário root e senha root e nosso banco se chamará Tiktok

configuração do arquivo .env pronta

Criando o banco

Tendo tudo configurado, basta pedirmos para o doctrine criar o banco pra gente através do comando bin/console doctrine:database:create

E pronto! Sem precisar de uma linha de SQL, criamos nosso banco de dados =)

Mapeando entidades

Tendo o banco criado, precisamos indicar pro Doctrine qual classe vai virar uma tabela. Para isso, basta utilizarmos a anotação Entity, da classe Doctrine\ORM\Mapping:

mapeando o funcionário

Perfeito, já indicamos a tabela. Mas, e as colunas?

É comum que os atributos da classe acabem virando uma coluna, por isso precisamos indicar o tipo de cada coluna, com a anotação Column

indicando as colunas

Pra finalizar, precisamos apenas indicar quem será o identificar único(mais conhecido como id) da tabela. Isso significa que, agora, nosso funcionário deve ter um campo id:

Entidade Funcionario pronta

Criando a tabela

Agora que indicamos tudo pro doctrine, falta mandar ele atualizar o banco de dados criando nossa tabela com as colunas. Para isso, podemos utilizar o comando doctrine:schema:update

Persistindo entidades

Temos tabela, entidade, ORM, formulário mas ainda não mandamos nada pro banco de dados!

Agora que temos tudo configurado é bem simples salvar nosso funcionário. Basta chamar o Doctrine pelo próprio controller e persistir

chamada do Doctrine

E, por fim, basta redirecionar para a tela que mostra usuarios

return $this->redirect("/funcionario/mostra/".$funcionario->getNome());

Assim, ele já vem com o nome do funcionário que acabamos de criar!

Melhorando a action mostra

Agora que temos o Doctrine integrado no nosso sistema, podemos receber o identificador do funcionário na action mostra. Assim, a gente consegue buscar o funcionário no banco de dados e devolver todos os dados de forma dinâmica na view:

buscando o funcionário

Bem melhor, certo? Pode ficar melhor ainda. Ao invés de termos que buscar o funcionário na mão, podemos pedir para que o Symfony injete o funcionário na nossa action!

injetando o funcionário

Por baixo dos panos, o que o Symfony faz é exatamente o que a gente fez. Chama o Doctrine, busca pelo id que foi passado na rota e injeta na nossa action.

Próximos passos

Agora que temos o banco de dados integrado pelo Doctrine no nosso sistema, vamos olhar com um pouco mais de carinho para as Views. Adicionar um pouco de estilo com Bootstrap e aprofundar mais nos Twigs.

E ai, o que você achou da injeção de dependências do Symfony? E do Doctrine? Trabalhar com ORMs pode reduzir muito nosso tempo de desenvolvimento no dia-a-dia.

Ah! O código pronto desse post você pode encontrar versionado no meu git!

--

--

André Chaves
Code Maestro

Empreendedor, CTO, desenvolvedor e apaixonado por automação.