webiny/storage

Webiny 存储组件

v1.6.1 2017-09-29 08:12 UTC

README

存储组件是一个存储抽象层,简化了您与文件和目录交互的方式。

安装组件

安装组件的最佳方式是使用 Composer。

composer require webiny/storage

要获取软件包的附加版本,请访问Packagist 页面

用法

您需要使用存储驱动程序来访问不同的存储提供商,如本地磁盘、Amazon、Rackspace 等。

Webiny 框架提供 LocalStorageDriverS3StorageDriver,但使用内置接口集可以帮助您快速开发新的驱动程序。

以下驱动程序接口可用

  • DriverInterface - 主要存储驱动程序接口
  • TouchableInterface - 用于支持 touch 功能的驱动程序(修改时间的变化)
  • SizeAwareInterface - 用于可以访问文件 size 的驱动程序
  • DirectoryAwareInterface - 用于可以处理目录的驱动程序
  • AbsolutePathInterface - 用于可以提供绝对文件路径的驱动程序(例如:/var/www/app/storage/myFile.txt)

配置存储服务

使用存储的最佳方式是定义一个存储服务。以下是一个使用 LocalStorageDriverS3StorageDriver 定义服务的示例:注意:您可以使用 DIR 来动态构建文件路径。DIR 将被替换为包含当前配置文件的目录路径。

Storage:
    # You can optionally specify parameters for use in services definitions
    Parameters:
        Storage.Class: \Webiny\Component\Storage\Storage
        Storage.S3DriverArgs:
            - yourAccessKeyID
            - yourSecretAccessKey
            - webiny # Bucket name
            - false # Date folder structure
            - http://d47gcb3uej2zar.cloudfront.net # CDN domain
    Services:
        LocalStorage:
            Class: %Storage.Class%
            Arguments:
                Driver:
                    Object: \Webiny\Component\Storage\Driver\Local\LocalStorageDriver
                    ObjectArguments:
                        - __DIR__/../../Public/Uploads # Absolute root path
                        - http://admin.w3.com/Uploads # Web root path
                        - false # DateFolderStructure
                        - true # Create folder if it doesn't exist
        CloudStorage:
            Class: %Storage.Class%
            Arguments:
                Driver:
                    Object: \Webiny\Component\Storage\Driver\AmazonS3\S3StorageDriver
                    ObjectArguments: %Storage.S3DriverArgs%
            Tags: [cloud]

(这只是定义服务的一种方式。有关定义服务的详细文档,请参阅 ServiceManager 组件。)

使用您的新存储

为了使本地存储更容易、更灵活,有两个类:`\Webiny\Component\Storage\File\File` 和 `\Webiny\Component\Storage\Directory\Directory`。这两个类作为包装器,因此您永远不需要直接调用存储。此外,它们包含您将需要的在文件和目录上执行操作的方法。

让我们看看如何存储一个新的文件

// use StorageTrait

// Get your storage service. Storage name is part of the service name after 'Storage.'
$storage = $this->storage('LocalStorage');

// Create a file object with a key (file name) and a $storage instance
$file = new File('file.txt', $storage);

$contents = file_get_contents('https://w3schools.org.cn/images/w3schoolslogoNEW310113.gif');
$file->setContents($contents);

调用 setContents($contents) 后,内容将立即写入存储,并返回一个 bool

处理目录

有时您需要读取整个目录,按名称、扩展名等过滤文件。为此类型操作有一个特殊接口,`\Webiny\Component\Storage\Directory\DirectoryInterface`。

由于并非所有存储引擎都支持目录,因此没有此接口的通用实现。然而,有一个名为 `Directory` 的实现,它与本地文件存储配合得很好。读取目录有两种模式:`recursive`(递归)和`non-recursive`(非递归)。

  • Recursive 会递归地读取整个目录结构,并构建一个一维数组(目录对象不会被创建,但会返回它们的子文件)。当您需要一次性读取所有文件或按名称、扩展名等进行过滤时,这非常有用。
  • Non-recursive 只会读取当前目录,并返回子 `Directory` 和 `File` 对象。然后您可以通过遍历子 `Directory` 对象来深入。

