Удалить / обновить кэшированное изображение при обновлении / удалении записи с помощью liipImagineBundle

Я новичок в Symfony2. Я использую liipImagineBundle для управления миниатюрами изображений. У меня есть класс сущности продукта, который использует Lifecycle Callbacks для управления имиджем продукта.

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 }

Код генерации миниатюр

...

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

...

Миниатюра генерируется правильно.

Но я не могу найти способ обновить / удалить кэшированное изображение при изменении или удалении исходного изображения с помощью формы.

4 ответа

Вам необходимо зарегистрировать прослушиватель / подписчик событий preUpdate и preRemove, внедрить необходимый сервис и удалить там изображения.

Поскольку у вас нет доступа к контейнеру сервисов (и вы не должны внедрять сервисы в свои сущности), вы не можете запрашивать службы LiipImagineBundle для получения кэшированных файлов внутри вашей сущности, используя события жизненного цикла.

Вы можете добавить сервис liip_imagine.cache.manager и использовать его метод remove() для удаления изображения из кэша.

Вы должны создать сущность слушателя и создать службу. Служба будет называть эту сущность при каждом желаемом событии: здесь, в PostUpdate и до удаления вашего продукта.

В Entity Listener у вас есть метод для каждого события, которое вы установили, и вам просто нужно очистить кэш каждого метода или сделать что-нибудь еще, что вы хотите.

Вот пример из этого поста

обслуживание

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());
        }
    }
}

Это решение отлично работает на моем сайте.

Не забудьте вызвать метод resol () из liip_imagine.cache.manager. В противном случае он не удалит ваше кэшированное изображение.

как описано здесь: https://github.com/liip/LiipImagineBundle/issues/132

$cacheManager = $this->get('liip_imagine.cache.manager');
$cacheManager->resolve($this->getRequest(), $pngPath, $filter);
$cacheManager->remove($pngPath, $filter);

Я знаю, что этот вопрос немного устарел, но в случае, если кто-то ищет какой-то код (я использую SF 2.3). У меня было это требование для удаления файла. В моем проекте я использую VichUploaderBundle для обработки загрузки файлов и https://github.com/liip/LiipImagineBundle для генерации миниатюр для этих изображений. Когда объект удаляется, загруженный файл должен быть удален вместе с миниатюрой (если она была создана). Я реализовал прослушиватель доктрины, метод preRemove выглядит следующим образом:

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);
    }
}
Другие вопросы по тегам