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);
}
}
AWS S3 filesystem builder plugins
The FlysystemAws3v3FileSystem module provides two builder plugins for Amazon S3. Both return a \League\Flysystem\Filesystem backed by the AWS S3 v3 adapter; they differ only in how AWS credentials are resolved.
Aws3v3FilesystemBuilderPlugin |
IamAws3v3FilesystemBuilderPlugin |
|
|---|---|---|
| Credentials | Explicit key and secret from the adapter config |
Resolved automatically by the AWS SDK default credential provider chain |
| Required adapter config | key, secret, bucket, region, path |
bucket, region |
key / secret |
Used | Ignored |
endpoint |
Always passed to the S3 client | Passed only when non-empty |
| Recommended for | Buckets provisioned with explicit access keys, such as the legacy csv-import bucket |
Spryker-managed asset, import/export, and self-service buckets, where it is required |
Both plugins can be registered side by side. The sprykerAdapterClass value of each filesystem entry decides which plugin builds that filesystem, so different filesystems can use different credential strategies at the same time. Switching an existing filesystem from one plugin to the other is not a breaking change, and nothing is migrated automatically.
On Spryker-managed environments, the asset, import/export, and self-service buckets authenticate exclusively through the IAM role attached to the workload. Access keys are not supported for these buckets, so they must use IamAws3v3FilesystemBuilderPlugin. Use Aws3v3FilesystemBuilderPlugin only for buckets that are provisioned with explicit access keys, such as the legacy csv-import bucket.
IamAws3v3FilesystemBuilderPlugin
Use IamAws3v3FilesystemBuilderPlugin when the runtime—an ECS task or EC2 instance—carries an IAM role that grants access to the target bucket. The plugin does not pass a credentials entry to the S3 client, so the AWS SDK falls back to its default credential provider chain: environment variables (AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY), the shared credentials and config files, ECS container credentials, and finally EC2 instance metadata (IMDS).
This is the recommended option for Spryker-managed (PaaS) environments, where storing long-lived key and secret pairs in the container is undesirable. It is used, for example, for the public-media buckets that store Back Office, Storefront, and Merchant Portal media, and for the Product Experience Management import and export filesystems.
Adapter configuration reference
| PROPERTY | REQUIRED | DESCRIPTION |
|---|---|---|
bucket |
Yes | Target S3 bucket. A missing value throws NoBucketException. |
region |
Yes | AWS region of the bucket. |
path |
No | Path prefix inside the bucket. Defaults to an empty string. |
endpoint |
No | Custom endpoint for S3-compatible storage such as MinIO or LocalStack. Applied only when non-empty. |
isStreamReads |
No | Whether reads are streamed. Defaults to false. |
key, secret |
Ignored | Not read by this plugin. Credentials come from the IAM role or the AWS SDK credential chain. |
Because IamAws3v3FilesystemBuilderPlugin ignores key and secret, you do not need to set them for filesystems that use this plugin. If they are present, they have no effect.
Configuration example
config/Shared/config_default.php
use Spryker\Service\FlysystemAws3v3FileSystem\Plugin\Flysystem\IamAws3v3FilesystemBuilderPlugin;
use Spryker\Shared\FileSystem\FileSystemConstants;
$config[FileSystemConstants::FILESYSTEM_SERVICE] = [
// ... existing entries ...
'backoffice-media' => [
'sprykerAdapterClass' => IamAws3v3FilesystemBuilderPlugin::class,
'bucket' => getenv('SPRYKER_S3_PUBLIC_ASSETS_BUCKET') ?: '',
'region' => getenv('AWS_REGION') ?: '',
'path' => '/backoffice-media',
],
];
Registration
Register the plugin in \Pyz\Service\Flysystem\FlysystemDependencyProvider::getFilesystemBuilderPluginCollection() next to the other builder plugins:
protected function getFilesystemBuilderPluginCollection(): array
{
return [
new FtpFilesystemBuilderPlugin(),
new LocalFilesystemBuilderPlugin(),
new Aws3v3FilesystemBuilderPlugin(),
new IamAws3v3FilesystemBuilderPlugin(),
];
}
Local development
For local development, set the endpoint option to point at an S3-compatible service such as MinIO or LocalStack. Alternatively, use LocalFilesystemBuilderPlugin when no bucket is configured.
Aws3v3FilesystemBuilderPlugin
Use Aws3v3FilesystemBuilderPlugin for buckets provisioned with explicit access keys, such as the legacy csv-import bucket. The plugin reads key and secret from the adapter config and passes them to the S3 client as static credentials. Do not use it for the Spryker-managed asset, import/export, and self-service buckets, which require IamAws3v3FilesystemBuilderPlugin.
Configuration example
config/Shared/config_default.php
use Spryker\Service\FlysystemAws3v3FileSystem\Plugin\Flysystem\Aws3v3FilesystemBuilderPlugin;
use Spryker\Shared\FileSystem\FileSystemConstants;
$config[FileSystemConstants::FILESYSTEM_SERVICE] = [
// ... existing entries ...
'backoffice-media' => [
'sprykerAdapterClass' => Aws3v3FilesystemBuilderPlugin::class,
'key' => getenv('SPRYKER_S3_PUBLIC_ASSETS_KEY') ?: '',
'secret' => getenv('SPRYKER_S3_PUBLIC_ASSETS_SECRET') ?: '',
'bucket' => getenv('SPRYKER_S3_PUBLIC_ASSETS_BUCKET') ?: '',
'region' => getenv('AWS_REGION') ?: '',
'path' => '/backoffice-media',
],
];
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