iiirxs / image-upload-bundle
一个用于处理带有映射图像集合的多个图像上传的 Symfony 扩展包
Requires
- php: ^7.1.3
- ext-gd: *
- ext-json: *
- ext-mongodb: *
- doctrine/mongodb-odm-bundle: ^3.4 || ^4.0
- iiirxs/exception-handler-bundle: @dev
- iiirxs/validation-error-normalizer-bundle: @dev
- sensio/framework-extra-bundle: ^5.2
- symfony/event-dispatcher: ^4.0
- symfony/expression-language: ^4.2
- symfony/form: ^4.3
- symfony/framework-bundle: ^4.0 || ^5.0
- symfony/http-foundation: *
- symfony/property-access: *
Requires (Dev)
- spatie/image-optimizer: ^1.1
- symfony/browser-kit: ^4.0
- symfony/cache: ^4.0
- symfony/phpunit-bridge: ^5.0
- symfony/validator: ^4.0
Suggests
README
此扩展包为嵌入式图像集合提供开箱即用的图像上传和优化功能。
安装
请确保已全局安装 Composer,如 Composer 文档中的安装章节所述。
使用 Symfony Flex 的应用程序
打开命令控制台,进入您的项目目录,并执行以下命令
$ composer require iiirxs/image-upload-bundle
不使用 Symfony Flex 的应用程序
步骤 1:下载扩展包
打开命令控制台,进入您的项目目录,并执行以下命令以下载此扩展包的最新稳定版本
$ composer require iiirxs/image-upload-bundle
步骤 2:启用扩展包
然后,通过将其添加到项目 config/bundles.php
文件中注册的扩展包列表中,来启用扩展包。
// config/bundles.php return [ // ... IIIRxs\ImageUploadBundle\IIIRxsImageUploadBundle::class => ['all' => true], ];
使用方法
该扩展包提供所有必要的图像上传功能,以及通过配置、服务覆盖和类继承进行扩展的能力。目前它只支持 MongoDB 数据库,通过 Doctrine ODM 扩展包。
基本使用方法
步骤 1:添加图像嵌入式集合
在文档内嵌入图像集合。目标文档类 必须 扩展 IIIRxs\ImageUploadBundle\Document\AbstractImage
AbstractImage 类提供两个基本映射字段:path
和 rank
,但可以在扩展类中添加任何其他映射字段。
// src/Document/ImageContainer.php /** * @MongoDB\EmbedMany(targetDocument=Image::class, strategy="atomicSetArray") */ protected $images;
// src/Document/Image.php use IIIRxs\ImageUploadBundle\Document\AbstractImage; /** * @MongoDB\EmbeddedDocument */ class Image extends AbstractImage
步骤 2:设置上传器
为了在文件系统中上传图像,您的应用程序应包含至少一个实现 IIIRxs\ImageUploadBundle\Uploader\ImageUploaderInterface
的服务,并将其添加到 IIIRxs\ImageUploadBundle\Uploader\ChainUploader
。
实现这一点的最简单方法是简单地配置图像应上传到的目录的完整路径。您可以通过在扩展包的配置文件中配置 default_image_upload_dir
值来完成此操作。
// config/packages/iiirxs_image_upload.yaml iiirxs_image_upload: default_image_upload_dir: '%kernel.project_dir%/public/images'
该扩展包还提供创建每个上传图像的优化版本和缩略图的能力,而不仅仅是将上传的文件移动到目标目录。要使用此功能,只需提供一个包含 optimized
和 thumbnails
键的数组,而不是单个路径即可。
// config/packages/iiirxs_image_upload.yaml iiirxs_image_upload: default_image_upload_dir: optimized: '%kernel.project_dir%/public/images/optimized' thumbnails: '%kernel.project_dir%/public/images/thumbnails'
现在,默认上传器已注册在链上传器中,并将用于上传应用程序中配置为通过扩展包处理的任何图像集合中的图像。
步骤 3:上传图像文件
由于所有必要的功能都已实现在 IIIRxs\ImageUploadBundle\Controller\ImageController
中,您只需向 uploadImages
控制器操作发出适当的请求即可。
创建图像集合
全部上传
要在一个请求中上传一个包含其排名的新图像集合,您应在 JavaScript 代码中向您的 iiirxs_image_upload
路由发出一个 POST 请求,并将 Content-Type
标头设置为 multipart/form-data
。请求的有效负载应为 FormData
对象。
示例:将图像集合添加到现有的图像容器对象中
let formData = new FormData(); // name of the property containing the embedded collection let formField = 'images'; let imageInput = document.querySelector('#multiple_image_file_input'); formData.append(formField + '[0][file]', imageInput.files[0]); formData.append(formField + '[0][rank]', 1); formData.append(formField + '[1][file]', imageInput.files[1]); formData.append(formField + '[1][rank]', 2); // the object id to which images are being added let id = 1; // name of the class with the embedded collection // route path: /{className}/{fieldName}/upload/{id} let route = '/image-container-class/images/upload/' + id; axios.post(route, formData);
逐个上传
要逐个上传包含 n 个图像的新图像集合,您应向 iiirxs_image_upload 路由发出 n+1 个 POST 请求;每个图像一个,加上一个图像排名。
示例:通过多个请求添加图像集合
let formField = 'images'; // the object id to which images are being added let id = 1; // name of the class with the embedded collection // route path: /{className}/{fieldName}/upload/{id} let route = '/image-container-class/images/upload/' + id; let formData = new FormData(); // name of the property containing the embedded collection let imageInput = document.querySelector('#multiple_image_file_input'); formData.append(formField + '[0][file]', imageInput.files[0]); formData.append(formField + '[1][file]', null); let request1 = axios.post(route, formData); formData = new FormData(); formData.append(formField + '[0][file]', null); formData.append(formField + '[1][file]', imageInput.files[1]); let request2 = axios.post(route, formData); axios.all([request1, request2]).then(() => { let rankData = new FormData(); rankData.append(formField + '[0][rank]', 1); rankData.append(formField + '[1][rank]', 2); axios.post(route, rankData); })
添加到图像集合
将新图像添加到现有集合与创建图像集合的过程非常相似,涉及多个请求。请注意,在这些请求过程中,您应始终为数据库中的每张现有图像添加一个值为null的字段到FormData
对象中,如果相应的排名字段未在您的FormData
对象中设置,否则该图像将从数据库中删除。
示例:将新图像添加到现有集合
let formData = new FormData(); // name of the property containing the embedded collection let formField = 'images'; let imageInput = document.querySelector('#image_file_input'); // A third image is being added formData.append(formField + '[2][file]', imageInput.files[0]); formData.append(formField + '[0][rank]', 1); formData.append(formField + '[1][rank]', 2); formData.append(formField + '[2][rank]', 3); // the object id to which images are being added let id = 1; // name of the class with the embedded collection // route path: /{className}/{fieldName}/upload/{id} let route = '/image-container-class/images/upload/' + id; axios.post(route, formData);
示例:将新图像添加到现有集合(无排名)
let formData = new FormData(); // name of the property containing the embedded collection let formField = 'images'; let imageInput = document.querySelector('#image_file_input'); // A third image is being added formData.append(formField + '[0][file]', null); formData.append(formField + '[1][file]', null); formData.append(formField + '[2][file]', imageInput.files[0]); // the object id to which images are being added let id = 1; // name of the class with the embedded collection // route path: /{className}/{fieldName}/upload/{id} let route = '/image-container-class/images/upload/' + id; axios.post(route, formData);
从图像集合中删除
为了从集合中删除图像,您只需从发送到FormData
对象的键中省略即可。
示例:将新图像添加到现有集合(无排名)
let formData = new FormData(); // name of the property containing the embedded collection let formField = 'images'; // Second image is being deleted formData.append(formField + '[0][file]', null); formData.append(formField + '[2][file]', null); // the object id to which images are being added let id = 1; // name of the class with the embedded collection // route path: /{className}/{fieldName}/upload/{id} let route = '/image-container-class/images/upload/' + id; axios.post(route, formData);
步骤4(可选):发布额外的图像详情
如果您在Image类中添加了额外的字段(例如,描述),您可以将这些详细信息发布到postImageDetails
控制器操作。
但是,为了做到这一点,首先您应该创建自己的表单类型类,该类扩展了IIIRxs\ImageUploadBundle\Form\Type\ImageType
类。
class CustomImageType extends ImageType { public function buildForm(FormBuilderInterface $builder, array $options) { parent::buildForm($builder, $options); $builder ->add('description', TextType::class) ; } }
然后您必须将适当的映射添加到包的配置中,以便为特定的嵌入式集合使用正确的表单类型。
// config/packages/iiirxs_image_upload.yaml iiirxs_image_upload: mappings: App\Document\ImageContainerClass: fields: # name of the property containing the image collection images: class: App\Document\CustomImage form_type: App\Form\Type\CustomImageType
现在您可以通过向iiirxs_image_upload_details_post
路由发送简单的POST请求来发布图像详情。请求的有效负载应该是一个具有示例结构的json对象。
示例:向现有图像集合发布额外详情
// name of the property containing the embedded collection let formField = 'images'; let details = { [formField]: { 0: { rank: 1, description: 'Lorem ipsum' }, 1: { rank: 2, description: 'dolor sit amet' }, } } // the object id to which images are being added let id = 1; // name of the class with the embedded collection // route path: /{className}/{fieldName}/details/{id} let route = '/image-container-class/details/' + id; axios.post(route, details);
您已完成操作!您的图像将被存储在MongoDB数据库中的嵌入式集合中,并且相应的文件将被移动到文件系统中的适当位置。
高级用法
表单
该包提供两种基本的表单类型
- IIIRxs\ImageUploadBundle\Form\Type\ImageCollectionType
- IIIRxs\ImageUploadBundle\Form\Type\ImageType
它还提供了一个ImageFormService
服务,该服务根据Doctrine ODM映射或显式配置创建基于ImageCollectionType
的表单。
ImageCollectionType
提供了一个集合字段(字段名应明确提供)。此集合字段的条目类型默认为ImageType
类,但您可以通过包或通过适当传递表单选项来覆盖它。
ImageType
仅支持扩展AbstractImage
类的对象。
如果您的项目中的Doctrine ODM映射定义正确或包配置中存在正确的映射,您要为特定类创建一个ImageCollectionType
表单,只需提供该类的实例和一个有效的字段名(对应于图像集合)给ImageFormService即可。
$object = new ImageContainer(); $form = $imageFormService->createForm($object, 'images');
为了显式定义特定类及其相应表单类型的映射,您可以使用包的配置,如下所示
// config/packages/iiirxs_image_upload.yaml iiirxs_image_upload: mappings: App\Document\ImageContainer: fields: images: class: App\Document\Image form_type: App\Form\Type\YourOwnImageType anotherImageCollection: class: App\Document\AnotherImageClass form_type: App\Form\Type\AnotherImageType
上传器
该包提供了一个ChainUploader
类,一个AbstractUploader
类和一个ImageUploaderInterface
。 ImageUploaderInterface
公开了两个方法:supports
和upload
。
// config/services.yaml App\Service\ImageUploader: tags: ['image.uploader'] arguments: imagesDir: '%kernel.project_dir%/public/images' # in order to save both optimized and thumbnail images for each upload: # imagesDir: # optimized: '%kernel.project_dir%/public/images/optimized' # thumbnails: '%kernel.project_dir%/public/images/thumbnails'
创建ImageUploader类最简单的方法是扩展提供所有必要功能的IIIRxs\ImageUploadBundle\Uploader\AbstractUploader
类。
在扩展AbstractUploader
类时,您的ImageUploader
服务在其构造函数中至少应接收两个参数。
构造函数参数
$imagesDir
对应于图像应存储的目录的完整路径。它可以是字符串或数组,在后一种情况下,必须包含具有字符串值作为完整路径的optimized
和thumbnails
键的数组。$maxThumbnailDimension
在需要创建缩略图时使用,并定义缩略图的最大像素尺寸。默认设置为600px。
// App\Service\ImageUploader class ImageUploader extends AbstractUploader { function __construct(string $imagesDir, int $maxThumbnailDimension) { parent::__construct($imagesDir, $maxThumbnailDimension); } public function supports($document): bool { // return true to support every document or "$document instanceof ExampleClass"// // to support upload only for specific class. // Note that ExampleClass is a class containing the image file, typically a// // subclass of AbstractImage class return true; } }
您可以在包配置中轻松设置最大缩略图尺寸。
// config/packages/iiirxs_image_upload.yaml iiirxs_image_upload: max_thumbnail_dimension: 400
该插件注册了所有标记为 'image.uploader' 的服务,这些服务位于 ChainUploader
类中。要在服务中使用 ChainUploader
,您只需注入它,并调用 selectUploader
和 upload
方法即可。
class Service { public function __construct(ChainUploader $uploader) { $this->uploader = $uploader; } public function callUploader() { $this->uploader->selectUploader($image); $filename = $this->uploader->upload($image->getFile()); } }
事件
该插件提供了三个事件
ImageDetailsPostEvent
ImagesDeleteEvent
ImagesUploadEvent
以及一个事件订阅者,它监听 ImagesDeleteEvent
和 ImagesUploadEvent
事件。该 ImageListener
使用 ChainUploader
服务适当上传文件,并在正确分发 ImagesDeleteEvent
时删除图像文件。
您可以通过覆盖项目配置中的 iiirxs_image_upload.event_listener.image_listener
服务来为该事件订阅者设置自己的功能。
控制器
该插件最终提供了处理与图像上传相关的所有内容的控制器操作。
如前所述,如果您想使用插件提供的控制器操作,您只需注册至少一个实现 ImageUploaderInterface
的服务,并标记为 'image.uploader',且支持您想要的上传情况即可。
该插件提供了两种不同的操作:用于文件上传的 uploadImages
和用于更新图像相关信息的 postImageDetails
(如图像排名和图像描述)。
目前,uploadImages
操作仅支持通过表单提交(multipart/form-data 内容类型)进行文件上传。