sajad torkamani

Install dependencies

Install aws/aws-sdk-php:

composer require aws/aws-sdk-php

Install vich/uploader-bundle:

composer require vich/uploader-bundle

Install league/flysystem:

composer require league/flysystem

Install league/flysystem-aws-s3-v3:

composer require league/flysystem-aws-s3-v3

Configure S3 bucket on AWS

Create an S3 bucket on the AWS console.

Create an IAM user with access to that bucket by assigning it the following policy:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:ListBucket",
                "s3:GetObject",
                "s3:DeleteObject",
                "s3:GetObjectAcl",
                "s3:PutObjectAcl",
                "s3:PutObject"
            ],
            "Resource": [
                "arn:aws:s3:::<your-s3-bucket-name>",
                "arn:aws:s3:::<your-s3-bucket-name>/*"
            ]
        }
    ]
}

Create an access key to obtain an access key and secret. You’ll use this to authenticate your Symfony app with AWS.

Configure S3 bucket on AWS

Configure your Aws\S3\S3Client service

Add the following entry under the services key in config/services.yaml:

    Aws\S3\S3Client:
        arguments:
            -
                version: 'latest'
                region: 'eu-west-2'
                credentials:
                    key: '%env(AWS_S3_ACCESS_KEY)%'
                    secret: '%env(AWS_S3_ACCESS_SECRET)%'

Replace region, credentials.key and credentials.secrets with the values that make sense for your application.

Configure flysystem S3 storage

Edit config/packages/flysystem.yaml to something like the below:

# Read the documentation at https://github.com/thephpleague/flysystem-bundle/blob/master/docs/1-getting-started.md
flysystem:
  storages:
    default.storage:
      adapter: 'local'
      options:
        directory: '%kernel.project_dir%/var/storage/default'

    s3_public.storage:
      adapter: 'aws'
      visibility: public
      options:
        client: Aws\S3\S3Client
        bucket: '%env(AWS_S3_BUCKET)%'

Configure VichUploader to use S3 storage

vich_uploader:
    db_driver: orm
    storage: flysystem
    metadata:
        type: attribute

    mappings:
        media_object:
            uri_prefix: ''
            upload_destination: 's3_public.storage'
            # Will rename uploaded files using a uniqueid as a suffix.
            namer: Vich\UploaderBundle\Naming\SmartUniqueNamer

Upload file to S3

To test things work ok, create a dev-only debugging route

  • add example debug controller method
<?php

declare(strict_types=1);

namespace App\Controller;

use Aws\S3\S3Client;
use League\Flysystem\FilesystemOperator;
use League\Flysystem\StorageAttributes;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\Routing\Attribute\Route;

class DebugController extends AbstractController
{
    public function __construct(
        private readonly ParameterBagInterface $parameterBag,
        private readonly FilesystemOperator $defaultStorage,
        private readonly FilesystemOperator $s3PublicStorage,
    ) {}

    #[Route('/debug/s3-client', condition: '"%kernel.environment%" === "dev"')]
    public function s3Client(): void
    {
        $s3Client = new S3Client([
            'credentials' => [
                'key'    => $this->parameterBag->get('app.aws_s3_access_key'),
                'secret' => $this->parameterBag->get('app.aws_s3_access_secret'),
            ],
            'region'      => 'eu-west-2',
            'version'     => 'latest'
        ]);

        $buckets = $s3Client->listBuckets()->toArray()['Buckets'];

        dd($buckets);
    }

    #[Route('/debug/flysystem', condition: '"%kernel.environment%" === "dev"')]
    public function flysystem(): void
    {
        $this->defaultStorage->write('example.txt', 'Example file...');

        $filePaths = $this->defaultStorage->listContents('/')
            ->filter(fn(StorageAttributes $attributes) => $attributes->isFile())
            ->map(fn(StorageAttributes $attributes) => $attributes->path())
            ->toArray();

        dd($filePaths);
    }

    #[Route('/debug/flysystem-s3', condition: '"%kernel.environment%" === "dev"')]
    public function flysystemS3(): void
    {
        // Upload a file to S3
        $this->s3PublicStorage->write('example1.txt', 'Example file...');

        // Check that it exists
        $filePaths = $this->s3PublicStorage->listContents('/')
            ->filter(fn(StorageAttributes $attributes) => $attributes->isFile())
            ->map(fn(StorageAttributes $attributes) => $attributes->path())
            ->toArray();

        dd($filePaths);
    }
}

Visit your application’s /debug/flysystem-s3 route and if all is working ok, you should see this:

And when viewing the S3 bucket’s contents on AWS, you should see example1.txt:

Setup flysystem for tests

See here.

Links