title: Updating a user profile with an uploaded image in Symfony2
body: <p>I have a user profile that allows a user to upload and save a profile picture.</p>
  
  <p>I have a UserProfile entity and a Document entity:</p>
  
  <p><strong>Entity/UserProfile.php</strong>
      
  
  <pre><code>namespace Acme\AppBundle\Entity\Profile;
  use Doctrine\ORM\Mapping as ORM;
  
  /**
   * @ORM\Entity
   * @ORM\Table(name="ISUserProfile")
   */
  class UserProfile extends GenericProfile
  {
  
      /**
       * @ORM\OneToOne(cascade={"persist", "remove"}, targetEntity="Acme\AppBundle\Entity\Document")
       * @ORM\JoinColumn(name="picture_id", referencedColumnName="id", onDelete="set null")
       */
      protected $picture;
  
      /**
       * Set picture
       *
       * @param Acme\AppBundle\Entity\Document $picture
       */
      public function setPicture($picture)
      {
          $this-&gt;picture = $picture;
      }
  
      /**
       * Get picture
       *
       * @return Acme\AppBundle\Entity\Document
       */
      public function getPicture()
      {
          return $this-&gt;picture;
      }
  }
  </code></pre>
  
  <p><strong>Entity/Document.php</strong>
      
  
  <pre><code>namespace Acme\AppBundle\Entity;
  
  use Doctrine\ORM\Mapping as ORM;
  use Symfony\Component\HttpFoundation\File\UploadedFile;
  use Symfony\Component\Validator\Constraints as Assert;
  
  /**
   * @ORM\Entity
   * @ORM\HasLifecycleCallbacks
   */
  class Document
  {
  
      /**
       * @ORM\Id
       * @ORM\Column(type="integer")
       * @ORM\GeneratedValue(strategy="AUTO")
       */
      private $id;
  
      /**
       * @ORM\Column(type="string", length=255, nullable=true)
       */
      private $path;
  
      /**
       * @Assert\File(maxSize="6000000")
       */
      private $file;
  
  
      public function getAbsolutePath()
      {
          return null === $this-&gt;path ? null : $this-&gt;getUploadRootDir().'/'.$this-&gt;path;
      }
  
      public function getWebPath()
      {
          return null === $this-&gt;path ? null : $this-&gt;getUploadDir().'/'.$this-&gt;path;
      }
  
      protected function getUploadRootDir()
      {
          // the absolute directory path where uploaded documents should be saved
          return __DIR__.'/../../../../web/'.$this-&gt;getUploadDir();
      }
  
      protected function getUploadDir()
      {
          // get rid of the __DIR__ so it doesn't screw when displaying uploaded doc/image in the view.
          return 'uploads/documents';
      }
  
      /**
       * @ORM\PrePersist()
       * @ORM\PreUpdate()
       */
      public function preUpload()
      {
          if (null !== $this-&gt;file) {
              $this-&gt;path = sha1(uniqid(mt_rand(), true)).'.'.$this-&gt;file-&gt;guessExtension();
          }
      }
  
      /**
       * @ORM\PostPersist()
       * @ORM\PostUpdate()
       */
      public function upload()
      {
          if (null === $this-&gt;file) {
              return;
          }
  
          $this-&gt;file-&gt;move($this-&gt;getUploadRootDir(), $this-&gt;path);
  
          unset($this-&gt;file);
      }
  
      /**
       * @ORM\PostRemove()
       */
      public function removeUpload()
      {
          if ($file = $this-&gt;getAbsolutePath()) {
              unlink($file);
          }
      }
  
      /**
       * Get id
       *
       * @return integer
       */
      public function getId()
      {
          return $this-&gt;id;
      }
  
      /**
       * Set path
       *
       * @param string $path
       */
      public function setPath($path)
      {
          $this-&gt;path = $path;
      }
  
      /**
       * Get path
       *
       * @return string
       */
      public function getPath()
      {
          return $this-&gt;path;
      }
  
      /**
       * Set file
       *
       * @param string $file
       */
      public function setFile($file)
      {
          $this-&gt;file = $file;
      }
  
      /**
       * Get file
       *
       * @return string
       */
      public function getFile()
      {
          return $this-&gt;file;
      }
  
  }
  </code></pre>
  
  <p>My user profile form type adds a document form type to include the file uploader on the user profile page:</p>
  
  <p><strong>Form/UserProfileType.php</strong>
      
  
  <pre><code>namespace Acme\AppBundle\Form;
  
  use Symfony\Component\Form\FormBuilderInterface;
  use Symfony\Component\OptionsResolver\OptionsResolverInterface;
  
  class UserProfileType extends GeneralContactType
  {
      public function buildForm(FormBuilderInterface $builder, array $options)
      {
      parent::buildForm($builder, $options);
      /*
      if(!($pic=$builder-&gt;getData()-&gt;getPicture()) || $pic-&gt;getWebPath()==''){
        $builder-&gt;add('picture', new DocumentType());
      }
      */
  
      $builder
        -&gt;add('picture', new DocumentType());
        //and add some other stuff like name, phone number, etc
      }
  
      public function setDefaultOptions(OptionsResolverInterface $resolver)
      {
          $resolver-&gt;setDefaults(array(
        'data_class' =&gt; 'Acme\AppBundle\Entity\Profile\UserProfile',
        'intention'  =&gt; 'user_picture',
        'cascade_validation' =&gt; true,
          ));
      }
  
  
      public function getName()
      {
          return 'user_profile_form';
      }
  }
  </code></pre>
  
  <p><strong>Form/DocumentType.php</strong>
      
  
  <pre><code>namespace Acme\AppBundle\Form;
  
  use Symfony\Component\Form\AbstractType;
  use Symfony\Component\Form\FormBuilderInterface;
  use Symfony\Component\OptionsResolver\OptionsResolverInterface;
  
  class DocumentType extends AbstractType
  {
          public function buildForm(FormBuilderInterface $builder, array $options)
          {
                  $builder
                          -&gt;add('file')
                          ;
          }
  
          public function setDefaultOptions(OptionsResolverInterface $resolver)
          {
              $resolver-&gt;setDefaults(array(
                      'data_class' =&gt; 'Acme\AppBundle\Entity\Document',
              ));
          }
  
          public function getName()
          {
                  return 'document_form';
          }
  }
  </code></pre>
  
  <p>In my controller I have an update profile action:</p>
  
  <p><strong>Controller/ProfileController.php</strong>
      
  
  <pre><code>namespace Acme\AppBundle\Controller;
  
  
  class AccountManagementController extends BaseController
  {
  
      /**
       * @param Symfony\Component\HttpFoundation\Request
       * @return Symfony\Component\HttpFoundation\Response
       */
      public function userProfileAction(Request $request) {
          $user = $this-&gt;getCurrentUser();
          $entityManager = $this-&gt;getDoctrine()-&gt;getEntityManager();
  
          if($user &amp;&amp; !($userProfile = $user-&gt;getUserProfile())){
              $userProfile = new UserProfile();
              $userProfile-&gt;setUser($user);
          }
  
          $uploadedFile = $request-&gt;files-&gt;get('user_profile_form');
          if ($uploadedFile['picture']['file'] != NULL) {
                  $userProfile-&gt;setPicture(NULL);
          }
  
          $userProfileForm = $this-&gt;createForm(new UserProfileType(), $userProfile);
  
          if ($request-&gt;getMethod() == 'POST') {
            $userProfileForm-&gt;bindRequest($request);
  
            if ($userProfileForm-&gt;isValid()) {
              $entityManager-&gt;persist($userProfile);
              $entityManager-&gt;flush();
  
              $this-&gt;get('session')-&gt;setFlash('notice', 'Your user profile was successfully updated.');
              return $this-&gt;redirect($this-&gt;get('router')-&gt;generate($request-&gt;get('_route')));
            } else {
              $this-&gt;get('session')-&gt;setFlash('error', 'There was an error while updating your user profile.');
            }
          }
  
          $bindings = array(
            'user_profile_form' =&gt; $userProfileForm-&gt;createView(),
          );
  
          return $this-&gt;render('user-profile-template.html.twig', $bindings);
      }
  }
  </code></pre>
  
  <p>Now, this code works... but it's ugly as hell.  why do I have to check the request object for an uploaded file and set the picture to null so Symfony realises that it needs to persist a new Document entity?</p>
  
  <p>Surely having a simple user profile page with the option to upload an image as a profile picture should be simpler than this?</p>
  
  <p><em>What am I missing??</em></p>