Skip to content

File Storage

Doggy's file storage system is built on League Flysystem, supporting local and S3-compatible storage with file upload, image optimization, and URL generation.

Overview

The storage system lives in src/Service/Storage/:

src/Service/Storage/
├── StorageManager.php          # Storage manager (adapter selection)
├── FileUploadService.php       # File upload service
├── FileUrlGenerator.php        # URL generation/caching
├── ImageOptimizerService.php   # Image optimization (Imagine)
└── Adapter/
    ├── StorageAdapterInterface.php
    ├── LocalStorageAdapter.php
    └── S3StorageAdapter.php

Related entities in src/Entity/Storage/:

EntityDescription
File.phpFile record
StorageConfig.phpStorage configuration (adapter type, params, CDN domain)
UploadSession.phpUpload session

Storage Backends

BackendAdapterUse Case
LocalLocalStorageAdapterDevelopment, small deployments
AWS S3S3StorageAdapterCloud (supports CDN domain)

Local Storage

php
// Default local storage: public/uploads/
$adapter = new LocalStorageAdapter(
    rootPath: '/var/www/public/uploads',
    publicUrl: '/uploads'
);

S3 Storage

php
// S3-compatible (AWS, MinIO, Alibaba OSS, etc.)
$adapter = new S3StorageAdapter([
    'access_key' => '...',
    'secret_key' => '...',
    'region' => 'us-east-1',
    'bucket' => 'doggy-files',
    'endpoint' => 'https://oss-cn-hangzhou.aliyuncs.com',
    'cdn_domain' => 'https://cdn.example.com',
]);

File Upload

FileUploadService provides a complete upload flow:

php
$file = $fileUploadService->upload($uploadedFile, [
    'disk' => 'default',
    'optimize' => true,
    'max_size' => 52428800,  // 50MB
]);

Upload flow:

  1. FileUploadingEvent dispatched (can intercept and modify options)
  2. File safety check (type, size, extension, MIME)
  3. SHA-256 hash deduplication
  4. Date-based path generation (Y/m/uuid.ext or uuid.ext)
  5. Upload to adapter
  6. Create File entity
  7. FileUploadedEvent dispatched
  8. Async image compression (ImageCompressMessage)

Image Optimization

ImageOptimizerService uses the Imagine library:

php
$optimizer->optimize($sourcePath, $targetPath, [
    'max_width' => 1920,
    'max_height' => 1080,
    'quality' => 80,
    'format' => 'webp',
]);

URL Generation

FileUrlGenerator supports caching and temporary URLs:

php
$url = $urlGenerator->getUrl($file);                          // Cached
$tempUrl = $urlGenerator->getTemporaryUrl($file, $expiresAt); // Signed URL
$urlGenerator->invalidateUrl($file);                          // Clear cache

Admin Interface

Controller: App\Controller\Admin\StorageConfigController
Templates: templates/admin/storage/

Open Source under MIT | Copyright © 2026 Doggy