Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Remove/update cached image while update/delete record with liipImagineBundle

I am new to symfony2. I am using liipImagineBundle to manage image thumbnail. I have a product entity class which uses Lifecycle Callbacks to manage product image.

Product.php

<?php

namespace Svipl\AdminBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as GEDMO;
use Symfony\Component\HttpFoundation\File\UploadedFile;

/**
 * Svipl\AdminBundle\Entity\Product
 * @ORM\Entity
 * @ORM\Table(name="product")
 * @ORM\Entity(repositoryClass="Svipl\AdminBundle\Entity\ProductRepository")
 * @ORM\HasLifecycleCallbacks
 */
class Product{
    /**
     * @ORM\Column(type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @ORM\Column(type="string", length=25, unique=true)
     */
    private $name;

    /**
     * @ORM\Column(type="text")
     */
    private $description;

    /**
     * @ORM\Column(type="float", length=8)
     * @var unknown
     */
    private $price;

    /**
     * @GEDMO\Timestampable(on="update")
     * @ORM\Column(name="updated_at", type="datetime")
     */
    private $updated_at;

    /**
     * @GEDMO\Timestampable(on="create")
     * @ORM\Column(name="created_at", type="datetime")
     */
    private $created_at;

    /**
     * @ORM\ManyToOne(targetEntity="Category", inversedBy="products")
     * @ORM\JoinColumn(name="category_id", referencedColumnName="id")
     */
    protected $category;

    /**
     * @ORM\Column(name="image", type="string", length=50)
     */
    private $image;

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

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

    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/product';
    }

    private $file;

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

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

    /**
     * Set name
     *
     * @param string $name
     * @return Product
     */
    public function setName($name)
    {
        $this->name = $name;

        return $this;
    }

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

    /**
     * Set description
     *
     * @param string $description
     * @return Product
     */
    public function setDescription($description)
    {
        $this->description = $description;

        return $this;
    }

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

    /**
     * Set price
     *
     * @param float $price
     * @return Product
     */
    public function setPrice($price)
    {
        $this->price = $price;

        return $this;
    }

    /**
     * Get price
     *
     * @return float 
     */
    public function getPrice()
    {
        return $this->price;
    }

    /**
     * Set updated_at
     *
     * @param \DateTime $updatedAt
     * @return Product
     */
    public function setUpdatedAt($updatedAt)
    {
        $this->updated_at = $updatedAt;

        return $this;
    }

    /**
     * Get updated_at
     *
     * @return \DateTime 
     */
    public function getUpdatedAt()
    {
        return $this->updated_at;
    }

    /**
     * Set created_at
     *
     * @param \DateTime $createdAt
     * @return Product
     */
    public function setCreatedAt($createdAt)
    {
        $this->created_at = $createdAt;

        return $this;
    }

    /**
     * Get created_at
     *
     * @return \DateTime 
     */
    public function getCreatedAt()
    {
        return $this->created_at;
    }

    /**
     * Set category
     *
     * @param \Svipl\AdminBundle\Entity\Category $category
     * @return Product
     */
    public function setCategory(\Svipl\AdminBundle\Entity\Category $category = null)
    {
        $this->category = $category;

        return $this;
    }

    /**
     * Get category
     *
     * @return \Svipl\AdminBundle\Entity\Category 
     */
    public function getCategory()
    {
        return $this->category;
    }

    /**
     * Set image
     *
     * @param string $image
     * @return Product
     */
    public function setImage($image)
    {
        $this->image = $image;

        return $this;
    }

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

    private $temp;

    /**
     * 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->image)) {
            // store the old name to delete after the update
            $this->temp = $this->image;
            $this->image = null;
        } else {
            $this->image = '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->image = $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->image);

        // 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()
    {
        if ($file = $this->getAbsolutePath()) {
            unlink($file);
        }
    }
}

config.yml

...
liip_imagine:
    filter_sets:
        my_thumb:
            quality: 75
            filters:
                thumbnail: { size: [120, 90], mode: outbound }

Thumbnail generation code

...

<img src="{{ asset('uploads/product/' ~ form_object.vars.value.image) | imagine_filter('my_thumb', true) }}" />

...

Thumbnail generating correctly.

But I am not able to find the way to update/remove cached image while original image change or delete with form.

like image 915
Hardeep Pandya Avatar asked Sep 25 '13 06:09

Hardeep Pandya


4 Answers

You should register a preUpdate and a preRemove event listener/subscriber, inject the service needed and delete the images in there.

As you don't have access to the service container ( and you should not inject services into your entities ) you can't query LiipImagineBundle's services to obtain the cached files from inside your entity using Lifecycle Events.

You can inject the service liip_imagine.cache.manager and use it's remove() method to delete an image from cache.

like image 179
Nicolai Fröhlich Avatar answered Nov 19 '22 17:11

Nicolai Fröhlich


You have to create a Listener Entity and create a service. The service will call this Entity each event you want : here in the PostUpdate and the preRemove of your Product.

In the Entity Listener you have a method for each event you have set, and you just have to clear the cache on each method or do anything else you want.

Here an example comes from this post

Service

services:
    project.cacheimage_listener:
        class: Acme\Listener\CacheImageListener
        arguments: ["@liip_imagine.cache.manager"]
        tags:
            - { name: doctrine.event_listener, event: postUpdate }
            - { name: doctrine.event_listener, event: preRemove }

Entity Listener

<?php
namespace Acme\Listener;

use Doctrine\ORM\Event\LifecycleEventArgs;
use Acme\Entity\Image;

class CacheImageListener
{
    protected $cacheManager;

    public function __construct($cacheManager)
    {
        $this->cacheManager = $cacheManager;
    }

    public function postUpdate(LifecycleEventArgs $args)
    {
        $entity = $args->getEntity();

        if ($entity instanceof Image) {
// clear cache of thumbnail
            $this->cacheManager->remove($entity->getUploadDir());
        }
    }

// when delete entity so remove all thumbnails related
    public function preRemove(LifecycleEventArgs $args)
    {
        $entity = $args->getEntity();

        if ($entity instanceof Image) {

            $this->cacheManager->remove($entity->getWebPath());
        }
    }
}

This solution works fine on my site.

like image 3
Zagonine Avatar answered Nov 19 '22 17:11

Zagonine


Don't forget to call resolve() method of liip_imagine.cache.manager. Otherwise, it won't remove your cached image.

as described here: https://github.com/liip/LiipImagineBundle/issues/132

$cacheManager = $this->get('liip_imagine.cache.manager');
$cacheManager->resolve($this->getRequest(), $pngPath, $filter);
$cacheManager->remove($pngPath, $filter);
like image 2
Serhii Smirnov Avatar answered Nov 19 '22 17:11

Serhii Smirnov


I know this question is a bit old, but in case someone looks for some code (I'm using SF 2.3). I had this requirement for file removal. in my project I'm using VichUploaderBundle to handle file uploads and LiipImagineBundle to handle thumbnail generation for those images. When the entity is removed, uploaded file should be removed as well as the thumbnail (if any was generated). I've implemented a doctrine listener, the preRemove method is as follow:

public function preRemove(LifecycleEventArgs $args)
{
    $filter = 'thumbnail'; //the filter that imagine bundle uses
    $fileEntity = $args->getEntity();
    if($fileEntity instanceof FileEntity)
    {
        //get the path to the uploaded file, relative to the web url
        $sourcePath = $this->uploaderStorage->resolveUri($fileEntity, "file");    

        $this->liipCacheManager->remove($sourcePath, $filter);
    }
}
like image 2
james_bond Avatar answered Nov 19 '22 17:11

james_bond