Flysystem
Edit on GitHubThe Flysystem module integrates Spryker with the thephpleague/flysystem vendor package.
It handles operation and Flysystem adapter configuration and provides FlysystemFilesystemBuilderPluginInterface
, where the build()
method is expected to return a concrete implementation of the \League\Flysystem\Filesystem
interface.
There are modules with adapters for Local, FTP, and AWS3 filesystems.
Flysystem features
Quote from Flysytem’s official documentation:
- Generic API for handling common tasks across multiple file storage engines.
- A consistent output that you can rely on.
- Integrate well with other packages and frameworks.
- Be cacheable.
- Emulate directories in systems that support none, like AwsS3.
- Support third-party plugins.
- Make it easy to test your filesystem interactions.
- Support streams for big file handling.
Module dependency graph
Flysystem provides plugins that integrate thephpleague/flysystem vendor package and implement FileSystem’s plugin interface.
Flysystem service API
Flysystem’s Service API is almost exactly like Flysystem’s API with only one distinction, it takes an additional mandatory parameter containing a preconfigured filesystem name.
For details, see Plugin configuration
For example, to extract an image’s metadata information stored under foo/bar.jpg
, use the getMetadata()
method with the media store’s name.
<?php
/**
* Specification:
* - Select preconfigured filesystem
* - Get resource metadata
* - Return resource metadata transfer, null on failure
*
* @param string $filesystemName
* @param string $path
*
* @return \Generated\Shared\Transfer\FlysystemResourceMetadataTransfer
*/
public function getMetadata($filesystemName, $path);
$metadataTransfer = $flysystemService->getMetadata('media', 'foo/bar.jpg');
Or to read file content from the customerDocument
store.
<?php
/**
* Specification:
* - Select preconfigured filesystem
* - Read file
* - Return file content, false on failure
*
* @param string $filesystemName
* @param string $path
*
* @return false|string
*/
public function read($filesystemName, $path);
$invoiceDocument = $flysystemService->read('customerData', 'invoices/2017/05/123.pdf');
Flysystem filesystem adapter modules
Different filesystems require different adapters to handle them. In Spryker, we use package principles to create modular and easy-to-configure applications. Each different Flysystem adapter implementing \League\Flysystem\FilesystemInterface
has its own module.
MODULE | DESCRIPTIO0N | CONFIG |
---|---|---|
FlysystemAws3v3FileSystem | Amazon AWS3 version 3 filesystem adapter. | FlysystemConfigAws3v3Transfer |
FlysystemFtpFileSystem | FTP filesystem adapter. | FlysystemConfigFtpTransfer |
FlysystemLocalFileSystem | Local filesystem adapter. | FlysystemConfigLocalTransfer |
You can install the adapter bundles on demand, just like any other Spryker module, or create your own.
Flysystem config
The FlysystemConfigTransfer
and options for thephpleague/flysystem are passed to the build()
method.
The adapter config is under adapterConfig
and flysystem options under flysystemConfig
.
<transfer name="FlysystemConfig">
<property name="name" type="string" />
<property name="type" type="string" />
<property name="adapterConfig" type="array" />
<property name="flysystemConfig" type="array" />
</transfer>
The name and type come from the project configuration.
The value of type should point to a concrete builder plugin implementing FlysystemFilesystemBuilderPluginInterface.
Filesystem adapter config
Every adapter module requires its own specific settings.
Example of FlysystemConfigFtp
:
<transfer name="FlysystemConfigFtp">
<property name="host" type="string" />
<property name="username" type="string" />
<property name="password" type="string" />
<property name="port" type="int" />
<property name="root" type="string" />
<property name="passive" type="bool" />
<property name="ssl" type="bool" />
<property name="timeout" type="int" />
</transfer>
Adapter builders
Every implementation of \League\Flysystem\AdapterInterface
requires a unique set of parameters or dependencies. Therefore, adapter instantiation is delegated to a specialized builder which knows about implementation details.
The builders are executed through plugins.
Filesystem builder plugin
The Flysystem bundle uses the FlysystemFilesystemBuilderPluginInterface
implemented by the concrete adapter’s module.
The build()
method is expected to return a class implementing the \League\Flysystem\Filesystem
interface.
The acceptType()
method is expected to return true if the filesystem type can be handled by the implementation.
Mapping between Filesystem and the type it can handle is done through configuration. For more details, see Plugin Configuration.
<?php
namespace Spryker\Service\Flysystem\Dependency\Plugin;
use Generated\Shared\Transfer\FlysystemConfigTransfer;
interface FlysystemFilesystemBuilderPluginInterface
{
/**
* @api
*
* @param \Generated\Shared\Transfer\FlysystemConfigTransfer $configTransfer
* @param \League\Flysystem\PluginInterface[] $flysystemPluginCollection
*
* @return \League\Flysystem\Filesystem
*/
public function build(FlysystemConfigTransfer $configTransfer, array $flysystemPluginCollection = []);
/**
* @api
*
* @param string $type
*
* @return bool
*/
public function acceptType($type);
}
Plugin example
Example implementation from Aws3v3FilesystemBuilderPlugin
.
<?php
namespace Spryker\Service\FlysystemAws3v3FileSystem\Plugin\Flysystem;
use Generated\Shared\Transfer\FlysystemConfigTransfer;
use Spryker\Service\Flysystem\Dependency\Plugin\FlysystemFilesystemBuilderPluginInterface;
use Spryker\Service\Kernel\AbstractPlugin;
class Aws3v3FilesystemBuilderPlugin extends AbstractPlugin implements FlysystemFilesystemBuilderPluginInterface
{
/**
* @param string $type
*
* @return bool
*/
public function acceptType($type)
{
return $type === get_class($this);
}
/**
* @param \Generated\Shared\Transfer\FlysystemConfigTransfer $configTransfer
* @param \League\Flysystem\PluginInterface[] $flysystemPluginCollection
*
* @return \League\Flysystem\Filesystem
*/
public function build(FlysystemConfigTransfer $configTransfer, array $flysystemPluginCollection = [])
{
return $this->getFactory()
->createFlysystemAws3v3FileSystemBuilder($configTransfer, $flysystemPluginCollection)
->build();
}
}
Flysystem adapter builder example
An example of an Aws3v3AdapterBuilder
, responsible for the instantiation of League\Flysystem\Adapter\AwsS3v3\AwsS3Adapter
.
It uses its own config FlysystemConfigAws3v3Transfer
, created by Aws3v3FilesystemBuilder
.
<?php
namespace Spryker\Service\FlysystemAws3v3FileSystem\Model\Builder\Adapter;
use Aws\S3\S3Client;
use Generated\Shared\Transfer\FlysystemConfigAws3v3Transfer;
use League\Flysystem\Adapter\AwsS3v3\AwsS3Adapter;
class Aws3v3AdapterBuilder implements AdapterBuilderInterface
{
const KEY = 'key';
const SECRET = 'secret';
const REGION = 'region';
const VERSION = 'version';
const CREDENTIALS = 'credentials';
/**
* @var \League\Flysystem\Adapter\AwsS3v3\AwsS3Adapter
*/
protected $adapter;
/**
* @var \Generated\Shared\Transfer\FlysystemConfigAws3v3Transfer
*/
protected $adapterConfig;
/**
* @var \Aws\S3\S3Client
*/
protected $client;
/**
* @param \Generated\Shared\Transfer\FlysystemConfigAws3v3Transfer $adapterConfig
*/
public function __construct(FlysystemConfigAws3v3Transfer $adapterConfig)
{
$this->adapterConfig = $adapterConfig;
}
/**
* @return \League\Flysystem\AdapterInterface
*/
public function build()
{
$this
->buildS3Client()
->buildAdapter();
return $this->adapter;
}
/**
* @return $this
*/
protected function buildS3Client()
{
$this->client = new S3Client([
self::CREDENTIALS => [
self::KEY => $this->adapterConfig->getKey(),
self::SECRET => $this->adapterConfig->getSecret(),
],
self::REGION => $this->adapterConfig->getRegion(),
self::VERSION => $this->adapterConfig->getVersion(),
]);
return $this;
}
/**
* @return $this
*/
protected function buildAdapter()
{
$this->adapter = new AwsS3Adapter($this->client, $this->adapterConfig->getBucket());
return $this;
}
}
Flysystem filesystem builder example
The following is an example of Aws3v3FilesystemBuilder
, responsible for instantiation of Filesystem implementing League\Flysystem\FilesystemInterface
. It creates a config using FlysystemConfigAws3v3Transfer
and validates it.
<?php
namespace Spryker\Service\FlysystemAws3v3FileSystem\Model\Builder\Filesystem;
use Generated\Shared\Transfer\FlysystemConfigAws3v3Transfer;
use Spryker\Service\FlysystemAws3v3FileSystem\Model\Builder\Adapter\Aws3v3AdapterBuilder;
class Aws3v3FilesystemBuilder extends AbstractFilesystemBuilder
{
/**
* @return \Generated\Shared\Transfer\FlysystemConfigAws3v3Transfer
*/
protected function buildAdapterConfig()
{
$configTransfer = new FlysystemConfigAws3v3Transfer();
$configTransfer->fromArray($this->config->getAdapterConfig(), true);
return $configTransfer;
}
/**
* @return void
*/
protected function assertAdapterConfig()
{
$adapterConfigTransfer = $this->buildAdapterConfig();
$adapterConfigTransfer->requireRoot();
$adapterConfigTransfer->requirePath();
$adapterConfigTransfer->requireKey();
$adapterConfigTransfer->requireSecret();
$adapterConfigTransfer->requireBucket();
$adapterConfigTransfer->requireVersion();
$adapterConfigTransfer->requireRegion();
}
/**
* @return \Spryker\Service\FlysystemAws3v3FileSystem\Model\Builder\Adapter\AdapterBuilderInterface
*/
protected function createAdapterBuilder()
{
$adapterConfigTransfer = $this->buildAdapterConfig();
return new Aws3v3AdapterBuilder($adapterConfigTransfer);
}
}
AbstractFilesystemBuilder example
The following is an example of AbstractFilesystemBuilder
from the FlysystemAws3v3FileSystem
module.
<?php
namespace Spryker\Service\FlysystemAws3v3FileSystem\Model\Builder\Filesystem;
use Generated\Shared\Transfer\FlysystemConfigTransfer;
use League\Flysystem\Filesystem;
abstract class AbstractFilesystemBuilder implements FilesystemBuilderInterface
{
/**
* @var \Generated\Shared\Transfer\FlysystemConfigTransfer
*/
protected $config;
/**
* @param \Generated\Shared\Transfer\FlysystemConfigTransfer $configTransfer
*/
public function __construct(FlysystemConfigTransfer $configTransfer)
{
$this->config = $configTransfer;
}
/**
* @return void
*/
abstract protected function assertAdapterConfig();
/**
* @return \Spryker\Service\FlysystemAws3v3FileSystem\Model\Builder\Adapter\AdapterBuilderInterface
*/
abstract protected function createAdapterBuilder();
/**
* @return \League\Flysystem\Filesystem
*/
public function build()
{
$this->assertAdapterConfig();
$filesystem = $this->buildFilesystem();
return $filesystem;
}
/**
* @return \League\Flysystem\Filesystem
*/
protected function buildFilesystem()
{
$adapter = $this->createAdapterBuilder()->build();
$config = $this->config->getFlysystemConfig() ?: [];
return new Filesystem($adapter, $config);
}
}
Flysystem plugins
The thephpleague/flysystem vendor package also supports plugins.
In Spryker, they are loaded using FlysystemDependencyProvider
and automatically passed to the build()
method.
All you need to do is to configure them in the addFlysystemPluginCollection()
method.
<?php
namespace Spryker\Service\Flysystem;
use Spryker\Service\Kernel\AbstractBundleDependencyProvider;
use Spryker\Service\Kernel\Container;
class FlysystemDependencyProvider extends AbstractBundleDependencyProvider
{
/**
* @param \Spryker\Service\Kernel\Container $container
*
* @return \Spryker\Service\Kernel\Container
*/
protected function addFlysystemPluginCollection($container)
{
$container[self::PLUGIN_COLLECTION_FLYSYSTEM] = function (Container $container) {
return [];
};
return $container;
}
FlysystemServiceFactory
uses the configured plugins stack in buildFilesystemCollection()
using the getFlysystemPluginCollection()
method.
To overwrite buildFilesystemCollection()
, make sure to carry over this behavior. Otherwise, implement the Flysystem
plugin loading and configuration on your own.
Enable SFTP
Flysystem does not support SFTP by default, but the separate Flysystem Adapter for SFTP module enables it.
To enable SFTP for Flysystem, implement FlysystemFilesystemBuilderPluginInterface
and add it to \Pyz\Service\Flysystem\FlysystemDependencyProvider::addFilesystemBuilderPluginCollection
.
Thank you!
For submitting the form