Use flysystem with Cloudcube on Heroku
Recently I switched from a project from an usual hoster to Heroku. For the file storage we decided to use Cloudcube (because it includes a free tier we use for review apps). For the file abstraction layer we use flysystem with the flysystem bundle for Symfony integration.
Unfortunately the environment variables we get through Heroku aren't a perfect match for what we need in the flysystem configuration. We get CLOUDCUBE_ACCESS_KEY_ID
, CLOUDCUBE_SECRET_ACCESS_KEY
and CLOUDCUBE_URL
. For the configuration we would also need the prefix
which is already part of the Cloudcube url. As it's generated for every review app, we can't just put it in a custom environment variable. So we pull it out through an expression. For this we need the package symfony/expression-language
installed through composer.
services:
Aws\S3\S3Client:
arguments:
- version: '2006-03-01'
region: 'eu-west-1'
endpoint: '%env(CLOUDCUBE_URL)%'
credentials:
key: '%env(CLOUDCUBE_ACCESS_KEY_ID)%'
secret: '%env(CLOUDCUBE_SECRET_ACCESS_KEY)%'
flysystem:
storages:
aws.storage:
adapter: 'aws'
options:
client: 'Aws\S3\S3Client'
bucket: '' # No bucket as it's already part of the url
# Pull the prefix (last part after ..com/) out of an url like: https://cloud-cube-eu.s3.amazonaws.com/v14wxz3uwp2n
# Locally we have set the url to `` which will also return `` as we don't need it locally
prefix: "@=preg_match('([^\/]+$)', %env(CLOUDCUBE_URL)%)"
This is everything needed to use flysystem to store files on Amazon S3.
But for local development and testing we don't want to store our files on S3, so we use the lazy
adapter to switch to a local
adapter. This is the final flysystem.yaml
:
services:
Aws\S3\S3Client:
arguments:
- version: '2006-03-01'
region: 'eu-west-1'
endpoint: '%env(CLOUDCUBE_URL)%'
credentials:
key: '%env(CLOUDCUBE_ACCESS_KEY_ID)%'
secret: '%env(CLOUDCUBE_SECRET_ACCESS_KEY)%'
flysystem:
storages:
aws.storage:
adapter: 'aws'
options:
client: 'Aws\S3\S3Client'
bucket: '' # No bucket as it's already part of the url
# Pull the prefix (last part after ..com/) out of an url like: https://cloud-cube-eu.s3.amazonaws.com/v14wxz3uwp2n
# Locally we have set the url to `` which will also return `` as we don't need it locally
prefix: "@=preg_match('([^\/]+$)', %env(CLOUDCUBE_URL)%)"
local.storage:
adapter: 'local'
options:
directory: '%kernel.project_dir%/var/storage'
default.storage:
adapter: 'lazy'
options:
source: '%env(APP_STORAGE)%'
APP_STORAGE
can now have two parameters: aws.storage
or local.storage
. Switching between them is as simple as changing the environment variable.
In a Symfony service you can use dependency injection to inject the configured storage by using FilesystemInterface $defaultStorage
like this:
private FilesystemInterface $filesystem;
public function __construct(FilesystemInterface $defaultStorage)
{
$this->filesystem = $defaultStorage;
}
This technique is taken from the flysystem bundle documentation.