FriendsOfCake / cakephp-upload

CakePHP: Handle file uploading sans ridiculous automagic
https://cakephp-upload.readthedocs.io/
MIT License
551 stars 255 forks source link

Enhancement - Delete file during/after edit #493

Open stosh15x opened 6 years ago

stosh15x commented 6 years ago

Hi I recently noticed an issue that files where not being deleted when I was editing a table. (IE: User changes their profile photo.) I have the plugin uploading the file, updating the database but the old file doesn't get deleted.

Note: I changed the path in the config to:

'path' => 'webroot{DS}img{DS}{model}{DS}{field}{DS}'

So here is my temporary solution in the model but I imagine there is a better way to accomplish this.

use Cake\Filesystem\File;
use Cake\Event\Event;
use Cake\ORM\Entity;
use ArrayObject;

// clean up default leaderboard image change
public function afterSave(Event $event, Entity $entity, ArrayObject $options) {
  $field = 'image';

  $original = $entity->getOriginal($field);
  if($entity->{$field} != $original && $original != null) {
    $path = ROOT . DS . $entity->image_dir . $original;
    $file = new File($path);
    if($file->exists()) {
       $file->delete();
    }
    $file->close();
  }
}
b0n commented 5 years ago

I also write afterSave method with almost afterDelete code at Upload.Upload behavior.


    /**
     * Deletes the original files after the entity is saved
     *
     * @param Event $event
     * @param Entity $entity
     * @param ArrayObject $options
     * @return bool
     */
    public function afterSave(Event $event, Entity $entity, ArrayObject $options)
    {
        $result = true;

        $behavior = $this->getBehavior('Upload');

        foreach ($behavior->getConfig(null, []) as $field => $settings) {
            if ($entity->isNew()) {
                continue;
            }

            if (!$entity->isDirty($field)) {
                continue;
            }

            if (Hash::get($settings, 'keepFilesOnDelete', true)) {
                continue;
            }

            $dirField = Hash::get($settings, 'fields.dir', 'dir');
            if ($entity->has($dirField)) {
                $path = $entity->get($dirField);
            } else {
                $path = $behavior->getPathProcessor($entity, $entity->get($field), $field, $settings)->basepath();
            }

            $original_entity = clone $entity;
            $original_entity->{$field} = $entity->getOriginal($field);
            $callback = Hash::get($settings, 'deleteCallback', null);
            if ($callback && is_callable($callback)) {
                $files = $callback($path, $original_entity, $field, $settings);
            } else {
                $files = [$path . $original_entity->get($field)];
            }

            $writer = $behavior->getWriter($entity, [], $field, $settings);
            $success = $writer->delete($files);

            if ($result && (new Collection($success))->contains(false)) {
                $result = false;
            }
        }

        return $result;
    }
general2000vn commented 2 years ago

b0n,

Where should i place your afterSave() method? I tried to place it in my Model which use the Upload behavious, but then it complain that undefine $behavior->getPathProcessor() and $behavior->getWriter .

I checked and see those method are public, but somehow my model can not call them.

Please kindly advice. I am using CakePHP 4.x and Josegonzalez/cakephp-upload 6.0

b0n commented 2 years ago

Hello general!

I use Josegonzalez/cakephp-upload 3.0. Please checkout and try these. pathProcessor https://github.com/FriendsOfCake/cakephp-upload/blob/3.8.1/src/Model/Behavior/UploadBehavior.php#L171 getWriter https://github.com/FriendsOfCake/cakephp-upload/blob/3.8.1/src/Model/Behavior/UploadBehavior.php#L194

And Josegonzalez/cakephp-upload 6.0 has these methods. Please check this out.

https://github.com/FriendsOfCake/cakephp-upload/blob/6.0.0/src/Model/Behavior/UploadBehavior.php