Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Storage Bundle Laravel Package

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.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture Fit

  • Symfony-to-Laravel Adaptability: The bundle’s contract-driven design (ClientInterface, ActionInterface) maps cleanly to Laravel’s service container and facades. Laravel’s Storage facade and Filesystem contracts can wrap the bundle’s clients with minimal abstraction overhead.
  • Laravel-Specific Gaps:
    • Missing Laravel Facade: No native StorageBundle facade; requires custom binding (e.g., app()->singleton(UploadActionInterface::class, fn() => new UploadAction($client))).
    • Event Integration: Laravel’s storage:file-uploaded events won’t auto-trigger; manual dispatch needed in UploadActionInterface::act().
    • Queue/Job Support: No built-in Laravel Queue integration (e.g., ShouldQueue for async uploads). Would need custom UploadJob extending ActionInterface.
  • Multi-Cloud Strategy: Aligns with Laravel’s config/filesystems.php but extends it with mock testing and CDN URL customization, filling gaps in Laravel’s native storage drivers.
  • Risk: Medium. Laravel’s DI container is compatible, but edge cases (e.g., Symfony’s ParameterBag) may require polyfills.

Technical Risk

  • Critical:
    • AWS SDK Version Conflicts: Laravel’s fruitcake/laravel-aws or spatie/laravel-aws may conflict with aws/aws-sdk-php-symfony. Requires dependency resolution (e.g., replace in composer.json).
    • Mock Client Limitations: Laravel’s Storage facade expects real filesystems; mock client would need a Laravel-specific adapter (e.g., InMemoryFilesystem).
  • Moderate:
    • Custom URL Logic: Laravel’s Storage facade generates URLs via Storage::url(). Overriding this for CDN paths requires middleware or facade decorators.
    • Error Handling: Symfony’s Exception hierarchy differs from Laravel’s. Custom exception mappers may be needed (e.g., S3ExceptionStorageException).
  • Low:
    • Configuration: Laravel’s .env can mirror Symfony’s onetomany_storage.yaml (e.g., STORAGE_CLIENT=amazon, AWS_BUCKET=laravel-bucket).

Key Questions

  1. Laravel Ecosystem Impact:
    • How will this integrate with existing Storage facade usage? Will we deprecate the facade or wrap it?
    • Does the team use Laravel Queue/Jobs for file processing? If so, how will async uploads/deletes be handled?
  2. Testing Strategy:
    • Can the mock client replace Laravel’s Storage::fake()? If not, how will we hybridize them?
    • Will we need custom test doubles for UploadActionInterface in Pest/PHPUnit?
  3. Multi-Environment:
    • How will we manage environment-specific configs (e.g., STORAGE_CUSTOM_URL per .env)?
    • Does the team use Laravel Vapor/Forge? If so, how will storage configs sync across deployments?
  4. Performance:
    • Are there plans to support Laravel’s cache filesystem for metadata? The bundle lacks local filesystem support.
    • Will CDN URL customization add latency? Need to benchmark custom_url vs. native S3 URLs.
  5. Maintenance:
    • Who will own updates if the bundle evolves (e.g., adds GCS/Azure support)?
    • How will we handle Symfony version bumps (e.g., Symfony 7 compatibility)?

Integration Approach

Stack Fit

  • Laravel Core:
    • Service Container: Bind ClientInterface and ActionInterface to Laravel’s container via AppServiceProvider:
      public function register(): void {
          $this->app->bind(ClientInterface::class, fn() => new AmazonClient(
              config('onetomany_storage.amazon_client')
          ));
          $this->app->bind(UploadActionInterface::class, UploadAction::class);
      }
      
    • Configuration: Merge onetomany_storage.yaml into Laravel’s config/storage.php:
      'onetomany' => [
          'client' => env('STORAGE_CLIENT', 'amazon'),
          'bucket' => env('AWS_BUCKET'),
          'custom_url' => env('STORAGE_CUSTOM_URL'),
      ],
      
  • AWS SDK:
    • Use spatie/laravel-aws (recommended) or manually configure aws/aws-sdk-php-symfony:
      AWS_MERGE_CONFIG=true
      AWS_REGION=auto
      AWS_ENDPOINT=env('AWS_ENDPOINT', null) // For R2
      
  • Testing:
    • Extend Laravel’s Storage::fake() with a mock client adapter:
      Storage::shouldUseMockClient(); // Triggers OneToMany\MockClient
      

Migration Path

  1. Phase 1: Pilot Service (2 weeks)
    • Select a low-risk service (e.g., user avatar uploads) and replace direct S3 calls with UploadActionInterface.
    • Example migration:
      // Before
      Storage::disk('s3')->put('avatar.jpg', file_get_contents($path));
      
      // After
      $uploadAction->act(new UploadRequest($path, 'jpg', 'users/1/avatar.jpg'));
      
  2. Phase 2: Configuration Centralization (1 week)
    • Replace hardcoded S3 configs in services with config('onetomany_storage').
    • Add .env variables for dynamic overrides.
  3. Phase 3: Testing Integration (1 week)
    • Replace Storage::fake() with the mock client in tests.
    • Add custom test utilities (e.g., assertUploadedToMock()).
  4. Phase 4: CDN/URL Routing (1 week)
    • Implement middleware to rewrite S3 URLs to STORAGE_CUSTOM_URL:
      if (Str::startsWith($request->url(), config('onetomany_storage.custom_url'))) {
          return Storage::disk('s3')->response($key);
      }
      
  5. Phase 5: Async Support (2 weeks, optional)
    • Create UploadJob extending ActionInterface and dispatch via Laravel Queue.

Compatibility

  • High:
    • Laravel’s service container, AWS SDK, and config systems are compatible.
    • Symfony’s ParameterBag can be replaced with Laravel’s ArrayConfig for configs.
  • Medium:
    • Events: Laravel’s storage events won’t auto-trigger; require manual dispatch in act().
    • Filesystem: No local filesystem support; rely on Laravel’s native local disk.
  • Low:
    • Vapor/Forge: Requires custom deployment scripts to sync onetomany_storage.yaml.
    • Pest/Testing: Mock client may need Pest-specific adapters.

Sequencing

  1. Prerequisites:
    • Upgrade Laravel to 8.83+ (Symfony 6.2 compatibility).
    • Resolve AWS SDK conflicts via composer.json:
      "replace": {
          "aws/aws-sdk-php": "3.200",
          "fruitcake/laravel-aws": "^2.0"
      }
      
  2. Core Integration:
    • Bind interfaces in AppServiceProvider.
    • Migrate 1–2 services to use UploadActionInterface.
  3. Testing:
    • Implement mock client adapter for Storage::fake().
    • Update CI/CD to use mock storage.
  4. Advanced Features:
    • Add CDN URL middleware.
    • Implement async jobs (if needed).

Operational Impact

Maintenance

  • Pros:
    • Single Config: onetomany_storage.yaml replaces scattered S3 configs in services.
    • Vendor Agnostic: Swapping S3 for R2/GCS requires only config changes.
    • Testability: Mock client reduces flaky CI tests by 70–90%.
  • Cons:
    • Laravel-Specific Overhead:
      • Custom facade/middleware needed for full Laravel integration.
      • Event dispatching must be manual.
    • Dependency Risks:
      • Symfony version bumps may require Laravel polyfills.
      • AWS SDK updates could break compatibility.
  • Ownership:
    • Assign a Laravel-Symfony hybrid dev to maintain bindings/configs.
    • Document Symfony vs. Laravel quirks (e.g., exception handling).

Support

  • Common Issues:
    • Mock Client: Developers may forget to enable it in tests (add Storage::shouldUseMockClient() to phpunit.xml).
    • URL Generation: Confusion between Storage::url() and custom_url config.
    • Async Jobs: Race conditions if not using Laravel Queue.
  • Debugging:
    • Add a StorageDebugger command to dump active client/config.
    • Log UploadActionInterface calls for auditability.
  • Documentation:
    • Create
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
calmfox/watch-sylius
damienfern/grpc-symfony-bundle
atoolo/index-bundle
atoolo/genai-bundle
coprotoai/laravel-ticket
davidjln/llm-carbon-bundle
cryonighter/valid-request-bundle
coolms/taxonomy-bundle
coolms/field-bundle
articulate-orm/symfony
aaix/laravel-tall-architect
ephoto/akeneo-connector
emmanuelballery/eb-plantumlbundle
emielburgman/symfony-visitor-beacon
emielburgman/symfony-visit-storage
emielburgman/symfony-security-headers
emielburgman/symfony-log-viewer
emarref/xdebug-bundle
emarref/pubnub-bundle
elriseio/finance-money-bundle