Upload do arquivo symfony2 passo a passo

Ainda estou aprendendo o Symfony2 e não entendo como fazer upload de um arquivo.

Não se preocupe, eu já verifiquei a documentação . É muito bom, mas meu problema não é explicado em nenhum tutorial.

Eu estou procurando orientação sobre como fazer upload de um arquivo com o Symfony2, mas com todas as coisas que todo mundo precisa (como restrição de extensão, renomear o arquivo com base no id e outras coisas, armazenar o caminho no database, etc …)

Eu encontrei bons tutoriais, tentei misturá-los, mas sem sucesso. Cada vez que um problema diferente aparece: upload de arquivos em cada envio no formulário (mesmo se o campo do arquivo estiver vazio), guessExtension impossível de ser usado, caminho tmp armazenado no database em vez do caminho certo, arquivo não movido, impossível usou o id na renomeação porque o id está no auto-incremento e por isso ainda não foi gerado).

Então, vou colocar uma entidade ‘padrão’, digamos: Photo.php

/** * Photo * * @ORM\Table(name="photo") * @ORM\Entity * @ORM\HasLifecycleCallbacks */ class Photo { // Annotation for the id and auto increment etc private $id; /** * @var string * @Assert\File( maxSize = "3072k", mimeTypesMessage = "Please upload a valid Image") * @ORM\Column(name="image", type="string", length=245, nullable=false) */ private $image private $title private $description // all the function get, set for the 4 previous variables } 

e o controlador:

 public function addPhotoAction() { $add_photo = new Photo; $formBuilderPhoto = $this->createFormBuilder($add_photo); $formBuilderPhoto ->add('title','text',array('label' => 'Title of the photo', 'required' => true)) ->add('image','file', array('required' => true, 'data_class' => null)) ->add('description','textarea',array('label' => 'Description of your photo', 'required' => false)) ; $form_photo = $formBuilderPhoto->getForm(); if ($request->getMethod() == 'POST') { $form_photo->bind($request); if ($form_photo->isValid()) { // ... } } return $this->render('MyBundle:frontend:photo.html.twig', array('form_photo' => $form_photo->createView()) ); } 

Você sabe agora qual é a function “importante” a ser adicionada para poder enviar a foto e renomeá-la?

Como você verifica a extensão para ver se o upload é possível?

Qual é a sua maneira real de fazer uma coisa dessas com o Symfony2? Eu sei que há um monte de Bundle que faz todas essas coisas para você, mas eu quero aprender a fazê-lo e entender o processo.

Qual é a maneira ‘clássica’ de implementar um formulário de upload de arquivos e renomear a function com o Symfony2?

Você sabe agora qual é a function “importante” a ser adicionada para poder enviar a foto e renomeá-la?

Veja a documentação oficial sobre como fazer isso. Existem bons exemplos de trabalho para um simples upload de arquivo. Além disso, verifique a documentação da doctrine para retornos de chamada de ciclo de vida .

Como você verifica a extensão para ver se o upload é possível?

Existe alguma validação de formulário HTML em cada navegador. Veja esta pergunta para o atributo HTML accept="" em elementos de input . Também no Symfony2 você pode especificar o tipo MIME de um arquivo carregado usando esta anotação:

 /** * @Assert\File( * maxSize = "1024k", * mimeTypes = {"application/pdf", "application/x-pdf"}, * mimeTypesMessage = "Please upload a valid PDF" * ) */ 

Mesmo que você não queira usar nenhum pacote, terei que recomendar o KnpDoctrineBehavioursBundle, que facilita muito o upload de arquivos.


Passo a passo:

Porque você leu a documentação já vou dar-lhe um exemplo de código passo a passo.

Primeiro de tudo você precisa de uma entidade. Vamos chamá-lo Image :

 /** * Class Image * * @ORM\Entity() * @ORM\HasLifecycleCallbacks */ class Image extends BaseEntity { 

Observe a anotação @ORM\HasLifecycleCallbacks . É muito importante e você precisa disso mais tarde. Criamos todos os campos básicos como ID e o que não. Também precisamos de um campo para armazenar o caminho do arquivo em:

  /** * Image path * * @var string * * @ORM\Column(type="text", length=255, nullable=false) */ protected $path; 

E um para a própria imagem. Aqui também definimos a validação para as imagens. No meu exemplo, tem que ser 5M grande e de um dos mimeTypes definidos. Deve ser auto-explicativo. Caso contrário, os documentos oficiais ajudarão como sempre.

  /** * Image file * * @var File * * @Assert\File( * maxSize = "5M", * mimeTypes = {"image/jpeg", "image/gif", "image/png", "image/tiff"}, * maxSizeMessage = "The maxmimum allowed file size is 5MB.", * mimeTypesMessage = "Only the filetypes image are allowed." * ) */ protected $file; 

Adicione todos os Getters & Setters e atualize seu esquema de database com este comando:

 php app/console doctrine:schema:update --force 

Em seguida, precisamos dos ciclos de vida . Eles são methods na Entity que são chamados em determinados events. Por exemplo, a @ORM\PreUpdate() antes de um método diz que esse método está sendo chamado logo antes de a entidade ser atualizada.

 /** * Called before saving the entity * * @ORM\PrePersist() * @ORM\PreUpdate() */ public function preUpload() { if (null !== $this->file) { // do whatever you want to generate a unique name $filename = sha1(uniqid(mt_rand(), true)); $this->path = $filename.'.'.$this->file->guessExtension(); } } 

Antes que a entidade seja armazenada ou atualizada, esse método é chamado. Você pode usá-lo para, por exemplo, gerar um nome de arquivo exclusivo.

 /** * Called before entity removal * * @ORM\PreRemove() */ public function removeUpload() { if ($file = $this->getAbsolutePath()) { unlink($file); } } 

Chamado antes que a entidade seja removida. Isso permite que você exclua a imagem das suas pastas ou registre uma mensagem, se desejar.

 /** * Called after entity persistence * * @ORM\PostPersist() * @ORM\PostUpdate() */ public function upload() { // The file property can be empty if the field is not required if (null === $this->file) { return; } // Use the original file name here but you should // sanitize it at least to avoid any security issues // move takes the target directory and then the // target filename to move to $this->file->move( $this->getUploadRootDir(), $this->path ); // Set the path property to the filename where you've saved the file //$this->path = $this->file->getClientOriginalName(); // Clean up the file property as you won't need it anymore $this->file = null; } 

Essa é a parte importante em que o arquivo é movido para o diretório correto. Observe que eu usei alguns methods adicionais. Todos podem obtê-los dos documentos oficiais .

A próxima coisa que você precisa é de um formulário. A class de formulário em si é muito simples. Apenas certifique-se de definir o padrão data_class assim:

 public function setDefaultOptions(OptionsResolverInterface $resolver) { $resolver->setDefaults( array( 'data_class' => 'FSchubert\SiyabongaBundle\Entity\Image', ) ); } 

Um campo de upload de arquivo pode ser criado com muita facilidade no método buildForm() :

 $builder->add('file', 'file'); 

Os methods para o seu Controller são um pouco longos para apenas colá-los aqui e IMHO não faz parte de responder a sua pergunta. Existem inúmeros exemplos por aí para escrever uma Controller Action apropriada para o seu propósito.


Mais coisas que você deve ter em mente:

  • Você precisa dar permissions de escrita ao app para as pastas nas quais você fez o upload dos arquivos. Embora pareça óbvio, pode ser irritante se você tiver vários servidores nos quais executa o aplicativo.
  • Há uma Image Constraint para sua entidade também. Você pode encontrá-lo aqui . Mas desde que você estava falando sobre um arquivo de upload eu usei a File Constraint lugar.
  • Como mencionei no início deste post, existem muitos pacotes que lidam com todas essas coisas para você. Confira se você quer uma vida fácil.

Editar:

  • Alterado de DoctrineExtensionsBundle para DoctrineBehaviours pois o desenvolvimento do antigo parou em favor do pacote DoctrineBehaviours .

Eu recomendo que você use o pacote de mídia vlabs .

O VichUploaderBundle também é fácil de usar para o upload de arquivos:

https://github.com/dustin10/VichUploaderBundle