Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Delete unused images #2

Open
comur opened this issue Feb 13, 2014 · 8 comments
Open

Delete unused images #2

comur opened this issue Feb 13, 2014 · 8 comments

Comments

@comur
Copy link
Owner

comur commented Feb 13, 2014

Have to find a way to delete images when they are not used anymore.

2 possibilities:

  1. Add a listener on preUpdate and remove old images
  2. Add a trigger on image change in the widget and call an ajax route to delete old images

Any way, we have to create a service to get all image types (cropped, thumbs) related to an image.

@Tersoal
Copy link

Tersoal commented Feb 28, 2015

Hi.

It's needed this. I'm detecting some issues:

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 :-(

@comur
Copy link
Owner Author

comur commented Mar 2, 2015

Hi @Tersoal

I have some thoughts about this issue.

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.

Tell me if you are able to achieve that.

@Tersoal
Copy link

Tersoal commented Mar 2, 2015

Thanks!

Let me see...

@Tersoal
Copy link

Tersoal commented Mar 5, 2015

Well, it does not work.

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.

@comur
Copy link
Owner Author

comur commented Mar 6, 2015

Send me your code and i will show you how to do it. I have to include a real example in the project

@Tersoal
Copy link

Tersoal commented Mar 6, 2015

I'll put here. Is up to you how include it in the docs.

I see other problems that I have to confirm in my tests.

@Tersoal
Copy link

Tersoal commented Mar 7, 2015

Hi.

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.

  1. 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).

  2. Create service definition:

    acme.subscriber.hello:
    class: Acme\HelloBundle\Service\HelloSubscriber
    tags:
    - {name: doctrine.event_subscriber }
    arguments: [%comur_image.cropped_image_dir%, %comur_image.thumbs_dir%, "@service_container", %comur_image.web_dirname%, %comur_image.gallery_dir%]

  3. 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.

@comur
Copy link
Owner Author

comur commented Mar 9, 2015

Hi,

Thanks for this great job, I will take some time to check it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants