1tomany/storage-bundle
Symfony bundle for uploading files to remote storage (Amazon S3/R2, GCS, Azure) with a simple client-based config. Includes an Amazon S3-compatible client plus a mock client for fast, offline testing, and optional custom URLs for CDN/public buckets.
Pros:
ClientInterface, ActionInterface) mirrors Laravel’s service container patterns (e.g., Storage facade, Filesystem contracts).Uploading, Deleted events) or job queues (e.g., UploadFileJob).Cons:
UploadRequest to Laravel’s UploadedFile or SplFileInfo).app()->bind('uploadAction', fn() => app(UploadActionInterface::class))).FilesystemManager, Vapor, or Forge services.Laravel Compatibility:
aws/aws-sdk-php-symfony) are compatible with Laravel via symfony/flex or manual configuration.fruitcake/laravel-aws or spatie/laravel-aws can coexist if configured to share the same s3_client_service_id..env and config/services.php (see Laravel R2 docs).Key Integration Points:
config/app.php or a custom provider.onetomany_storage.yaml with Laravel’s config/filesystems.php (e.g., alias the bundle’s client to Laravel’s disks).UploadRequest to Laravel’s Request object (e.g., using Symfony\Component\HttpFoundation/FileBag).Medium:
symfony/http-foundation). Mitigate via composer.json overrides or Laravel’s config/extra.php.ClientInterface in Laravel’s PHPUnit tests requires custom test doubles (e.g., Mockery or Laravel\Pest\Mock).spatie/laravel-activitylog or laravel-debugbar.Mitigation:
ClientInterface to implement Laravel’s Filesystem contract for seamless integration.laravel-storage-bundle facade (e.g., Storage::disk('s3')->upload()).composer validate and phpstan checks for Symfony/Laravel compatibility.Does this replace or complement Laravel’s built-in Storage facade?
ClientInterface could unify them under a single facade.Storage is more mature for local filesystems (e.g., Filesystem::put()).How will we handle Laravel’s UploadedFile vs. Symfony’s UploadedFile?
SymfonyUploadedFileAdapter to bridge the two (see Laravel’s Illuminate\Http\File).What’s the fallback for unsupported Laravel features?
Filesystem::temporaryUrl() isn’t exposed. Implement a custom TemporaryUrlActionInterface.How will we manage secrets (AWS keys) in Laravel’s .env?
Vapor or Envoy for secret rotation, or integrate with spatie/laravel-envoy.Primary Use Cases:
Storage::put() for S3/R2 with the bundle’s UploadActionInterface (e.g., user avatars, documents).custom_url: "https://cdn.app.com").mock_client for unit/integration tests (e.g., Storage::fake() alternative).Laravel-Specific Adaptations:
| Bundle Feature | Laravel Equivalent | Integration Strategy |
|---|---|---|
UploadRequest |
Illuminate\Http\UploadedFile |
Create a LaravelUploadRequest adapter. |
ClientInterface |
Illuminate\Contracts\Filesystem |
Implement Filesystem contract in a wrapper. |
UploadActionInterface |
Storage::put() |
Bind to Laravel’s service container. |
| Mock client | Storage::fake() |
Extend bundle’s mock to support Laravel assertions. |
Phase 1: Proof of Concept (1–2 weeks)
composer require 1tomany/storage-bundle aws/aws-sdk-php-symfony
config/packages/onetomany_storage.yaml and .env for AWS/R2.Http\Testing\File:
use OneToMany\StorageBundle\Contract\Action\UploadActionInterface;
use Illuminate\Http\UploadedFile;
$uploadAction = app(UploadActionInterface::class);
$response = $uploadAction->act(new UploadRequest(
UploadedFile::fake()->image('avatar.png'),
'png',
'avatars/user1.png'
));
Phase 2: Laravel Wrapper (2–3 weeks)
LaravelStorageBundle facade:
// app/Providers/AppServiceProvider.php
public function register(): void
{
$this->app->bind('uploadAction', fn() => $this->app->make(UploadActionInterface::class));
Storage::extend('onetomany', fn() => new OnetomanyFilesystem(
$this->app->make(ClientInterface::class)
));
}
OnetomanyFilesystem extending Illuminate\Filesystem\Filesystem.Phase 3: Full Integration (3–4 weeks)
Storage::put() calls with the bundle’s actions:
// Before
Storage::disk('s3')->put('file.txt', $content);
// After
$uploadAction->act(new UploadRequest(
$filePath,
'txt',
'file.txt'
));
storage.uploaded) to trigger notifications or analytics.ClientInterface implementations (e.g., for Google Cloud Storage).spatie/laravel-medialibrary or intervention/image (use separate disks).spatie/laravel-activitylog to log storage actions.How can I help you explore Laravel packages today?