I’m migrating a legacy PHP application to Symfony, and that includes implementing file uploads to AWS S3. Symfony does not provide this feature out of the box, and many of the existing tutorials are outdated or do not work well, therefore I decided to document this in the hope that it will be useful to someone else.
To implement this, we will need to install four packages:
aws/aws-sdk-php: the AWS PHP SDK.
oneup/flysystem-bundle: a bundle for Flysystem (
league/flysystem), a filesystem abstraction library.
league/flysystem-aws-s3-v3: a Flysystem adapter for AWS SDK.
vich/uploader-bundle: a bundle that eases file uploads that are attached to ORM entities.
These packages can be easily installed with Composer:
Next, we need to add to
AppKernel.php our newly installed bundles:
Now, we will start setting up the bundles on the configuration file
First, we will setup the Flysystem bundle. This bundle will expose a set of adapters and filesystems for the application to use. The configuration below creates an adapter called
assets_adapter and a filesystem called
assets_fs, which in turn uses the adapter
assets_adapter. The built-in
awss3v3 Flysystem adapter takes two arguments: a service that’s nothing more than an instance of the AWS S3 SDK and the AWS bucket name (in this case, from the
parameters.yml variable called
Next, we will setup the
VichUploaderBundle. The configuration below tells
VichUploaderBundle to use the
orm driver, which integrates with Doctrine, and to use the Flysystem storage adapter. It also creates a mapping, which will be hooked into our entity. A mapping tells
VichUploaderBundle where to upload a file, how to generate its URI, and what naming strategy to use. In this case, we are supplying a user defined URI prefix, which is the S3 bucket URI (it’s defined in
parameters.yml); we are telling it to upload the file the the
assets_fs filesystem; and we are telling it to use the naming strategy that generates unique IDs for each file.
app/services.yml, we will create the AWS S3 service that will be used to upload the files to S3. The configuration below defines a service named
app.assets.s3 that is an instance of the
Aws\S3\S3Client class, which takes the arguments defined below. These arguments are best stored in the
Good! Now it’s time to plug everything into our model.
Let us suppose we have an entity called
Product, which represents a… product, ta-da! First, we will start by adding the
@Vich\Uploadable annotation to the class, which allows it to upload the files. Then, we will add two properties:
$image, which represents an image that was uploaded, and
$imageFile, which represents a image that may be uploaded. Finally, we will also add a few setters and getters. The complete class can be seen below:
Note that the
$imageFile property has the following annotation:
This annotation tells
VichUploaderBundle to upload the file using the
assets mapping we defined earlier, and to use the
$image property to hold the details of the uploaded file.
Now, how do we upload an image? We add an image field to the product creation form.
VichUploaderBundle provides a special form type
VichImageType that automatically handles the file download, file preview and deletion. We simply add it to our form and use the
$imageFile property - remember, this is the property that handles the image upload.
What about our controller? What do we need to change? Fortunately, we don’t need to change anything:
VichUploaderBundle is well implemented, and uploading is done behind the scenes when the forms are processed.
That’s all. You’re ready to start uploading. ;)
You probably do not want to upload your files to S3 on your development and test environments (maybe you do, but that’s not very smart, lol). You can get over this by using a local filesystem on dev and a in-memory filesystem on test.
I used to have Disqus enabled on my website, but I have disabled it because of privacy concerns.
If you feel like commenting or asking something, you can still contact me via other means.