Symfony Quickstart
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=us-east-1
RABATA_BUCKET=your-bucket-name
RABATA_ENDPOINT=https://s3.us-east-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;
}
}