Sylius/Symfony:使用自定义实体上传图片
Sylius/Symfony: Image Upload with custom entity
我正在尝试将 Sylius 的 ImagesUploadListener 用于自定义实体。
在 documentation 中,它说我应该听 "sylius.shipping_method.pre_create" 这样的事件。对于我的自定义实体,没有我可以挂接的事件。
所以我尝试挂钩 product.pre_create 事件并将我的实体作为参数,但似乎图片上传仅在产品实体上触发,我的实体配置被忽略。尽管 ImagesUploadListener 被触发了两次,一次来自核心,一次来自我的配置。
我得到的错误是 "Column 'path' cannot be null",这基本上意味着 ImagesUploadListener 在保存实体之前没有执行图像上传。
app.listener.images_upload:
class: Sylius\Bundle\CoreBundle\EventListener\ImagesUploadListener
parent: sylius.listener.images_upload
autowire: true
autoconfigure: false
public: false
tags:
- { name: kernel.event_listener, event: sylius.product.pre_create, entity: MyBundle\Entity\MyEntity, method: uploadImages }
如果您正确创建实体(Sylius 方式),应该有一个事件可以挂钩。您需要将实体定义为资源:
# config/packages/sylius_resource.yaml
sylius_resource:
resources:
app.name_of_etity:
driver: doctrine/orm
classes:
model: App\Entity\NameOfEntity
如果您这样定义资源,事件将是:
event: app.system_manual.pre_create
event: app.app.name_of_entity.pre_update
遵循本指南:
https://docs.sylius.com/en/1.6/cookbook/entities/custom-model.html
更新
因为您是通过现有产品表单管理您的自定义实体,所以上述方法将不起作用。要使其工作,您可以创建自己的事件侦听器。
final class ProductSeoTranslationImagesUploadListener
{
/** @var ImageUploaderInterface */
private $uploader;
public function __construct(ImageUploaderInterface $uploader)
{
$this->uploader = $uploader;
}
public function uploadImages(GenericEvent $event): void
{
$subject = $event->getSubject();
// Add a ProductSeoInterface so you can use this check:
Assert::isInstanceOf($subject, ProductSeoInterface::class);
foreach ($subject->getSeo()->getTranslations() as $translation) {
Assert::isInstanceOf($translation, ImagesAwareInterface::class);
$this->uploadSubjectImages($translation);
}
}
private function uploadSubjectImages(ImagesAwareInterface $subject): void
{
$images = $subject->getImages();
foreach ($images as $image) {
if ($image->hasFile()) {
$this->uploader->upload($image);
}
// Upload failed? Let's remove that image.
if (null === $image->getPath()) {
$images->removeElement($image);
}
}
}
}
提示:创建一个 (Product)SeoInterface 以便您可以执行类型检查。
别忘了注册事件监听器:
App\EventListener\ProductSeoTranslationImagesUploadListener:
tags:
- {
name: kernel.event_listener,
event: sylius.product.pre_create,
method: uploadImages,
}
- {
name: kernel.event_listener,
event: sylius.product.pre_update,
method: uploadImages,
}
我正在尝试将 Sylius 的 ImagesUploadListener 用于自定义实体。 在 documentation 中,它说我应该听 "sylius.shipping_method.pre_create" 这样的事件。对于我的自定义实体,没有我可以挂接的事件。
所以我尝试挂钩 product.pre_create 事件并将我的实体作为参数,但似乎图片上传仅在产品实体上触发,我的实体配置被忽略。尽管 ImagesUploadListener 被触发了两次,一次来自核心,一次来自我的配置。
我得到的错误是 "Column 'path' cannot be null",这基本上意味着 ImagesUploadListener 在保存实体之前没有执行图像上传。
app.listener.images_upload:
class: Sylius\Bundle\CoreBundle\EventListener\ImagesUploadListener
parent: sylius.listener.images_upload
autowire: true
autoconfigure: false
public: false
tags:
- { name: kernel.event_listener, event: sylius.product.pre_create, entity: MyBundle\Entity\MyEntity, method: uploadImages }
如果您正确创建实体(Sylius 方式),应该有一个事件可以挂钩。您需要将实体定义为资源:
# config/packages/sylius_resource.yaml
sylius_resource:
resources:
app.name_of_etity:
driver: doctrine/orm
classes:
model: App\Entity\NameOfEntity
如果您这样定义资源,事件将是:
event: app.system_manual.pre_create
event: app.app.name_of_entity.pre_update
遵循本指南: https://docs.sylius.com/en/1.6/cookbook/entities/custom-model.html
更新
因为您是通过现有产品表单管理您的自定义实体,所以上述方法将不起作用。要使其工作,您可以创建自己的事件侦听器。
final class ProductSeoTranslationImagesUploadListener
{
/** @var ImageUploaderInterface */
private $uploader;
public function __construct(ImageUploaderInterface $uploader)
{
$this->uploader = $uploader;
}
public function uploadImages(GenericEvent $event): void
{
$subject = $event->getSubject();
// Add a ProductSeoInterface so you can use this check:
Assert::isInstanceOf($subject, ProductSeoInterface::class);
foreach ($subject->getSeo()->getTranslations() as $translation) {
Assert::isInstanceOf($translation, ImagesAwareInterface::class);
$this->uploadSubjectImages($translation);
}
}
private function uploadSubjectImages(ImagesAwareInterface $subject): void
{
$images = $subject->getImages();
foreach ($images as $image) {
if ($image->hasFile()) {
$this->uploader->upload($image);
}
// Upload failed? Let's remove that image.
if (null === $image->getPath()) {
$images->removeElement($image);
}
}
}
}
提示:创建一个 (Product)SeoInterface 以便您可以执行类型检查。
别忘了注册事件监听器:
App\EventListener\ProductSeoTranslationImagesUploadListener:
tags:
- {
name: kernel.event_listener,
event: sylius.product.pre_create,
method: uploadImages,
}
- {
name: kernel.event_listener,
event: sylius.product.pre_update,
method: uploadImages,
}