
## 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

```bash
$ 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:

```bash
$ 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`:

```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`:

```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:

```yaml
# 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
<?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

```php
#[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

```php
#[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

```php
#[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
<?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
<?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:

```php
#[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
<?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
<?php

namespace App\Message;

class ProcessFile
{
    private $filename;

    public function __construct(string $filename)
    {
        $this->filename = $filename;
    }

    public function getFilename(): string
    {
        return $this->filename;
    }
}
```

```php
<?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;
    }
}
```

<div class="docs-article__actions">
  <a href="/docs/quickstart/php/" class="btn btn--secondary">PHP Quickstart</a>
  <a href="/docs/quickstart/laravel/" class="btn btn--secondary">Laravel Integration</a>
</div>
