bmartel/phperclip

用于 Eloquent 模型的文件附件和管理

1.2.1 2015-06-23 16:24 UTC

README

文件上传管理模板让你头疼吗?你是否想简化修改和缓存原始上传文件的过程?Phperclip 是一个旨在简化文件存储、排序和处理的包。

特性

  • 通过界面和一个可选的特质将文件附加到任何 eloquent 模型
  • 可配置和可自定义的存储驱动器
  • 根据使用的存储驱动器生成文件 URI
  • 通过 FileProcessors 插件文件处理
  • 通过包含的 FileProcessor 进行图像处理
  • 强大的、无差别的批量处理器

设置

要将 Phperclip 准备好用于您的项目,请按照设置 Laravel 4 包的常规步骤操作。

  • bmartel/phperclip 添加到您的 composer.json 文件中。
  • 在项目根目录运行 composer update
  • 编辑您的 app/config/app.php 文件并添加
    • 'Bmartel\Phperclip\ServiceProvider',providers 数组中
    • 'Phperclip' => 'Bmartel\Phperclip\Facade',aliases 数组中
  • 运行迁移 ./artisan migrate --package="bmartel/phperclip"
  • 复制项目级别的配置 ./artisan config:publish bmartel/phperclip
Note: If you are using type-hinted dependency injection in your project, as a convenience Phperclip binds the type `Bmartel\Phperclip\Service` in the container.

配置

文件名生成

文件名是通过一个实现了 Bmartel\Phperclip\Contracts\FileNameGenerator 接口的类生成的。默认情况下,Phperclip 使用自己的文件名生成器实现 Bmartel\Phperclip\FileNameGenerator。它在配置中设置如下

	'filename_generator' => 'Bmartel\Phperclip\FileNameGenerator'

此实现获取文件选项和属性 json 结果的 md5 哈希值。如果您想使用其他方式生成文件名,请创建自己的实现,并将其作为 Phperclip 的 config.php 文件中 filename_generator 的值包含。

存储

如果您打开设置期间创建的 config.php 文件副本,您会看到它已经填充了最常见的设置配置选项。`Bmartel\Phperclip\Storage\Filesystem` 驱动程序是最基本的,它只是将图像文件存储在您的网站公共目录中。

Amazon S3 驱动程序

将 'config.php' 文件中的文件系统驱动程序配置替换为以下 Amazon AWS 配置。

[
	'storage' =>
	[
		'Bmartel\Phperclip\Storage\S3' =>
		[
			'aws_key' => 'YOUR_KEY_HERE',
			'aws_secret' => 'YOUR_SECRET_HERE',
            'aws_bucket' => 'phperclip-bucket'
		]
	]
]

处理器

Phperclip 不强制指定您想对文件做什么。相反,它通过 FileProcessors 提供服务生命周期方法的钩子。FileProcessors 允许您指定它将负责的文件类型和生命周期方法:onBeforeSave、onSave、onDelete 和 onMove,您可以在文件上执行任何处理。

以下生命周期方法将在它们返回 false 类型时中止当前操作。方法的正常运行条件预期您返回传递的文件。

  • onBeforeSave:在任何文件持久化之前执行。非常适合验证或其他预保存处理,您不希望在失败时创建文件。
  • onSave:在原始、未修改的文件持久化后立即执行。允许对文件进行修改。
  • onDelete:每当即将删除文件时执行。非常适合开始清理烦人的文件关系、执行验证或对请求文件删除的用户进行授权。
  • onMove:每当文件在插槽之间移动时执行。

已提供ImageProcessor,既是为了展示FileProcessor组件的强大功能,也是为了提供灵活且可链定的图像过滤功能!

图像过滤器

Phperclip的过滤链是一个非常强大的功能,允许您在保存或检索图像时编排任意组合的操纵。在处理链时,Phperclip对链中的每个过滤器执行以下操作:

  • 尝试实例化指定的类,该类必须实现Bmartel\Phperclip\Contracts\Filter
  • 如果过滤器的配置是一个数组,则第二个索引中的每个键都将作为子类中的setter方法调用
  • 在子类上调用方法run,传入原始图像和图像的数据库条目

您可能希望为项目预先配置过滤链,这样在检索各种版本时就不必重复它们。Phperclip使用一个简单的数组模式来定义过滤链。以下是一个示例

[

	'Bmartel\Phperclip\Processes\Image\FixRotation',
	
	[
		'Bmartel\Phperclip\Processes\Image\Resize',
		[
			'width' => 300,
			'height' => 300,
			'preserve_ratio' => true
		]
	],
	
	[
		'Bmartel\Phperclip\Processes\Image\Watermark',
		[
			'source_path' => sprintf('%s/logo.png', __DIR__),
			'anchor' => 'bottom-right'
		]
	]

]
  • 数组不得有键。
  • 字符串类型的条目将实例化并运行,不传递任何参数。
  • 子数组类型的条目将使用该数组的第一个索引[0]进行实例化,将第二个索引[1]转换为实例的setter
    • setWidth(300)
    • setHeight(300)
    • setPreserveRatio(true)
    • 等等...

如果您不确定应该在哪里存储您的过滤器配置文件,建议您将它们放置在之前在发布Phperclip配置时为您创建的filters.php文件中。这将允许您根据环境变化过滤器配置,并使检索变得简单,如Config::get('phperclip::filters.filter_name')

用法

根据您的实现方式,您接收文件的方式可能会有所不同。Phperclip不会对您的请求生命周期(或是否有请求)做出假设,它只关心接收Symfony\Component\HttpFoundation\File\File实例。

Phperclip使用的两个可选的次要信息是Clippable,用于限制到特定模型,以及一个选项数组,允许在文件上执行处理。

