1.- When I create a new item and I upload a image, automatically the file is upload to "[defined path]" and "[defined path]/thumbnails" folder with a hash. And I have no original image defined in the config.
2.- If I crop the image and continue, the cropped image is uploaded automatically to "[defined path]/cropped" and "[defined path]/cropped/thumbnails" folder with a hash, wich is different to full image hash.
3.- If I flush the new item, all it's ok. The files are there. But in the database I only have the cropped filename with the step 2 hash.
4.- If I cancel the new item, the images have been uploaded anyway.
Then, I can't imagine how to handle the images deletion. My knowledge of symfony is limited, but I'm trying to handle this and I'm frustrated.
I hope you will deal with this soon. I don't know how to resolve it :-(
First, you can save original file name in another field if you want to delete it when your entity is removed (be careful, you will no longer see this image in "already uploaded" images selection). To do this, you can pass a parameter to your field : https://github.com/comur/ComurImageBundle#saveoriginal-optional
Then in your entity you need to use http://doctrine-orm.readthedocs.org/en/latest/reference/events.html#preremove function to delete images uploaded / cropped by this entity.
I have defined my image field with 'saveOriginal' => false (or you can delete this as it's by default). The image file is upload by ajax to the server anyway, just when the image is selected to upload.
Preremove lyfecycle callback does not work because the defined field isn't a file, but string instead.
I'm updating my form, entity and controller to delete files. I'll put here, and it should be included in the doc for reference to new users.
I have resolved the old image files deletion with a service. The problem is that it must be done for all entities that have a comur image field, and I have tried to do in the bundle, but I don't know how identify the image fields in classmetada. My knowledge of symfony is not sufficient.
Entity and form field: as doc says, but originalImage is mandatory for deleting uploaded image (I don't know why does occur it if I set the originalimage to false).
Create service: all reference to tempNewOriginalImage must be commented if you don't want to delete the original image.
tempImage = null;
$this->tempOriginalImage = null;
$this->tempNewOriginalImage = null;
```
$this->croppedDir = $croppedDir;
$this->thumbsDir = $thumbsDir;
$this->webDir = $container->get('kernel')->getRootdir().'/../' . $webDirName;
$this->galleryDir = $galleryDir;
```
}
public function getSubscribedEvents()
{
return array(
'prePersist',
'postPersist',
'preUpdate',
'postUpdate',
);
}
public function prePersist(LifeCycleEventArgs $args)
{
$entity = $args->getObject();
```
if ($entity instanceof Hello) {
$this->tempNewOriginalImage = $entity->getOriginalImage();
$entity->setOriginalImage(null);
}
```
}
public function postPersist(LifeCycleEventArgs $args)
{
if (null === $this->tempNewOriginalImage) {
return;
}
```
$entity = $args->getObject();
$this->removeNewOriginalImage($entity);
```
}
public function preUpdate(LifeCycleEventArgs $args)
{
$entity = $args->getObject();
```
if ($entity instanceof Hello) {
if ($args->hasChangedField('image')) {
$this->tempImage = $args->getOldValue('image');
$this->tempOriginalImage = $args->getOldValue('originalImage');
$this->tempNewOriginalImage = $args->getNewValue('originalImage');
$entity->setOriginalImage(null);
}
}
```
}
public function postUpdate(LifeCycleEventArgs $args)
{
if (null === $this->tempImage &&
null === $this->tempOriginalImage &&
null === $this->tempNewOriginalImage) {
return;
}
```
$entity = $args->getObject();
if (null !== $this->tempImage) {
$imageName = explode('/', $this->tempImage);
$imageName = end($imageName);
// Delete cropped image
$this->removeFile($this->webDir.'/'.$entity->getUploadDir().'/'.$this->croppedDir.'/'.$imageName);
// Delete cropped image thumbnail
$croppedImageNames = glob($this->webDir.'/'.$entity->getUploadDir().'/'.$this->croppedDir.'/'.$this->thumbsDir.'/*' . $imageName);
foreach ($croppedImageNames as $croppedImageName) {
unlink($croppedImageName);
}
$this->tempImage = null;
}
if (null !== $this->tempOriginalImage) {
$this->removeNewOriginalImage($entity);
}
if (null !== $this->tempNewOriginalImage) {
$this->removeNewOriginalImage($entity);
}
```
}
public function removeOriginalImage($entity)
{
// Delete new original image and it's thumbnail
$this->removeFile($this->webDir.'/'.$entity->getUploadDir().'/'.$this->tempOriginalImage);
$this->removeFile($this->webDir.'/'.$entity->getUploadDir().'/'.$this->thumbsDir.'/'.$this->tempOriginalImage);
```
$this->tempOriginalImage = null;
```
}
public function removeNewOriginalImage($entity)
{
// Delete new original image and it's thumbnail
$this->removeFile($this->webDir.'/'.$entity->getUploadDir().'/'.$this->tempNewOriginalImage);
$this->removeFile($this->webDir.'/'.$entity->getUploadDir().'/'.$this->thumbsDir.'/'.$this->tempNewOriginalImage);
```
$this->tempNewOriginalImage = null;
```
}
public function removeFile($file)
{
if (file_exists($file)) {
unlink($file);
}
}
}
TO-DO:
- If I cancel new or edit entity, the images are uploaded and the can't be deleted. It's possible to create a synchronous ajax call in window.beforeunload event, but it can cause problems in the browser if server don't respond for whatever reason. As well, I've a script copied from Sonata admin, wich allows to the user cancel redirection if form has been modified. Thus, the ajax call must not be done if the user cancels the action, and it's not possible with other beforeunload action in the comur bundle. Same occurs in the unload event.
- I will create a cron job to delete uploaded images periodically. It's the only solution that comes to my mind.