读取目录(非递归模式)

// Get your storage service
$storage = $this->storage('LocalStorage');

// Create a directory object with a key (directory name), $storage instance
$dir = new Directory('2013', $storage);

// Loop through directory object
foreach($dir as $item){
    if($item->isDirectory()){
		// Do something with child Directory object
	} else {
		// Do something with File object
	}
}

注意:直到您实际使用对象,目录文件不会被从存储中检索。

过滤文件(递归模式)

// Get your storage service
$storage = $this->storage('LocalStorage');

// Read recursively
$dir = new Directory('2013', $storage, true);

// Get only PDF files
$pdfFiles = $dir->filter('*.pdf');

// Count ZIP files
$zipFiles = $dir->filter('*.zip')->count();

// Get files starting with 'log_'
$logFiles = $dir->filter('log_*');

// You can also pass the result of filter directly to loops as `filter()` returns a new Directory object
foreach($dir->filter('*.txt') as $file){
    // Do something with your file
}

注意:调用 `filter()` 不会更改原始的 `Directory` 对象,而是创建一个新的带有过滤结果的新 `Directory` 对象,因此一旦您读取了根目录,您就可以使用任何条件多次进行过滤。

// Get your storage service
$storage = $this->storage('LocalStorage');

// Read recursively and don't filter
$dir = new Directory('2013', $storage, true);

// Now you can manipulate the whole directory 

// Get number of all ZIP files in the directory tree
$zipFiles = $dir->filter('*.zip')->count();

// Get number of all RAR files in the directory tree
$zipFiles = $dir->filter('*.rar')->count();

// Get number of all LOG files in the directory tree
$zipFiles = $dir->filter('*.log')->count();

// Now output all files in the directory without filtering them
foreach($dir as $file){
    echo $file->getKey();
}

删除目录

删除目录(这是递归进行的)非常简单

// Get your storage service
$storage = $this->storage('LocalStorage');

// Get directory
$dir = new Directory('2013', $storage);

// This will delete the whole directory structure and fire FILE_DELETED event for each file along the way
$dir->delete();

// If you don't want the events to be fired, pass as second parameter `false`:
$dir->delete(false);

存储事件

当对文件执行某些操作时,会触发3种类型的事件

  • wf.storage.file_saved(StorageEvent::FILE_SAVED)- 文件成功保存后触发。
  • wf.storage.file_renamed(StorageEvent::FILE_RENAMED)- 文件重命名后触发。
  • wf.storage.file_deleted(StorageEvent::FILE_DELETED)- 文件删除后触发。

所有3个事件都将\Webiny\Component\Storage\StorageEvent的实例传递给它们的事件处理器。一旦处理器执行,您可以使用$event->getFile()方法访问文件对象。

class Test {
    use EventManagerTrait;
    
    public function index(){
    
        // Listen for StorageEvent::FILE_SAVED
        $this->eventManager()->listen(StorageEvent::FILE_SAVED)->handler(function(StorageEvent $event){
            // Get the file object
            $file = $event->getFile();
        });
    }
}

StorageEvent::FILE_RENAMED事件还会将一个名为oldKey的特别属性赋给事件对象,该属性包含重命名前的文件键值(这有助于您更新数据库记录等)。

class Test {
    use EventManagerTrait;
    
    public function index(){
    
        // Listen for StorageEvent::FILE_RENAMED
        $this->eventManager()->listen(StorageEvent::FILE_RENAMED)->handler(function(StorageEvent $event){
        
            // Get the file object
            $file = $event->getFile();
            
            // $file now contains the file object with new key, and we need to get the old key
            $oldKey = $event->oldKey;
            $newKey = $file->getKey();
        });
    }
}

资源

要运行单元测试,您需要使用以下命令

$ cd path/to/Webiny/Component/Storage/
$ composer.phar install
$ phpunit