baks-dev/files-res
Laravel/PHP пакет для управления файловыми ресурсами: загрузка и хранение в public/upload, настройка прав доступа, асинхронная обработка через очередь Messenger (async_files_resources). Поддерживает пережатие и конвертацию изображений в WebP через отдельный CDN-сервер.
Installation:
composer require baks-dev/files-res
Ensure your project uses PHP 8.4+ and Laravel/Symfony 7.4+.
Configure Storage Directory:
mkdir -p public/upload
chown -R www-data:www-data public/upload # Adjust user/group as needed
Update config/filesystems.php to include a disk for uploads (e.g., upload_disk):
'disks' => [
'upload_disk' => [
'driver' => 'local',
'root' => public_path('upload'),
],
],
First Use Case: File Upload
Inject the FilesResourceManager service (if available) or use Laravel’s Storage facade directly:
use Illuminate\Support\Facades\Storage;
$path = Storage::disk('upload_disk')->putFile('images', $request->file('image'));
Async Processing Setup:
Ensure the messenger:consume command is running for background tasks:
php artisan queue:work --queue=resources
(Note: Symfony Messenger may require additional Laravel queue adapters.)
File Upload and Storage:
Storage facade for consistency:
$filePath = Storage::disk('upload_disk')->putFileAs(
'user_avatars',
$request->file('avatar'),
'user_' . auth()->id() . '.webp'
);
FileUploader) to handle validation, path generation, and disk selection.Image Optimization (WebP Conversion):
spatie/image-optimizer for local conversion:
use Spatie\ImageOptimizer\OptimizerChainFactory;
$optimizer = OptimizerChainFactory::create()->webp();
$optimizer->optimize($originalPath, $optimizedPath);
baks-dev/files-cdn (if required).Async Processing:
namespace App\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
class ConvertToWebPJob implements ShouldQueue
{
use Queueable;
public function handle()
{
// Logic to convert image to WebP
}
}
ConvertToWebPJob::dispatch($filePath)->onQueue('resources');
Integration with baks-dev/core (if applicable):
baks-dev/core, extend its ResourceManager trait or service bindings to integrate file resources:
use BaksDev\Core\Traits\ResourceManager;
class FileResourceService
{
use ResourceManager;
public function upload(...)
{
// Custom logic using FilesResourceManager
}
}
Service Providers:
Register custom bindings for FilesResourceManager (if needed) in AppServiceProvider:
public function register()
{
$this->app->bind(
\BaksDev\FilesRes\FilesResourceManager::class,
fn($app) => new \BaksDev\FilesRes\FilesResourceManager(
$app->make(\Illuminate\Filesystem\Filesystem::class),
config('files-res')
)
);
}
Middleware for File Access: Restrict access to uploads via middleware:
public function handle($request, Closure $next)
{
if ($request->is('upload/*') && !auth()->check()) {
abort(403);
}
return $next($request);
}
Event Listeners:
Trigger events post-upload (e.g., FileUploaded) to notify other services:
event(new FileUploaded($filePath, $request->user()));
Symfony Messenger Compatibility:
ShouldQueue interface and manually map jobs. Avoid direct dependency on Messenger.Symfony\Component\Messenger\* in composer.json and replace with Laravel’s queue adapters.Undocumented baks-dev/core Dependency:
baks-dev/core, which lacks release notes.composer.json for hidden dependencies. Replace core functionality with Laravel’s Illuminate\Foundation\Application or Illuminate\Support services.composer why-not baks-dev/core to check for indirect dependencies.Path Handling Quirks:
public/upload) without Laravel’s storage abstraction.$path = Storage::disk('upload_disk')->path($relativePath);
Storage::disk('upload_disk')->url($path) to verify URLs.WebP Conversion Without CDN:
spatie/image-optimizer or Intervention\Image for local conversion:
composer require spatie/image-optimizer
Async Job Failures:
database) and log failures:
ConvertToWebPJob::dispatch($filePath)
->onQueue('resources')
->catch(fn($e) => Log::error('WebP conversion failed', ['error' => $e]));
Leverage Laravel’s Storage:
Storage facade over direct filesystem calls for consistency:
// Instead of:
$path = 'public/upload/' . $filename;
// Use:
$path = Storage::disk('upload_disk')->putFile('subdir', $file);
Custom Disk Configuration:
config/filesystems.php to support dynamic disks:
'disks' => [
'upload_disk' => [
'driver' => 'local',
'root' => storage_path('app/public/upload'),
'url' => env('APP_URL') . '/storage/upload',
'visibility' => 'public',
],
],
php artisan storage:link
Queue Monitoring:
resources queue for stuck jobs:
php artisan queue:failed-table
php artisan queue:work --queue=resources --sleep=3 --tries=3
Testing File Uploads:
UploadedFile for testing:
$file = UploadedFile::fake()->image('avatar.jpg');
$this->post('/upload', ['file' => $file]);
$this->assertTrue(Storage::disk('upload_disk')->exists('avatars/user_1.jpg'));
Performance Optimization:
Symfony\Component\HttpFoundation\File\UploadedFile or libraries like league/flysystem-aws-s3-v3.if (!Storage::disk('upload_disk')->exists($webpPath)) {
ConvertToWebPJob::dispatch($originalPath, $webpPath);
}
Security:
$request->validate([
'file' => 'required|file|mimes:jpg,png|max:2048',
]);
$filename = Str::slug($request->user()->name) . '.' . $file->getClientOriginalExtension();
How can I help you explore Laravel packages today?