Symfony Quickstart
Learn how to use Symfony with Rabata.io for managing your object storage using the AWS SDK for PHP.
Installation
To use Rabata.io with Symfony, you’ll need to install the AWS SDK for PHP and configure Symfony to work with it.
Install AWS SDK and Flysystem Bundle
$ composer require aws/aws-sdk-php
$ composer require league/flysystem-bundle
Create a Symfony Project (Optional)
If you’re starting from scratch, you can create a new Symfony project:
$ symfony new my-rabata-symfony-app --full
$ cd my-rabata-symfony-app
$ composer require aws/aws-sdk-php
$ composer require league/flysystem-bundle
Configuration
There are several ways to configure Symfony to work with Rabata.io.
Method 1: Using Flysystem Bundle
The Flysystem Bundle provides a convenient way to work with various file systems in Symfony. You can configure it to work with Rabata.io.
First, create the configuration file at config/packages/flysystem.yaml:
flysystem:
storages:
rabata.storage:
adapter: 'aws'
options:
client: 'rabata.client'
bucket: '%env(RABATA_BUCKET)%'
prefix: '%env(default::RABATA_PREFIX)%'
Then, create a service for the AWS S3 client in config/services.yaml:
services:
rabata.client:
class: Aws\S3\S3Client
arguments:
-
version: 'latest'
region: '%env(RABATA_REGION)%'
endpoint: '%env(RABATA_ENDPOINT)%'
credentials:
key: '%env(RABATA_ACCESS_KEY)%'
secret: '%env(RABATA_SECRET_KEY)%'
use_path_style_endpoint: true
Finally, add the environment variables to your .env file:
RABATA_ACCESS_KEY=YOUR_ACCESS_KEY
RABATA_SECRET_KEY=YOUR_SECRET_KEY
RABATA_REGION=eu-west-1
RABATA_BUCKET=your-bucket-name
RABATA_ENDPOINT=https://s3.eu-west-1.rabata.io
RABATA_PREFIX=
Method 2: Using Symfony’s Service Container Directly
You can also configure the AWS S3 client directly in your service container:
# config/services.yaml
services:
Aws\S3\S3Client:
arguments:
-
version: 'latest'
region: '%env(AWS_REGION)%'
endpoint: '%env(AWS_ENDPOINT)%'
credentials:
key: '%env(AWS_ACCESS_KEY)%'
secret: '%env(AWS_SECRET_KEY)%'
use_path_style_endpoint: true
Basic Operations
Here are some common operations you can perform with Symfony and Rabata.io.
Using Flysystem in a Controller
Upload a File
<?php
namespace App\Controller;
use League\Flysystem\FilesystemOperator;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
class FileController extends AbstractController
{
#[Route('/upload', name: 'upload_file', methods: ['POST'])]
public function upload(Request $request, FilesystemOperator $rabataStorage): Response
{
$file = $request->files->get('file');
if (!$file) {
return $this->json(['error' => 'No file uploaded'], 400);
}
$filename = md5(uniqid()) . '.' . $file->getClientOriginalExtension();
$stream = fopen($file->getRealPath(), 'r');
$rabataStorage->writeStream($filename, $stream);
if (is_resource($stream)) {
fclose($stream);
}
return $this->json([
'success' => true,
'filename' => $filename,
]);
}
}
Download a File
#[Route('/download/{filename}', name: 'download_file', methods: ['GET'])]
public function download(string $filename, FilesystemOperator $rabataStorage): Response
{
if (!$rabataStorage->fileExists($filename)) {
throw $this->createNotFoundException('File not found');
}
$stream = $rabataStorage->readStream($filename);
$response = new Response(stream_get_contents($stream));
if (is_resource($stream)) {
fclose($stream);
}
$response->headers->set('Content-Type', $rabataStorage->mimeType($filename));
$response->headers->set('Content-Disposition', 'attachment; filename="' . $filename . '"');
return $response;
}
List Files
#[Route('/files', name: 'list_files', methods: ['GET'])]
public function listFiles(FilesystemOperator $rabataStorage): Response
{
$contents = $rabataStorage->listContents('', true)
->filter(fn ($item) => $item['type'] === 'file')
->map(fn ($item) => [
'path' => $item['path'],
'size' => $item['fileSize'],
'lastModified' => $item['lastModified'],
])
->toArray();
return $this->json($contents);
}
Delete a File
#[Route('/delete/{filename}', name: 'delete_file', methods: ['DELETE'])]
public function delete(string $filename, FilesystemOperator $rabataStorage): Response
{
if (!$rabataStorage->fileExists($filename)) {
throw $this->createNotFoundException('File not found');
}
$rabataStorage->delete($filename);
return $this->json(['success' => true]);
}
Using S3Client Directly
If you prefer to use the AWS SDK directly, you can inject the S3Client into your services:
<?php
namespace App\Service;
use Aws\S3\S3Client;
class FileManager
{
private $s3Client;
private $bucket;
public function __construct(S3Client $s3Client, string $bucket)
{
$this->s3Client = $s3Client;
$this->bucket = $bucket;
}
public function uploadFile(string $localPath, string $key): string
{
$result = $this->s3Client->putObject([
'Bucket' => $this->bucket,
'Key' => $key,
'SourceFile' => $localPath,
]);
return $result['ObjectURL'];
}
public function downloadFile(string $key, string $localPath): void
{
$this->s3Client->getObject([
'Bucket' => $this->bucket,
'Key' => $key,
'SaveAs' => $localPath,
]);
}
public function listFiles(string $prefix = ''): array
{
$result = $this->s3Client->listObjectsV2([
'Bucket' => $this->bucket,
'Prefix' => $prefix,
]);
return $result['Contents'] ?? [];
}
public function deleteFile(string $key): void
{
$this->s3Client->deleteObject([
'Bucket' => $this->bucket,
'Key' => $key,
]);
}
}
Advanced Operations
Here are some more advanced operations you can perform with Symfony and Rabata.io.
Creating a File Upload Form
You can create a form type for file uploads:
<?php
namespace App\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\FileType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Validator\Constraints\File;
class FileUploadType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('file', FileType::class, [
'label' => 'File to upload',
'constraints' => [
new File([
'maxSize' => '10M',
]),
],
])
->add('submit', SubmitType::class, [
'label' => 'Upload',
]);
}
}
Then use it in a controller:
#[Route('/upload-form', name: 'upload_form')]
public function uploadForm(Request $request, FilesystemOperator $rabataStorage): Response
{
$form = $this->createForm(FileUploadType::class);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$file = $form->get('file')->getData();
$filename = md5(uniqid()) . '.' . $file->getClientOriginalExtension();
$stream = fopen($file->getRealPath(), 'r');
$rabataStorage->writeStream($filename, $stream);
if (is_resource($stream)) {
fclose($stream);
}
$this->addFlash('success', 'File uploaded successfully');
return $this->redirectToRoute('upload_form');
}
return $this->render('file/upload.html.twig', [
'form' => $form->createView(),
]);
}
Using Presigned URLs
You can generate presigned URLs to allow temporary access to files:
<?php
namespace App\Service;
use Aws\S3\S3Client;
class PresignedUrlGenerator
{
private $s3Client;
private $bucket;
public function __construct(S3Client $s3Client, string $bucket)
{
$this->s3Client = $s3Client;
$this->bucket = $bucket;
}
public function generatePresignedUrl(string $key, int $expiresIn = 3600): string
{
$command = $this->s3Client->getCommand('GetObject', [
'Bucket' => $this->bucket,
'Key' => $key,
]);
$request = $this->s3Client->createPresignedRequest($command, "+{$expiresIn} seconds");
return (string) $request->getUri();
}
}
Using Symfony Messenger for Asynchronous File Processing
For handling large file uploads or processing, you can use Symfony Messenger:
<?php
namespace App\Message;
class ProcessFile
{
private $filename;
public function __construct(string $filename)
{
$this->filename = $filename;
}
public function getFilename(): string
{
return $this->filename;
}
}
<?php
namespace App\MessageHandler;
use App\Message\ProcessFile;
use League\Flysystem\FilesystemOperator;
use Symfony\Component\Messenger\Handler\MessageHandlerInterface;
class ProcessFileHandler implements MessageHandlerInterface
{
private $rabataStorage;
public function __construct(FilesystemOperator $rabataStorage)
{
$this->rabataStorage = $rabataStorage;
}
public function __invoke(ProcessFile $message)
{
$filename = $message->getFilename();
if (!$this->rabataStorage->fileExists($filename)) {
return;
}
$content = $this->rabataStorage->read($filename);
// Process the file content
$processedContent = $this->processContent($content);
// Save the processed file
$this->rabataStorage->write("processed/{$filename}", $processedContent);
}
private function processContent(string $content): string
{
// Your processing logic here
return $content;
}
}