anil/file-picker
Laravel Livewire media library & file picker modal for any file type. Upload via drag/drop or paste, search/filter, tags/folders/favorites, single or multi-select, trash/restore, replace files, SHA-256 dedupe, quotas, stats, downloads, and commands.
Installation
composer require anil/file-picker
Publish config and migrations:
php artisan vendor:publish --provider="Anil\FilePicker\FilePickerServiceProvider"
php artisan migrate
Basic Usage Add the Livewire component to your Blade view:
@livewire('file-picker', ['model' => 'Post', 'field' => 'image'])
Configure the field in your model:
use Anil\FilePicker\Traits\HasFilePicker;
class Post extends Model
{
use HasFilePicker;
}
First Use Case Trigger the picker in a form:
<x-file-picker-input wire:model="post.image" />
The modal will open, allowing selection of files from the media library or uploads.
Media Library Integration
FilePicker::getFiles() to fetch paginated files with filters:
$files = FilePicker::getFiles()->search('logo')->type('image')->paginate(10);
public $selectedFiles = [];
public function updatedSelectedFiles()
{
$this->validateEach($this->selectedFiles, [
'*.file' => 'required|file|mimes:jpeg,png',
]);
}
Upload Handling
config/file-picker.php:
'upload_rules' => [
'image' => ['max:10240', 'mimes:jpeg,png,svg'],
'document' => ['max:5120', 'mimes:pdf,docx'],
],
protected $listeners = ['fileUploaded' => 'handleUploadedFile'];
public function handleUploadedFile($file)
{
$this->store()->files()->create([
'user_id' => auth()->id(),
'path' => $file->path(),
'mime' => $file->mime(),
'size' => $file->size(),
]);
}
File Selection Patterns
<x-file-picker-input wire:model="post.thumbnail" mode="single" />
<x-file-picker-input wire:model="gallery.files" mode="multiple" max_files="5" />
Customizing the UI
resources/views/vendor/file-picker/.config/file-picker.styles:
'styles' => [
'primary' => '#3b82f6',
'background' => '#f8fafc',
],
Programmatic File Management
$file->tags()->attach(['logo', 'brand']);
$file->update(['folder_id' => $newFolder->id]);
File Validation Mismatch
upload_rules in config match your model validation. Discrepancies cause silent failures.wire:ignore on the input to debug:
<input wire:ignore type="file" wire:model="fileInput">
Duplicate Detection Conflicts
reuse strategy is set. Test with:
FilePicker::setDuplicateStrategy('allow'); // Temporarily override
Storage Quota Exceeded
if (FilePicker::isQuotaExceeded()) {
toast('Storage full!', 'error');
}
Livewire Property Binding
// Bad: wire:model="post.images"
// Good:
public $tempImages = [];
public function updatedTempImages()
{
$this->post->images = $this->tempImages;
}
Folder Permissions
$folder->update(['permissions' => 'rw']); // Read-write for all
Log Upload Events
Add to AppServiceProvider:
FilePicker::onUploading(function ($file) {
Log::debug('Uploading:', ['name' => $file->getClientOriginalName()]);
});
Inspect FilePicker State Use Tinker to check:
php artisan tinker
>>> \Anil\FilePicker\Facades\FilePicker::getStats();
Clear Cached Views If UI breaks after config changes:
php artisan view:clear
php artisan cache:clear
Custom File Types
Extend the FileType class:
namespace App\Extensions;
use Anil\FilePicker\Contracts\FileType;
class CustomType implements FileType
{
public function getMimes(): array { return ['application/x-custom']; }
public function getIcon(): string { return '🎯'; }
}
Register in config/file-picker.php:
'custom_types' => [
'custom' => \App\Extensions\CustomType::class,
],
Pre-Signed URLs for Direct Uploads
Use the FilePicker::generateUploadUrl() method to create temporary S3 URLs:
$url = FilePicker::generateUploadUrl($file->hash(), $file->mime());
// Pass to frontend for direct upload
Webhook Triggers
Listen for file events via FilePicker::on* methods:
FilePicker::onFileDeleted(function ($file) {
// Sync with external service
});
Override Default Storage
Bind custom storage to the File model:
use Anil\FilePicker\Models\File;
use League\Flysystem\Filesystem;
File::addGlobalScope('customStorage', function (Builder $builder) {
$builder->getQuery()->from(new Filesystem(...));
});
How can I help you explore Laravel packages today?