Installation:
composer require sextanet/laravel-files
php artisan vendor:publish --tag="files-migrations"
php artisan migrate
files table and relationships.Define a Model:
Add HasFiles trait to your model (e.g., Post):
use Sextanet\Files\HasFiles;
class Post extends Model
{
use HasFiles;
}
First Use Case: Upload a file via a form:
$post = Post::create(['title' => 'My Post']);
$post->addFile($request->file('file_input'), 'path/to/store'); // Stores on default disk
files table with metadata (disk, path, model ID).File Uploads with Metadata:
// Upload with custom disk and metadata
$user = User::find(1);
$user->addFile($request->file('avatar'), 'avatars', [
'disk' => 's3',
'mime_type' => 'image/jpeg',
'visibility' => 'public',
]);
Scoped Disks:
Leverage Laravel’s scoped disks (e.g., s3:private) for access control:
$file = $post->addFile($request->file('document'), 'documents', [
'disk' => 's3:private',
]);
Temporary URLs: Generate time-limited URLs for local files (e.g., for email attachments):
$url = $file->temporaryUrl(60); // Valid for 60 seconds
File Retrieval:
// Get file path (resolves disk automatically)
$path = $file->path;
// Stream file directly (e.g., for responses)
return response()->streamDownload($file->stream(), $file->name);
Bulk Operations:
// Delete all files for a model
$post->files()->delete();
// Sync files (e.g., after manual uploads)
$post->syncFiles([$newFileId, $existingFileId]);
Validation: Use Laravel’s validation rules to restrict file types/sizes before upload:
$request->validate([
'file' => 'required|file|mimes:pdf,jpeg|max:2048',
]);
Events:
Listen for file operations (e.g., FileCreated, FileDeleted) via Laravel’s event system:
// In EventServiceProvider
protected $listen = [
'Sextanet\Files\Events\FileCreated' => [
'App\Listeners\LogFileUpload',
],
];
Policy Authorization: Restrict file access in policies:
public function delete(User $user, File $file)
{
return $user->id === $file->model_id;
}
Storage Optimization:
Use optionalDisk() to handle missing disks gracefully:
$file->optionalDisk('fallback-disk')->path;
Disk Configuration:
config/filesystems.php. Missing disks will cause silent failures.if (!Storage::disk($disk)->exists($path)) {
Storage::disk($disk)->makeDirectory($path);
}
Temporary URLs:
symlink permissions. On shared hosting, this may fail.Model Deletion:
$post->delete(); // Files remain
$post->files()->delete(); // Then delete files
delete() in your model:
public function delete()
{
$this->files()->delete();
parent::delete();
}
Path Collisions:
documents/) will overwrite files.$post->addFile($file, "documents/{$post->id}/");
Large Files:
post_max_size or memory limits.Missing Files:
files table for orphaned records (where model_id doesn’t exist).SELECT * FROM files WHERE model_id NOT IN (SELECT id FROM posts);
Disk Permissions:
chmod -R 775 storage/app
chmod -R 775 public/storage
Log File Operations:
config(['files.debug' => true]);
Custom File Model:
Extend the File model to add fields (e.g., size, checksum):
php artisan make:model FileExtension --extend=Sextanet\Files\Models\File
File Events: Publish event classes and listen for custom logic:
php artisan vendor:publish --tag="files-events"
Disk Fallbacks:
Implement a fallback disk strategy in app/Providers/AppServiceProvider:
File::macro('fallbackDisk', function ($primary, $fallback) {
return Storage::disk($primary)->exists($this->path)
? $primary
: $fallback;
});
Presigned URLs: For S3, generate presigned URLs instead of temporary URLs:
$url = $file->disk->url($file->path, 3600); // 1-hour URL
How can I help you explore Laravel packages today?