特质

如果您计划将文件附加到模型(用户、项目、图像库),则该模型必须实现接口Bmartel\Phperclip\Model\Clippable。这将强制您实现一个方法,您可以自己实现或通过使用特质Bmartel\Phperclip\Model\ClippableImpl方便地与Phperclip保持同步。

保存

通过门面或通过依赖注入访问Phperclip服务,可以完成文件的保存。

	/** @var \Symfony\Component\HttpFoundation\File\File $file */
	/** @var \Bmartel\Phperclip\Model\Clippable $clippable */

	$options = [
		'attributes' => ['slot' => 1]
	];

	/** @var \Bmartel\Phperclip\Model\File $file */
	$file = Phperclip::saveFromFile($file, $clippable, $options);

Phperclip在成功保存后将返回一个Bmartel\Phperclip\Model\File实例。如果您提供了一个文件记录,它将与可剪切的项关联。通过选项数组的键属性,将传递任何其他属性到保存。

检索

在检索单个文件时,您需要一种方法来识别它

  • 文件的id
  • 文件的剪贴项和槽位
  • 文件的clippedFiles()关系

通常您至少会有一项这些信息,然后您就可以获得指向物理文件的URI。

	Phperclip::getPublicUri($file, $options);
	Phperclip::getPublicUriBySlot($slot, $clippable, $options);
	Phperclip::getPublicUriById($id, $options);

您还可以通过所属的可剪切的项、文件MIME类型或槽位检索文件集合。Phperclip将返回一个Bmartel\Phperclip\Model\File集合。

  Phperclip::getFilesFor($clippable, $mimetypes, $slot);

在从Phperclip检索文件时,请记住,您在“可剪切的”看到的地方都是可选的,省略它或提供null表示“全局”。同样,“选项”也是可选的,省略此值、提供null或空数组将表示“原始文件”

槽位

Phperclip 具有一个名为槽位的概念,其核心就是一个字符串值。槽位用于按顺序或按键对文件进行排序。在 Bmartel\Phperclip\Model\File 类上提供了辅助作用域,帮助根据槽位值检索文件。

Note: When storing files without a clippable (globally), keep in mind that they are all sharing the same slot scope and cannot have duplicates.

槽位的示例用例可能是一个具有图片库以及“主”图片的“项目”类。属于图片库的图片将具有数字槽位,以便可以保持特定的顺序,而主图片则在一个可以直接查询的命名槽位中。

批处理

实现通常需要一个方法,可以在单次遍历中提交多个对可剪辑文件的变化。这些变化有时可能会产生冲突,难以解决。

作为便利,Phperclip 提供了一个服务上的批处理方法,允许执行这些批量操作。操作按可剪辑文件进行范围划分,并按安全顺序逐槽位执行。

模式结构对调用者不可知,在不可避免的发生冲突的情况下,将使任何被替换文件的槽位为空。

以下是在执行批处理操作时使用的模式示例

	$operations = [
		1 => 2,
		3 => 'thumbnail',
		4 => null,
		5 => 'http://placehold.it/200x200&text=Phperclip'
	];

	/** @var \Symfony\Component\HttpFoundation\File\File[] $newFiles */
	/** @var \Bmartel\Phperclip\Model\Clippable $clippable */

	Phperclip::batch($operations, $newFiles, $clippable);

在此示例中,以下操作将按顺序执行

  • 槽位 1 和 2 中的文件将被交换
  • 槽位 3 中的文件将被移动到 '缩略图' 槽位
  • 槽位 4 中的文件将被删除
  • 位于 URI 的文件将被下载并插入槽位 5

文件数组 $newFiles 将按槽位键入,理论上可以包含槽位 4 的新文件。

当文件被指示移动到新槽位时,如果目标槽位中已有一个文件,则它们将被交换。如果上传的文件尝试进入一个已占用的槽位,则该槽位中当前文件将使其槽位为空。

需要注意的是,在此模式中,槽位键不能重复,因此最好提交最简单的批量列表。

驱动程序

创建驱动程序就像扩展类 Bmartel\Phperclip\Storage\Base 一样简单。您还可以使用 Bmartel\Phperclip\Storage\Filesystem 作为参考。

处理器

要使文件处理变得神奇,您需要实现一个专门的 FileProcessor 来处理在文件服务生命周期中可能需要执行的任务。您在类中指定处理器将执行哪些文件类型,并根据您的需求在生命周期方法中提供处理。

首先,实现接口 Bmartel\Phperclip\Contracts\FileProcessor。为了获得一些免费的功能,如内置文件验证和闪存消息,您可以扩展类 Bmartel\Phperclip\Processes\FileProcessorAdapter

图像过滤器实际上是通过一个包含的 FileProcessor Bmartel\Phperclip\Processes\ImageProcessor 来处理的!您可以在创建自己的 FileProcessor 时将其作为指导。

图像过滤器

在您的项目或包中创建自己的图像过滤器非常简单。只需实现接口 Bmartel\Phperclip\Contracts\Filter

唯一规则是,过滤器子类必须在不移动、重命名或删除文件的情况下对其提供的文件进行操作 - 覆盖是允许的。不期望 run 方法返回值。

在创建自己的图像过滤器时,请参阅 Bmartel\Phperclip\Processes\Image\ResizeBmartel\Phperclip\Processes\Image\FixRotation 作为指导。

问题

如果您遇到任何问题,发现错误或有任何问题,请随时在问题跟踪器中提交工单。

致谢

Brandon Martel - 维护者

Alex Trauzzi - 创建了 tippingcanoe/imager 的原始实现,此包基于此。