Upload de arquivos com Symfony

André Chaves
Code Maestro
Published in
6 min readApr 9, 2018

Um dos primeiros desafios de quem está começando na web (ou em algum framework) é realizar upload de arquivos. Além de ser uma dúvida bem comúm lá no forum da alura.

Como realizar o processo todo? Como guardar a imagem no banco? Como exibir? Nesse post vamos passar por todo o processo de upload de imagens com Symfony 4.

Criando o formulário

O primeiro passo de todo upload, seja lá qual for, sempre passará por uma requisição HTTP.

E, para enviar dados nada melhor que um formulário ou Ajax. A vantagem de formulários no Symfony é que temos como representar tudo no back-end com os FormTypes!

Ou seja, podemos criar um formulário que contenha nossa imagem. Algo como:

Criando o formulário com a foto

E renderizar na view todo o formulário:

renderizando o formulário na view

Porém, se executarmos essa action temos na view apenas um campo de texto!

campo foto renderizado

Especificando tipos no FormType

Por padrão, o Symfony sempre traz campos do tipo texto pra gente na view. Mas, no nosso caso, queriamos um campo que recebesse um arquivo!

Para isso, podemos dizer pro Symfony qual é tipo o campo que está sendo adicionado recebe, no segundo parametro do método add =)

Especificando o tipo

No nosso caso, queremos o tipo Arquivo (FileType).

Agora, como na view estamos apenas chamando o formulário criado, nossa alteração ja deve ser propagada:

renderiação do formulário de arquivos

Além do FileType, existem muitos outros como MoneyType(para dinheiro), TextType, ChoiceType(para selects,checkboxes,etc), entre outros =)

Recebendo o arquivo na action

Perfeito, criamos o formulário renderizamos com o tipo certo. Mas, ao clickar no botão enviar, o que acontece? Nada!

Na nossa action, podemos validar os dados enviados no formulário e, ao mesmo tempo, verificar se ele foi enviado =)

Uma prática muito comúm no Symfony, com exemplos na própria documentação, é utilizar uma mesma rota para exibir e processar o formulário com a utilização de um método que verifica se o formulário foi enviado( isSubmited() ) naquela requisição:

verificando se o formulário foi enviado e se está válido

Essa é uma prática bem questionável já que estamos acumulando muita responsabilidade na indexAction.

Como comentamos bastante nos cursos da caelum,o ideal sempre é quebrar as funcionalidades em rotas diferentes. Por isso, vamos dizer qual é a rota do formulário explicitamente:

definindo action do formulário

E, finalmente, criamos uma action para lidar apenas com o envio da imagem:

envia imagem action

Processando o upload

Perfeito, temos as responsabilidades isoladas!

E, caso o formulário esteja válido, entramos no if.

Mas, o que precisamos fazer ao entrar naquele caso? Se o formulário foi enviado e está válido precisamos pegar a imagem e guardar ela no banco de dados. Certo? Errado!

Guardar imagem no banco?

Guardar a imagem diretamente no banco de dados implica no processo de transformar essa imagem em texto! Esse texto normalmente é uma representação em binário.

Mas para guardar uma imagem em um binário vai muito zero e um. Por isso, o tipo reservado pra isso no Mysql costuma ser o BLOB (Binary Large Object).

Realmente precisamos guardar a imagem em algum lugar, mas podemos guardar na memória da máquina!

Guadar o caminho no banco!

Agora, no banco de dados, a única coisa que precisaremos guardar é o caminho da imagem dentro da máquina =)

Ou seja, precisamos pegar o arquivo que veio no upload, pra isso basta usar o método getData do form:

pegando o arquivo

Como usamos o FileType do Symfony, o conteudo disponivel em foto é do tipo UploadedFile!

Uma classe que já vem com diversos métodos pra ajudar a gente! Como, por exemplo, um método que devolve o nome completo do arquivo getClientOriginalName():

pegando o nome do arquivo

E um método que move( move() ) o arquivo pro lugar que a gente quiser:

movendo o arquivo para a pasta public/uploads/img

Para garantir, antes de passar o diretório public/uploads/img, passamos todo o caminho do projeto no sistema operacional. Assim, não importa aonde o sistema vai ser executado, o upload sempre vai funcionar=)

No nosso caso, estamos movendo o arquivo para a pasta uploads/img dentro da pasta public!

pasta publica para uploads de imagem

Essa pasta não vem por padrão no framework, mas é legal ter ela (ou alguma do tipo) disponivel.

Desse jeito, a gente evita um banco super populado e deixamos a responsabilidade de guardar arquivos pro sistema operacional!

E o banco de dados?

Aqui, a gente tem um sistema que recebe uma imagem e joga pra uma pasta funcionando. Mas, como encontrar essa imagem depois? Seria legal ter alguma forma de persistir essa imagem no banco de dados!

Para mandar qualquer coisa pro banco, precisamos do Entity Manager para persistir:

chamando o entity manager

Mas, se executarmos a action agora, temos a exception:

exception

Isso porque a classe UploadedFile que estamos manipulando não está no nosso sistema! Ela faz parte dos componentes do Symfony e por isso não pode ser persistida.

Se quisermos representar essa imagem que estamos fazendo upload no nosso sistema, precisamos criar uma classe pra ela:

entidade Imagem

Aqui, estamos dizendo que Imagem é, finalmente, uma entidade mapeada pelo Doctrine, além disso ela tem uma coluna com o caminho.

Agora, basta criarmos uma imagem, e definir o caminho dela. Assim, podemos passar nossa entidade imagem para o Doctrine persistir:

persistindo a imagem

E, ao realizar clickar no botão enviar, conseguimos verificar nossa imagem na pasta uploads:

imagem na pasta correta

E, também é possivel verificar no banco de dados, com o caminho completo:

select da tabela imagem

Considerações finals

Aqui, já temos tudo que precisamos para trabalhar com a imagem no nosso sistema.

Caso seja necessario imprimir alguma imagem, basta usarmos a entidade imagem e pegar o caminho. Algo como:

<img src="{{ imagem.caminho }}" alt="">

Também é possivel utilizar essa entidade em composição. Por exemplo,

<img src="{{ usuario.imagem.caminho }}" alt="">

Basta que a classe Usuario tenha um atributo do tipo Imagem =)

E ai, o que acharam do upload de imagens no Symfony? Conhece algum outro jeito? Compartilha aqui com a gente!

--

--

André Chaves
Code Maestro

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