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

cesurapp/storage-bundle

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation:

    composer require cesurapp/storage-bundle
    

    Note: Requires Symfony 8+ and PHP 8.4+. For Laravel, use a wrapper service provider (see Implementation Patterns).

  2. Configuration: Create config/storage.yaml (or adapt to Laravel’s config/filesystems.php):

    storage:
      default: main
      devices:
        local:
          driver: local
          root: "%kernel.project_dir%/storage/files"
        main:
          driver: cloudflare
          root: /
          accessKey: "%env(STORAGE_CLOUDFLARE_KEY)%"
          secretKey: "%env(STORAGE_CLOUDFLARE_SECRET)%"
          bucket: "%env(STORAGE_BUCKET)%"
          endPoint: "%env(STORAGE_ENDPOINT)%"
    
  3. First Use Case: Inject the Storage service into a controller or command:

    use Cesurapp\StorageBundle\Storage\Storage;
    
    class UploadController {
        public function __construct(private Storage $storage) {}
    
        public function handle() {
            $this->storage->upload(
                '/tmp/image.jpg',
                'uploads/user123/image.jpg'
            );
            $url = $this->storage->getUrl('uploads/user123/image.jpg');
            return response()->json(['url' => $url]);
        }
    }
    
  4. Laravel Adaptation: Create a service provider to bridge Symfony’s Storage to Laravel’s FilesystemManager:

    // app/Providers/StorageBundleServiceProvider.php
    public function register() {
        $this->app->singleton('storage', function ($app) {
            $config = $app['config']['storage'];
            return new \Cesurapp\StorageBundle\Storage\StorageManager($config);
        });
    }
    
    public function boot() {
        $this->app->extend('filesystem.disk', function ($disk, $app) {
            $storage = $app->make('storage');
            return new StorageBundleAdapter($storage->device($disk));
        });
    }
    

Implementation Patterns

Core Workflows

1. Multi-Provider File Operations

Use the device() method to switch contexts dynamically:

// Upload to Cloudflare R2 (default)
$storage->upload('/tmp/backup.zip', 'backups/2023.zip');

// Upload to BackBlaze B2
$storage->device('backblaze')->upload(
    '/tmp/backup.zip',
    'backups/2023-b2.zip'
);

2. Cloud-Specific Features

Leverage async operations and metadata for cloud providers:

// Upload with custom metadata (Cloudflare R2/BackBlaze)
$storage->upload(
    '/tmp/photo.jpg',
    'users/123/photo.jpg',
    [
        'ContentType' => 'image/jpeg',
        'Metadata' => ['user_id' => '123', 'tags' => 'profile'],
    ]
);

// Generate pre-signed URL (Cloudflare R2)
$client = $storage->device('main')->getClient();
$url = $client->getPresignedUrl(
    $storage->device('main')->getBucket(),
    'users/123/photo.jpg',
    new \DateTimeImmutable('+1 hour')
);

3. Local-Specific Operations

Use local driver methods for filesystem tasks:

$local = $storage->device('local');
$local->move('temp/file.pdf', 'documents/file.pdf');
$size = $local->getDirectorySize('users/123/');

4. Streaming and Chunking

Handle large files efficiently:

// Stream download (cloud)
foreach ($storage->downloadChunk('large-file.zip') as $chunk) {
    yield $chunk;
}

// Stream upload (Laravel HTTP request)
$request->file('file')->storeAs(
    'uploads',
    'large-file.zip',
    'custom' // Use the storage bundle disk
);

Integration Tips

