Search code examples
phpsymfonyamazon-s3pre-signed-urlvichuploaderbundle

Use S3 presigned URL with VichUploader


I am able to use the PHP Symfony bundle Vich-Uploader to upload files to a private bucket in Amazon S3, via the php sdk Flysystem adapter.

How can I get a signed/presigned URL for a key, after the upload?

I can load the plugin into Flysystem, but Vich won't use the $filesystem->getPresignedUrl('/tmp/some/target') method.

Is this supported by the bundle in any way? Or what class should be extended and registered in order to call the presignedURL method correctly?


Solution

  • There is not a direct way into VichUploader, but it is possible to tell Symfony to use a custom Storage and add the plugin logic inside there.

    Install presigned-URLs plugin for Flysystem

    composer require sistemi-etime/flysystem-plugin-aws-s3-v3
    

    Use the plugin with the Flysystem, via the bundle oneup_flysystem.yaml config:

    oneup_flysystem:
        filesystems:
            aws_s3:
                ...
                ...
                plugins:
                    - s3.plugin.presigned_url
    

    Define your own Storage

    <?php
    
    use Vich\UploaderBundle\Storage\FlysystemStorage;
    
    class CustomFlysystemStorage extends FlysystemStorage
    {
        // Copy the parent method code but then return the presigned URL
        public function resolveUri($obj, ?string $fieldName = null, ?string $className = null)
        {
            [$mapping, $filename] = $this->getFilename($obj, $fieldName, $className);
    
            if (empty($filename)) {
                return null;
            }
    
            $dir = $mapping->getUploadDir($obj);
            $path = !empty($dir) ? $dir.'/'.$filename : $filename;
    
            $fs = $this->getFilesystem($mapping, $obj, $fieldName, $className);
    
            return $fs->getPresignedUrl($path);
        }
    }
    

    Make use of it inside services.yaml:

    # alias the custom storage to be used instead of the one defined by VichUploader
    vich_uploader.storage.flysystem: '@Your\Own\Namespace\CustomFlysystemStorage'
    

    Fix autowiring (why? 🤷‍♂️)

    [Edit: that's why]

    Additionally I had to explicitly alias the arguments required by the FlysystemStorage in order for Symfony Autowire to initialise the custom storage:

    Vich\UploaderBundle\Mapping\PropertyMappingFactory: '@vich_uploader.property_mapping_factory'
    League\Flysystem\MountManager: '@oneup_flysystem.mount_manager'
    

    Although I am not sure why this was necessary.

    I would expect that either vich_uploader.property_mapping_factory and oneup_flysystem.mount_manager are already defined and aliased by the configs from VichUploaderBundle and OneupFlysystemBundle

    If anybody knows how to skip this fix, please comment.