I researched the How to Handle File Uploads with Doctrine and I don't want to hard-code the __DIR__.'/../../../../web/'.$this->getUploadDir();
path because maybe in future I will change the web/
directory. How to do it more flexible? I found this but it doesn't answer the question how to do it more flexible from inside the Entity
4 Answers
You shouldn't use entity class as a form model here. It's simply not suitable for that job. If the entity has the path
property, the only valid values it can stores are: null
(in case lack of the file) and string representing the path to the file.
Create a separate class, that's gonna be a model for your form:
class MyFormModel { /** @Assert\File */ private $file; /** @Assert\Valid */ private $entity; // constructor, getters, setters, other methods }
In your form handler (separate object configured through DIC; recommended) or the controller:
... if ($form->isValid()) { /** @var \Symfony\Component\HttpFoundation\File\UploadedFile */ $file = $form->getData()->getFile(); /** @var \Your\Entity\Class */ $entity = $form->getData()->getEntity(); // move the file // $path = '/path/to/the/moved/file'; $entity->setPath($path); $someEntityManager->persist($entity); return ...; } ...
Inside form handler/controller you can access any dependencies/properties from DIC (including path to the upload directory).
The tutorial you've linked works, but it's an example of bad design. The entities should not be aware of file upload.

- 43,890
- 13
- 88
- 135
-
I understood. Thanks. But how to use a lifecycle callbacks to manage a deletion of the file with your code? – Mikhail Oct 15 '12 at 10:57
-
Based on previous experience I suggest you store absolute path (or at least relative to webroot path) as well.. – Jovan Perovic Oct 15 '12 at 11:05
-
Create a listener, that subscribes `preRemove` (or `preDelete`) event (see [how to](http://symfony.com/doc/current/cookbook/doctrine/event_listeners_subscribers.html)) and unlink the file there. – Crozin Oct 15 '12 at 11:13
To access the root directory from outside the controller you can simply inject '%kernel.root_dir%' as an argument in your services configuration.
service_name:
class: Namespace\Bundle\etc
arguments: ['%kernel.root_dir%']
Then you can get the web root in the class constructor:
public function __construct($rootDir)
{
$this->webRoot = realpath($rootDir . '/../web');
}

- 1,016
- 9
- 11
You can use a variable in your parameters.yml. Like this you'll can change path when you want.
for example :
# app/config/parameters.yml
# Upload directories
upload_avatar_dir: /uploads/avatars
upload_content_dir: /uploads/content
upload_product_offer_dir: /uploads/product-offer
...

- 2,950
- 1
- 20
- 27
-
-
It's not the responsibility of your entity to know where the document is store. Yo can move this responsibility to your controller. Or you can add a path attribute to your entity – Benjamin Lazarecki Oct 16 '12 at 08:39
I handled this by creating an abstract class that Entities may extend if they are handling file uploads as described in the Symfony Documentation. I created the files array so I could create a copy of the existing file path in the set methods so it could be deleted off the file system on a successful update or delete without defining any additional properties in the Entity proper.
use Symfony\Component\HttpFoundation\File\File;
abstract class FileUploadEntity
{
private $files;
public function __set($name, File $value)
{
$this->files[$name] = $value;
}
public function __get($name)
{
if (!is_array($this->files)) $this->files = array();
if (!array_key_exists($name, $this->files)) {
return null;
}
return $this->files[$name];
}
public function getUploadRootDirectory()
{
return $this->getWebDirectory() . $this->getUploadDirectory();
}
public function getWebDirectory()
{
return __DIR__ . "/../../../../web/";
}
public function getUploadDirectory()
{
$year = date("Y");
$month= date("m");
return "images/uploads/$year/$month/";
}
public function getEncodedFilename($name)
{
return sha1($name . uniqid(mt_rand(), true));
}
// this should be a PrePersist method
abstract public function processImages();
// This should be defined as a Doctrine PreUpdate Method
abstract public function checkImages();
// this should be a PostPersist method
abstract public function upload();
// this should be a PostUpdate method and delete old files
abstract public function checkUpload();
// This should be a PostRemove method and delete files
abstract public function deleteFile();
}

- 52
- 2
-
1Hm, I see that you used the `__DIR__ . "/../../../../web/"` too, but my question is how to avoid it. – Mikhail Sep 02 '13 at 13:04
-
I'm not sure there is one. It seemed like the best i could do was define it in one place. – Tom Phillips Sep 18 '13 at 21:30