Laravel-Specific Adaptations

  1. Filesystem Disk Integration: Extend Laravel’s FilesystemAdapter to wrap the bundle’s Storage:

    class StorageBundleAdapter implements FilesystemAdapter {
        public function __construct(private Storage $storage) {}
    
        public function writeStream($path, $contents) {
            $this->storage->writeStream($contents, $path);
        }
    
        public function read($path) {
            return $this->storage->download($path);
        }
    
        // Implement remaining FilesystemAdapter methods...
    }
    
  2. Configuration Sync: Convert storage.yaml to Laravel’s filesystems.php:

    // config/filesystems.php
    'disks' => [
        'local' => [
            'driver' => 'local',
            'root' => storage_path('app'),
        ],
        'cloudflare' => [
            'driver' => 'custom', // Alias for StorageBundleAdapter
            'storage' => 'main',  // Maps to storage.yaml's 'main' device
        ],
    ],
    
  3. Service Provider Binding: Bind the bundle’s Storage to Laravel’s container:

    public function register() {
        $this->app->singleton('storage', function ($app) {
            $config = $app['config']['storage'];
            return new \Cesurapp\StorageBundle\Storage\StorageManager(
                $config['devices'],
                $config['default']
            );
        });
    }
    

Performance Optimization

  • Async Uploads/Downloads: Use the bundle’s async S3 client for background jobs:

    // In a queue job
    $storage->device('main')->getClient()->upload(
        new UploadFile('/tmp/large-video.mp4'),
        'videos/large-video.mp4',
        ['ContentType' => 'video/mp4']
    );
    
  • Caching URLs: Cache pre-signed URLs (e.g., with Laravel’s cache):

    $url = cache()->remember("presigned_url:{$path}", now()->addHour(), function () use ($storage, $path) {
        return $storage->device('main')->getClient()->getPresignedUrl(...);
    });
    

Testing Strategies

  1. Local Driver Testing: Use Laravel’s Storage facade for local operations in tests:

    public function test_local_upload() {
        Storage::fake('local');
        Storage::disk('local')->put('test.txt', 'Hello');
        Storage::assertExists('test.txt');
    }
    
  2. Cloud Driver Mocking: Mock the Storage service for cloud operations:

    $storage = Mockery::mock(\Cesurapp\StorageBundle\Storage\Storage::class);
    $storage->shouldReceive('upload')->once();
    $this->app->instance('storage', $storage);
    
  3. Environment-Based Testing: Use Laravel’s .env.testing to switch providers:

    STORAGE_DEFAULT=local
    STORAGE_CLOUDFLARE_KEY=test_key
    

Gotchas and Tips

Pitfalls

  1. Symfony vs. Laravel DI:

    • Issue: The bundle assumes Symfony’s ContainerInterface. Laravel’s container requires explicit binding.
    • Fix: Use a service provider to wrap the bundle’s StorageManager (see Implementation Patterns).
  2. PHP 8.4 Features:

    • Issue: The bundle may use PHP 8.4’s typed class constants (e.g., BackBlaze::US_WEST_001). Laravel’s PHP 8.2+ support may cause deprecation warnings.
    • Fix: Check the bundle’s source for 8.4-specific code and polyfill or patch if needed.
  3. Async SDK Conflicts:

    • Issue: The bundle uses async-aws/s3, which may conflict with Laravel’s aws/aws-sdk-php.
    • Fix: Isolate the async client to specific services or use a hybrid adapter.
  4. Local Driver Path Handling:

    • Issue: Local driver paths are relative to root. Incorrect paths (e.g., absolute paths) may cause silent failures.
    • Fix: Normalize paths in Laravel’s FilesystemAdapter wrapper:
      $path = Str::replaceFirst($root, '', $path);
      
  5. Pre-Signed URL Expiry:

    • Issue: Cloud providers’ pre-signed URLs expire. Cache them aggressively or regenerate dynamically.
    • Fix: Use Laravel’s cache with a short TTL (e.g., 55 minutes for 1-hour expiry).
  6. Metadata Limitations:

    • Issue: Cloud drivers support metadata, but local drivers ignore it. Passing metadata to local uploads may fail silently.
    • Fix: Validate metadata before upload:
      if (!$storage->device()->supportsMetadata()) {
          $metadata = null;
      }
      
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.
terminal42/code-quality-tools
codifyo/ts-generator-bundle
andydefer/laravel-cluster
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity
christhompsontldr/laravel-inky