Symfony 4 - LiipImagine - 侦听器删除我的所有目录(缓存清除侦听器)
Symfony 4 - LiipImagine - Listener delete all my directory (cache clear listener)
我有一个 symfony 4 项目,其中的用户实体与头像实体(使用 VichUploaderBundle 上传的图像)有关系。
在Avatar.php中:
/**
* @ORM\Column(type="string", length=255, nullable=true)
*/
private $imageName;
/**
* NOTE: This is not a mapped field of entity metadata, just a simple property.
*
* @Assert\Image(
* mimeTypes="image/jpeg")
* @Vich\UploadableField(mapping="avatar", fileNameProperty="imageName", size="imageSize")
*
* @var File|null
*/
private $imageFile;
在User.php中:
/**
* @ORM\OneToOne(targetEntity="App\Entity\Avatar", mappedBy="user", cascade={"persist", "remove"})
*/
private $avatar;
我有一个个人资料页面来编辑用户的数据(名字、姓氏、邮件、头像)。
在这个页面中,我使用LiipImagineBundle在某个维度显示当前头像。
当用户编辑他的个人资料时,我希望听众可以检查头像是否有变化。在这种情况下,它会删除旧媒体/缓存。
所以我为此创建了一个监听器:
<?php
namespace App\Listener;
use App\Entity\Avatar;
use Doctrine\Common\EventSubscriber;
use Doctrine\ORM\Event\LifecycleEventArgs;
use Doctrine\ORM\Event\PreUpdateEventArgs;
use Liip\ImagineBundle\Imagine\Cache\CacheManager;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Vich\UploaderBundle\Templating\Helper\UploaderHelper;
class ImageCacheSubscriber implements EventSubscriber
{
/**
* CacheManager
*
* @var CacheManager
*/
private $cacheManager;
/**
* UploaderHelper
*
* @var UploaderHelper
*/
private $uploaderHelper;
public function __construct(CacheManager $cacheManager, UploaderHelper $uploaderHelper)
{
$this->cacheManager = $cacheManager;
$this->uploaderHelper = $uploaderHelper;
}
public function getSubscribedEvents()
{
return [
'preRemove',
'preUpdate'
];
}
public function preRemove(LifecycleEventArgs $args)
{
$entity = $args->getEntity();
if (!$entity instanceof Avatar) {
return;
}
$this->cacheManager->remove($this->uploaderHelper->asset($entity, 'imageFile'));
}
public function preUpdate(PreUpdateEventArgs $args)
{
dump($args->getEntity());
dump($args->getObject());
$entity = $args->getEntity();
if (!$entity instanceof Avatar) {
return;
}
if ($entity->getImageFile() instanceof UploadedFile) {
$this->cacheManager->remove($this->uploaderHelper->asset($entity, 'imageFile'));
}
}
}
Services.yaml:
App\Listener\ImageCacheSubscriber:
tags:
- { name: doctrine.event_subscriber }
但是当我更改头像时,侦听器会删除媒体中包含头像的整个文件夹。
他让我犯了这个错误:
Failed to remove directory
"C:\Users\user\Desktop\congesTest2/public/media/cache/avatar_big\files":
rmdir(C:\Users\user\Desktop\congesTest2/public/media/cache/avatar_big\files):
Directory not empty.
我不明白为什么...:'(
编辑:
我将函数 preUpdate() 更新为 postUpdate() :
public function getSubscribedEvents()
{
return [
'preRemove',
'postUpdate'
];
}
public function postUpdate(LifecycleEventArgs $args)
{
dump($args->getEntity());
$entity = $args->getEntity();
if (!$entity instanceof Avatar) {
return;
}
if ($entity->getImageFile() instanceof UploadedFile) {
$this->cacheManager->remove($this->uploaderHelper->asset($entity, 'imageFile'));
}
}
现在,如果我转储:
dd($this->uploaderHelper->asset($entity, 'imageFile'));
我已经:
"/images/avatar/avatar3.jpg"
And this is the good path ! On the other hand, the image is not removed from the cache! The remove () function does not seem to give anything it's amazing
通过实体的转储,我看到该文件不再是一个 UploadedFile,而是一个简单的文件。而之前它看起来像一个 UploadedFile。所以我改变了行
if ($entity->getImageFile() instanceof UploadedFile)
来自
if ($entity->getImageFile() instanceof File)
但图片仍未从缓存中删除。
在我看来,由于这是一个 postUpdate,它会删除新的缓存图像,而不是旧的。但由于用户被重定向到同一页面,他在缓存后立即交付。 (编辑:不,我做了测试,图像甚至没有从缓存中删除)
当您使用 VichUploaderBundle 时,不需要创建您自己的侦听器。确保生命周期事件配置正确,Vich 应该负责删除旧图像。
# config/packages/vich_uploader.yaml or app/config/config.yml
vich_uploader:
db_driver: orm
mappings:
product_image:
uri_prefix: /images/products
upload_destination: '%kernel.project_dir%/public/images/products'
inject_on_load: false
delete_on_update: true
delete_on_remove: true
您可以监听 vich_uploader.pre_remove
事件,而不是监听 Doctrine 事件。这将确保您每次都能获得需要删除的旧图像。首先,确保您的 VichUploader 配置设置为在更新和删除时删除文件。这是默认值。
# config/packages/vich_uploader.yaml
vich_uploader:
mappings:
avatar:
upload_destination: '%kernel.project_dir%/public/uploads/avatar'
uri_prefix: 'uploads/avatar'
delete_on_update: true
delete_on_remove: true
现在您需要创建侦听器。
// src/EventListener/ImageCacheSubscriber.php
namespace App\EventListener;
use Liip\ImagineBundle\Imagine\Cache\CacheManager;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Vich\UploaderBundle\Event\Event;
use Vich\UploaderBundle\Event\Events;
use Vich\UploaderBundle\Storage\StorageInterface;
class ImageCacheSubscriber implements EventSubscriberInterface
{
private $storage;
private $cacheManager;
public function __construct(StorageInterface $storage, CacheManager $cacheManager)
{
$this->storage = $storage;
$this->cacheManager = $cacheManager;
}
public function onRemove(Event $event)
{
$path = $this->storage->resolveUri($event->getObject(), $event->getMapping()->getFilePropertyName());
$this->cacheManager->remove($path);
}
public static function getSubscribedEvents()
{
return [Events::PRE_REMOVE => 'onRemove'];
}
}
当删除任何 VichUploader 资产时,此侦听器将尝试将其从所有过滤器的缓存中删除。如果愿意,您可以在 CacheManager::remove()
方法中指定特定的过滤器。您也可以仅通过检查 $event->getObject()
.
的实例来删除特定实体的缓存
这也对您的 LiipImagine 配置做出了一些假设。如果您使用默认加载程序和缓存解析器,这应该可以工作。如果您使用的是自定义加载器或解析器,您可能需要根据需要修改此侦听器。
# config/packages/liip_imagine.yaml
liip_imagine:
resolvers:
default:
web_path:
web_root: '%kernel.project_dir%/public'
cache_prefix: 'media/cache'
loaders:
default:
filesystem:
data_root:
- '%kernel.project_dir%/public'
filter_sets:
cache: ~
# Your filters...
如果您使用的是 Symfony Flex,那么您就完成了。否则,请确保将侦听器注册为服务。
# config/services.yaml
services:
# ...
App\EventListener\ImageCacheSubscriber:
arguments: ['@vich_uploader.storage.file_system', '@liip_imagine.cache.manager']
tags:
- { name: kernel.event_subscriber }
我有一个 symfony 4 项目,其中的用户实体与头像实体(使用 VichUploaderBundle 上传的图像)有关系。
在Avatar.php中:
/**
* @ORM\Column(type="string", length=255, nullable=true)
*/
private $imageName;
/**
* NOTE: This is not a mapped field of entity metadata, just a simple property.
*
* @Assert\Image(
* mimeTypes="image/jpeg")
* @Vich\UploadableField(mapping="avatar", fileNameProperty="imageName", size="imageSize")
*
* @var File|null
*/
private $imageFile;
在User.php中:
/**
* @ORM\OneToOne(targetEntity="App\Entity\Avatar", mappedBy="user", cascade={"persist", "remove"})
*/
private $avatar;
我有一个个人资料页面来编辑用户的数据(名字、姓氏、邮件、头像)。 在这个页面中,我使用LiipImagineBundle在某个维度显示当前头像。
当用户编辑他的个人资料时,我希望听众可以检查头像是否有变化。在这种情况下,它会删除旧媒体/缓存。
所以我为此创建了一个监听器:
<?php
namespace App\Listener;
use App\Entity\Avatar;
use Doctrine\Common\EventSubscriber;
use Doctrine\ORM\Event\LifecycleEventArgs;
use Doctrine\ORM\Event\PreUpdateEventArgs;
use Liip\ImagineBundle\Imagine\Cache\CacheManager;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Vich\UploaderBundle\Templating\Helper\UploaderHelper;
class ImageCacheSubscriber implements EventSubscriber
{
/**
* CacheManager
*
* @var CacheManager
*/
private $cacheManager;
/**
* UploaderHelper
*
* @var UploaderHelper
*/
private $uploaderHelper;
public function __construct(CacheManager $cacheManager, UploaderHelper $uploaderHelper)
{
$this->cacheManager = $cacheManager;
$this->uploaderHelper = $uploaderHelper;
}
public function getSubscribedEvents()
{
return [
'preRemove',
'preUpdate'
];
}
public function preRemove(LifecycleEventArgs $args)
{
$entity = $args->getEntity();
if (!$entity instanceof Avatar) {
return;
}
$this->cacheManager->remove($this->uploaderHelper->asset($entity, 'imageFile'));
}
public function preUpdate(PreUpdateEventArgs $args)
{
dump($args->getEntity());
dump($args->getObject());
$entity = $args->getEntity();
if (!$entity instanceof Avatar) {
return;
}
if ($entity->getImageFile() instanceof UploadedFile) {
$this->cacheManager->remove($this->uploaderHelper->asset($entity, 'imageFile'));
}
}
}
Services.yaml:
App\Listener\ImageCacheSubscriber:
tags:
- { name: doctrine.event_subscriber }
但是当我更改头像时,侦听器会删除媒体中包含头像的整个文件夹。
他让我犯了这个错误:
Failed to remove directory "C:\Users\user\Desktop\congesTest2/public/media/cache/avatar_big\files": rmdir(C:\Users\user\Desktop\congesTest2/public/media/cache/avatar_big\files): Directory not empty.
我不明白为什么...:'(
编辑:
我将函数 preUpdate() 更新为 postUpdate() :
public function getSubscribedEvents()
{
return [
'preRemove',
'postUpdate'
];
}
public function postUpdate(LifecycleEventArgs $args)
{
dump($args->getEntity());
$entity = $args->getEntity();
if (!$entity instanceof Avatar) {
return;
}
if ($entity->getImageFile() instanceof UploadedFile) {
$this->cacheManager->remove($this->uploaderHelper->asset($entity, 'imageFile'));
}
}
现在,如果我转储:
dd($this->uploaderHelper->asset($entity, 'imageFile'));
我已经:
"/images/avatar/avatar3.jpg" And this is the good path ! On the other hand, the image is not removed from the cache! The remove () function does not seem to give anything it's amazing
通过实体的转储,我看到该文件不再是一个 UploadedFile,而是一个简单的文件。而之前它看起来像一个 UploadedFile。所以我改变了行
if ($entity->getImageFile() instanceof UploadedFile)
来自
if ($entity->getImageFile() instanceof File)
但图片仍未从缓存中删除。
在我看来,由于这是一个 postUpdate,它会删除新的缓存图像,而不是旧的。但由于用户被重定向到同一页面,他在缓存后立即交付。 (编辑:不,我做了测试,图像甚至没有从缓存中删除)
当您使用 VichUploaderBundle 时,不需要创建您自己的侦听器。确保生命周期事件配置正确,Vich 应该负责删除旧图像。
# config/packages/vich_uploader.yaml or app/config/config.yml
vich_uploader:
db_driver: orm
mappings:
product_image:
uri_prefix: /images/products
upload_destination: '%kernel.project_dir%/public/images/products'
inject_on_load: false
delete_on_update: true
delete_on_remove: true
您可以监听 vich_uploader.pre_remove
事件,而不是监听 Doctrine 事件。这将确保您每次都能获得需要删除的旧图像。首先,确保您的 VichUploader 配置设置为在更新和删除时删除文件。这是默认值。
# config/packages/vich_uploader.yaml
vich_uploader:
mappings:
avatar:
upload_destination: '%kernel.project_dir%/public/uploads/avatar'
uri_prefix: 'uploads/avatar'
delete_on_update: true
delete_on_remove: true
现在您需要创建侦听器。
// src/EventListener/ImageCacheSubscriber.php
namespace App\EventListener;
use Liip\ImagineBundle\Imagine\Cache\CacheManager;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Vich\UploaderBundle\Event\Event;
use Vich\UploaderBundle\Event\Events;
use Vich\UploaderBundle\Storage\StorageInterface;
class ImageCacheSubscriber implements EventSubscriberInterface
{
private $storage;
private $cacheManager;
public function __construct(StorageInterface $storage, CacheManager $cacheManager)
{
$this->storage = $storage;
$this->cacheManager = $cacheManager;
}
public function onRemove(Event $event)
{
$path = $this->storage->resolveUri($event->getObject(), $event->getMapping()->getFilePropertyName());
$this->cacheManager->remove($path);
}
public static function getSubscribedEvents()
{
return [Events::PRE_REMOVE => 'onRemove'];
}
}
当删除任何 VichUploader 资产时,此侦听器将尝试将其从所有过滤器的缓存中删除。如果愿意,您可以在 CacheManager::remove()
方法中指定特定的过滤器。您也可以仅通过检查 $event->getObject()
.
这也对您的 LiipImagine 配置做出了一些假设。如果您使用默认加载程序和缓存解析器,这应该可以工作。如果您使用的是自定义加载器或解析器,您可能需要根据需要修改此侦听器。
# config/packages/liip_imagine.yaml
liip_imagine:
resolvers:
default:
web_path:
web_root: '%kernel.project_dir%/public'
cache_prefix: 'media/cache'
loaders:
default:
filesystem:
data_root:
- '%kernel.project_dir%/public'
filter_sets:
cache: ~
# Your filters...
如果您使用的是 Symfony Flex,那么您就完成了。否则,请确保将侦听器注册为服务。
# config/services.yaml
services:
# ...
App\EventListener\ImageCacheSubscriber:
arguments: ['@vich_uploader.storage.file_system', '@liip_imagine.cache.manager']
tags:
- { name: kernel.event_subscriber }