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

Files Res Laravel Package

baks-dev/files-res

Laravel/PHP пакет для управления файловыми ресурсами: загрузка и хранение в public/upload, настройка прав доступа, асинхронная обработка через очередь Messenger (async_files_resources). Поддерживает пережатие и конвертацию изображений в WebP через отдельный CDN-сервер.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation:

    composer require baks-dev/files-res
    

    Ensure PHP 8.4+ and Laravel/Symfony compatibility.

  2. Directory Setup:

    mkdir -p public/upload
    chown -R www-data:www-data public/upload  # Adjust user/group as needed
    
  3. Basic Upload Usage:

    use BaksDev\FilesRes\Facades\FileResource;
    
    $file = FileResource::upload('file.jpg', 'public/upload');
    $url = asset($file->getPath());
    
  4. Queue Setup (for async processing):

    php artisan queue:work --queue=resources
    

    Or use Symfony Messenger:

    php bin/console messenger:consume async_files_resources
    
  5. CDN Integration (recommended):

    • Deploy baks-dev/files-cdn separately.
    • Configure CDN to handle WebP conversion and static asset delivery.

Implementation Patterns

Core Workflows

1. File Upload and Storage

  • Leverage Facades:

    use BaksDev\FilesRes\Facades\FileResource;
    
    // Upload with validation
    $file = FileResource::upload('image.jpg', 'public/upload', [
        'max_size' => '10MB',
        'allowed_types' => ['jpg', 'png', 'webp'],
    ]);
    
    // Store metadata (e.g., MIME type, size)
    $file->getMetadata();
    
  • Custom Storage Adapters: Extend BaksDev\FilesRes\Contracts\StorageAdapter for S3, GCS, etc.:

    class CustomS3Adapter implements StorageAdapter {
        public function store($path, $content) { ... }
        public function url($path) { ... }
    }
    

2. Async Processing with Symfony Messenger

  • Dispatch Jobs:

    use BaksDev\FilesRes\Message\ProcessFileMessage;
    
    $message = new ProcessFileMessage($file->getPath(), 'webp');
    app('messenger')->dispatch($message);
    
  • Handle Messages:

    namespace App\MessageHandler;
    
    use BaksDev\FilesRes\Message\ProcessFileMessage;
    use Symfony\Component\Messenger\Attribute\AsMessageHandler;
    
    #[AsMessageHandler]
    class ProcessFileHandler {
        public function __invoke(ProcessFileMessage $message) {
            // Convert to WebP, store, etc.
        }
    }
    

3. CDN Integration

  • Offload Static Assets: Configure baks-dev/files-cdn to:

    • Accept uploads via API.
    • Convert images to WebP.
    • Serve optimized assets via CDN.
  • Laravel Proxy: Use middleware to redirect requests:

    Route::get('/cdn/{path}', function ($path) {
        return redirect("https://cdn.yourdomain.com/{$path}");
    });
    

4. Tenant/User Isolation

  • Dynamic Paths:

    $tenantId = auth()->user()->tenant_id;
    $file = FileResource::upload('file.jpg', "public/upload/{$tenantId}");
    
  • Policy Integration: Extend BaksDev\FilesRes\Policies\FilePolicy for custom rules.


Integration Tips

  1. Laravel-Specific Adjustments:

    • Replace Symfony’s ContainerInterface with Laravel’s Container:
      $container = app();
      
    • Use Laravel’s Storage facade for fallback logic:
      use Illuminate\Support\Facades\Storage;
      
      if (!FileResource::exists($path)) {
          Storage::disk('public')->exists($path);
      }
      
  2. Queue System:

    • Align Symfony Messenger with Laravel Queues:
      // In a Laravel Job
      public function handle() {
          $message = new ProcessFileMessage(...);
          app('messenger')->dispatch($message);
      }
      
  3. WebP Conversion:

    • Use spatie/image-optimizer as a fallback:
      use Spatie\ImageOptimizer\OptimizerChainFactory;
      
      $optimizer = OptimizerChainFactory::create();
      $optimizer->optimize($filePath)->save();
      
  4. Testing:

    • Mock StorageAdapter and Messenger in PHPUnit:
      $this->partialMock(FileResource::class, ['store'])
           ->shouldReceive('store')
           ->once();
      

