Search code examples
symfonydoctrinesonata

Error uploading file using Sonata Admin and Doctirne


I'm following the guides about handling doctrine upload and sonata admin.
I set up my entity with only id, path and the file (image) :

use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\HttpFoundation\File\UploadedFile;

/**
 * @ORM\Entity
 * @ORM\Table(name="viaggio_perfetto")
*/
class ViaggioPerfetto
{
    private $temp;

    /**
    * @ORM\Column(type="integer")
    * @ORM\GeneratedValue(strategy="AUTO")
    * @ORM\Id
    */
    protected $id;


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

    /**
     * @Assert\File(maxSize="6000000")
     */
    protected $file;

    /**
     * Get file.
     *
     * @return UploadedFile
     */
    public function getFile()
    {
        return $this->file;
    }

    /**
     * Sets file.
     *
     * @param UploadedFile $file
     */
    public function setFile(UploadedFile $file = null)
    {
        $this->file = $file;
        // check if we have an old image path
        if (isset($this->path)) {
            // store the old name to delete after the update
            $this->temp = $this->path;
            $this->path = null;
        } else {
            $this->path = 'initial';
        }
    }

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

    /**
     * @ORM\PostPersist()
     * @ORM\PostUpdate()
     */
    public function upload()
    {
        if (null === $this->getFile()) {
            return;
        }

        // if there is an error when moving the file, an exception will
        // be automatically thrown by move(). This will properly prevent
        // the entity from being persisted to the database on error
        $this->getFile()->move($this->getUploadRootDir(), $this->path);

        // check if we have an old image
        if (isset($this->temp)) {
            // delete the old image
            unlink($this->getUploadRootDir().'/'.$this->temp);
            // clear the temp image path
            $this->temp = null;
        }
        $this->file = null;
    }

    /**
     * @ORM\PostRemove()
     */
    public function removeUpload()
    {
        $file = $this->getAbsolutePath();
        if ($file) {
            unlink($file);
        }
    }

    public function getAbsolutePath()
    {
        return null === $this->path
            ? null
            : $this->getUploadRootDir().'/'.$this->path;
    }

    public function getWebPath()
    {
        return null === $this->path
            ? null
            : $this->getUploadDir().'/'.$this->path;
    }

    protected function getUploadRootDir()
    {
        // the absolute directory path where uploaded
        // documents should be saved
        return __DIR__.'/../../../../web/'.$this->getUploadDir();
    }

    protected function getUploadDir()
    {
        // get rid of the __DIR__ so it doesn't screw up
        // when displaying uploaded doc/image in the view.
        return 'uploads/documents';
    }

    /**
     * Get id
     *
     * @return integer
     */
    public function getId()
    {
        return $this->id;
    }


    /**
     * Set path
     *
     * @param string $path
     *
     * @return ViaggioPerfetto
     */
    public function setPath($path)
    {
        $this->path = $path;

        return $this;
    }

    /**
     * Get path
     *
     * @return string
     */
    public function getPath()
    {
        return $this->path;
    }
}

I remove some filed for better reading the entity.
For this entity i followed the symfony cookbook.
The folder under web/uploads have 777 permission.

Then i add to the sonata admin :

protected function configureFormFields(FormMapper $formMapper)
{
    $formMapper->add('title', 'text');
    $formMapper->add('text', 'text');
    $formMapper->add('startDate', 'date');
    $formMapper->add('endDate', 'date');
    $formMapper->add('active', 'checkbox', array('required' => false));
    $formMapper->add('file', 'file');
}

protected function configureDatagridFilters(DatagridMapper $datagridMapper)
{
    $datagridMapper->add('text');
}

protected function configureListFields(ListMapper $listMapper)
{
    $listMapper->addIdentifier('title');
    $listMapper->add('text');
}

Now i log in sonata admin page and try to create new entity.
All works right i have in my db all field right except the file.
No file under web/uploads/documents and no path in path's filed in database (i have 'initial' that i set in SetFile function if path is not set).

I don't know where i'm wrong. Thanks for your help.


Solution

  • The problem is that you never call the upload method of your entity.

    Add the following methods to your admin class (sonata) :

    /**
     * Handles file upload on create.
     *
     * @param object $created The newly created entity
     */
    public function prePersist($created)
    {
        $created->upload();
    }
    
    /**
     * Handles file upload on update.
     *
     * @param object $updated The updated entity
     */
    public function preUpdate($updated)
    {
        $updated->upload();
    }
    

    And it should works.

    This will call the upload method of your entity before persist/update it.

    See the corresponding part of the Sonata File upload recipe.