bengor-file/file
Lightweight PHP file management library built with Domain-Driven Design. Provides common operations like upload (default or by hash), overwrite, remove, and rename, with a tested, documented codebase and flexible storage integration.
Installation:
composer require bengor-file/file
Add to composer.json if using Laravel’s vendor directory:
"autoload": {
"psr-4": {
"App\\": "app/",
"BenGor\\File\\": "vendor/bengor-file/file/src/"
}
}
Run composer dump-autoload.
First Use Case: Handle a file upload in a Laravel controller:
use BenGor\File\FileManager;
use BenGor\File\Storage\LocalStorage;
// Configure storage (e.g., local filesystem)
$storage = new LocalStorage(storage_path('app/uploads'));
$fileManager = new FileManager($storage);
// Handle upload
$request->file('file')->store('uploads');
$file = $fileManager->upload($request->file('file'));
Key Classes:
FileManager: Core class for file operations.Storage\LocalStorage: Default storage adapter (extend for S3, etc.).File: Represents a file entity with metadata (name, hash, size, etc.).File Uploads:
$file = $fileManager->upload($request->file('file'));
// Returns File entity with path, hash, and metadata.
$file = $fileManager->uploadByHash($request->file('file'));
File Management:
$fileManager->overwrite($existingFile, $newFile);
$fileManager->rename($file, 'new-name.ext');
$fileManager->remove($file);
Storage Adapters:
Storage\StorageInterface for custom storage (e.g., AWS S3):
class S3Storage implements StorageInterface {
public function save(File $file, $content) { /* ... */ }
public function exists($path) { /* ... */ }
// ...
}
FileManager:
$fileManager = new FileManager(new S3Storage());
Laravel Integration:
FileManager to the container in AppServiceProvider:
$this->app->singleton(FileManager::class, function ($app) {
return new FileManager(new LocalStorage(storage_path('app/uploads')));
});
// FileManagerFacade.php
namespace App\Facades;
use Illuminate\Support\Facades\Facade;
class FileManagerFacade extends Facade {
protected static function getFacadeAccessor() { return 'file-manager'; }
}
Register in AppServiceProvider:
Facade::alias(FileManagerFacade::class, 'FileManager');
Usage:
use App\Facades\FileManager;
$file = FileManager::upload($request->file('file'));
Domain-Driven Design (DDD) Patterns:
File entities to encapsulate file logic (e.g., validation, metadata).class FileRepository {
protected $fileManager;
public function __construct(FileManager $fileManager) {
$this->fileManager = $fileManager;
}
public function save(File $file) {
return $this->fileManager->upload($file->getFile());
}
}
Deprecated Package:
File entity methods (e.g., getPath() vs. getStoragePath()).Storage Adapter Quirks:
LocalStorage assumes Unix-like paths. For Windows, normalize paths:
$path = str_replace('\\', '/', $path);
StorageInterface methods (e.g., delete(), getUrl()).File Hashing:
uploadByHash() uses md5_file() by default. For consistency, override hashing logic:
$fileManager->setHashAlgorithm(function ($file) {
return hash_file('sha256', $file->getPathname());
});
Laravel Filesystem Integration:
Storage facade with BenGorFile. Use one consistently:
// Bad: Mixing approaches
$path = $request->file('file')->store('uploads');
$file = $fileManager->upload($path); // Fails: expects UploadedFile, not path.
BenGorFile for DDD-centric projects; use Laravel’s Storage for simplicity.Error Handling:
try {
$file = $fileManager->upload($request->file('file'));
} catch (\BenGor\File\Exception\FileException $e) {
return back()->withError($e->getMessage());
}
BenGor\File\Exception\FileException.Log File Metadata:
$file = $fileManager->upload($request->file('file'));
\Log::debug('Uploaded file', [
'name' => $file->getName(),
'hash' => $file->getHash(),
'path' => $file->getStoragePath(),
]);
Verify Storage Paths:
LocalStorage paths are correct:
$storage = new LocalStorage(storage_path('app/uploads'));
\Log::info('Storage base path:', [$storage->getBasePath()]);
Test Hash Collisions:
uploadByHash:
$file1 = $fileManager->upload(fopen('file1.txt', 'r'));
$file2 = $fileManager->upload(fopen('file1.txt', 'r')); // Should reuse hash.
Custom File Validation:
File entity or use a validator:
$validator = Validator::make([
'file' => $request->file('file'),
], [
'file' => 'required|mimes:jpg,png|max:2048',
]);
if ($validator->fails()) { /* ... */ }
Post-Upload Actions:
$fileManager->upload($request->file('file'), function ($file) {
// Generate thumbnail, update DB, etc.
\Log::info('Post-upload action for:', [$file->getName()]);
});
File Metadata:
File entity:
$file->setMetadata(['user_id' => auth()->id(), 'original_name' => $request->file('file')->getClientOriginalName()]);
$file->getMetadata('user_id');
Testing:
StorageInterface for unit tests:
$mockStorage = Mockery::mock(StorageInterface::class);
$mockStorage->shouldReceive('save')->andReturn(true);
$fileManager = new FileManager($mockStorage);
How can I help you explore Laravel packages today?