how to "manually" process file upload with symfony2?
I found what I was looking for. To access the files uploaded to symfony from the controller, you just need to do this:
$request = $this->getRequest(); $file = $request->files->get('file1'); //file1 being the name of my form field for the file /* if your entity is set up like mine - like they teach you in the symfony2 cookbook * file is actually a public property so you can just set it like this **/ $entity->file = $file; //and here's how you get the original name of that file $entity->setName( $file->getClientOriginalName() );
First of all, if you want to get an entity with your file after form submit/bind/handleRequest or smth else, you need to provide data_class
option in form configuration method (setDefaultOptions
etc.). And only after that your form will start to return needed entity after submission.
1)First of All create your entity :
namespace XXX;use Doctrine\ORM\Mapping as ORM;use Symfony\Component\Validator\Constraints as Assert;/** * @ORM\Table() * @ORM\Entity */class Article{ /** * @var integer $id * * @ORM\Column(name="id", type="integer") * @ORM\Id * @ORM\GeneratedValue(strategy="AUTO") */ private $id; /** * @var string $image * @Assert\File( maxSize = "1024k", mimeTypesMessage = "Please upload a valid Image") * @ORM\Column(name="image", type="string", length=255) */ private $image; /** * Get id * * @return integer */ public function getId() { return $this->id; } /** * Set image * * @param string $image */ public function setImage($image) { $this->image = $image; } /** * Get image * * @return string */ public function getImage() { return $this->image; }}
2) build your form: So we will then create a simple form type for this Article entity in order to fit into the other forms: ArticleType.php
use Symfony\Component\Form\AbstractType;use Symfony\Component\Form\FormBuilder;class ArticleType extends AbstractType{ public function buildForm(FormBuilder $builder, array $options) { $builder ->add('image') ->add('...') ; } public function getName() { return 'xxx_articletype'; }}
3)Create the controller: The controller below shows you how to manage the whole process: ArticleController.php:
use Symfony\Bundle\FrameworkBundle\Controller\Controller;/** * Article controller. * */class ArticleController extends Controller{ /** * Finds and displays a Article entity. * */ public function showAction($id) { $em = $this->getDoctrine()->getEntityManager(); $entity = $em->getRepository('XXXBundle:Article')->find($id); if (!$entity) { throw $this->createNotFoundException('Unable to find Article entity.'); } return $this->render('XXXBundle:Article:show.html.twig', array( 'entity' => $entity, )); } /** * Displays a form to create a new Article entity. * */ public function newAction() { $entity = new Article(); //$entity = $em->getRepository('CliniqueGynecoBundle:Article'); $form = $this->createForm(new ArticleType(), $entity); return $this->render('XXXBundle:Article:new.html.twig', array( 'entity' => $entity, 'form' => $form->createView() )); } /** * Creates a new Article entity. * */ public function createAction() { $entity = new Article(); $request = $this->getRequest(); $form = $this->createForm(new ArticleType(), $entity); $form->bindRequest($request); if ($form->isValid()) { $em = $this->getDoctrine()->getEntityManager(); $em->persist($entity); $em->flush(); return $this->redirect($this->generateUrl('article_show', array('id' => $entity->getId()))); } return $this->render('XXXBundle:Article:new.html.twig', array( 'entity' => $entity, 'form' => $form->createView() )); } private function createDeleteForm($id) { return $this->createFormBuilder(array('id' => $id)) ->add('id', 'hidden') ->getForm() ; }}
4) layout for the upload form: new.html.twig
<form action="{{ path('basearticle_create') }}" method="post" {{ form_enctype(form) }}> {{ form_widget(form) }} <p> <button class="btn btn-primary" type="submit">Create</button> </p></form>
5) Display layout: show.html.twig
<table> <tr> <td align="center" valign="top"><img src="{{ asset('upload/' ~ entity.id ~'/' ~ entity.image)}}" alt="" height="525" width="666" /></td></tr></table>
6) Use the « Lifecycle Callbacks » hooking the entity in a « Lifecycle callbacks »: « @ ORM \ HasLifecycleCallbacks »
/** * * @ORM\Table() * @ORM\HasLifecycleCallbacks * @ORM\Entity */class Article{....
7) Added methods to download files:
class Article{ .................................... public function getFullImagePath() { return null === $this->image ? null : $this->getUploadRootDir(). $this->image; } protected function getUploadRootDir() { // the absolute directory path where uploaded documents should be saved return $this->getTmpUploadRootDir().$this->getId()."/"; } protected function getTmpUploadRootDir() { // the absolute directory path where uploaded documents should be saved return __DIR__ . '/../../../../web/upload/'; } /** * @ORM\PrePersist() * @ORM\PreUpdate() */ public function uploadImage() { // the file property can be empty if the field is not required if (null === $this->image) { return; } if(!$this->id){ $this->image->move($this->getTmpUploadRootDir(), $this->image->getClientOriginalName()); }else{ $this->image->move($this->getUploadRootDir(), $this->image->getClientOriginalName()); } $this->setImage($this->image->getClientOriginalName()); } /** * @ORM\PostPersist() */ public function moveImage() { if (null === $this->image) { return; } if(!is_dir($this->getUploadRootDir())){ mkdir($this->getUploadRootDir()); } copy($this->getTmpUploadRootDir().$this->image, $this->getFullImagePath()); unlink($this->getTmpUploadRootDir().$this->image); } /** * @ORM\PreRemove() */ public function removeImage() { unlink($this->getFullImagePath()); rmdir($this->getUploadRootDir()); }