Gotchas and Tips

Pitfalls

  1. Symfony vs. Laravel Mismatches:

    • Messenger Integration: Symfony’s MessageBus won’t work directly with Laravel’s queues. Use a wrapper:
      class LaravelMessengerBridge {
          public function dispatch($message) {
              ProcessFileJob::dispatch($message);
          }
      }
      
    • Dependency Injection: Avoid new calls; use Laravel’s app() or make().
  2. CDN Dependency:

    • The package mandates baks-dev/files-cdn for WebP conversion. Without it, you’ll need to:
      • Implement conversion locally (e.g., Intervention\Image).
      • Use client-side libraries (e.g., browser-image-compression).
  3. Path Handling:

    • Assumes public/upload structure. For Laravel’s storage/app/public, adjust:
      $adapter = new LocalStorageAdapter(storage_path('app/public'));
      
  4. Async Processing Quirks:

    • Message Serialization: Symfony Messenger uses PHP’s serialize(). Laravel’s queues may fail with complex objects. Use ShouldQueue with serialize: false:
      public $connection = 'database';
      public $queue = 'resources';
      public $serialize = false;
      
  5. Permissions:

    • chown may fail on shared hosting. Use:
      chmod -R 775 public/upload
      

Debugging

  1. Queue Issues:

    • Check Symfony Messenger logs:
      php bin/console messenger:failed:list
      php bin/console messenger:failed:remove <id>
      
    • For Laravel, use:
      php artisan queue:failed
      
  2. File Not Found:

    • Verify StorageAdapter paths:
      FileResource::adapter()->getRootPath(); // Debug root
      
  3. WebP Conversion Failures:

    • Ensure imagemagick or gd is installed:
      sudo apt-get install imagemagick
      
    • Test conversion manually:
      convert input.jpg output.webp
      

Extension Points

  1. Custom Validators: Extend BaksDev\FilesRes\Validator\FileValidator:

    class CustomValidator extends FileValidator {
        protected function rules() {
            return array_merge(parent::rules(), [
                'custom_rule' => 'required|custom_validation',
            ]);
        }
    }
    
  2. Event Listeners: Listen for file upload events:

    use BaksDev\FilesRes\Events\FileUploaded;
    
    FileUploaded::listen(function ($event) {
        Log::info("File uploaded: {$event->file->getPath()}");
    });
    
  3. Middleware: Add custom logic to uploads:

    FileResource::extend(function ($resource) {
        $resource->onUpload(function ($file) {
            // Pre-process file
        });
    });
    
  4. Testing Helpers: Use FileResourceTestCase for unit tests:

    use BaksDev\FilesRes\Tests\FileResourceTestCase;
    
    class MyTest extends FileResourceTestCase {
        public function testUpload() { ... }
    }
    

Configuration Quirks

  1. Environment Variables: Override defaults in .env:

    FILES_RES_UPLOAD_DIR=storage/app/public/uploads
    FILES_RES_CDN_URL=https://cdn.yourdomain.com
    
  2. Messenger Transport: Configure Symfony Messenger to use Laravel’s database transport:

    # config/packages/messenger.yaml
    framework:
        messenger:
            transports:
                async: '%env(MESSENGER_TRANSPORT_DSN)%'
            routing:
                'BaksDev\FilesRes\Message\ProcessFileMessage': async
    
  3. Fallback Storage: Set a default adapter in config/files-res.php:

    'storage' => [
        'default' => 'local',
        'adapters' => [
            'local' => \BaksDev\FilesRes\Storage\LocalStorageAdapter::class,
            's3' => \BaksDev\FilesRes\Storage\S3StorageAdapter::class,
        ],
    ],
    

Pro Tips

  1. Leverage Laravel Mix: Process WebP files during build:
    // webpack.mix.js
    mix.webpackConfig({
        module: {
            rules: [
                {
                    test:
    
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.
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle
atriumphp/atrium
sandermuller/package-boost-laravel
sandermuller/boost-skills
redaxo/core
yusufgenc/filament-api-forge
l3aro/rating-star-for-filament
leek/filament-subtenant-scope