basekit-laravel / basekit-laravel-media
Media library for Laravel: metadata for files on a filesystem disk, a folder hierarchy and a Filament admin screen.
Package info
github.com/basekit-laravel/basekit-laravel-media
pkg:composer/basekit-laravel/basekit-laravel-media
Requires
- php: ^8.4|^8.5
- illuminate/contracts: ^13
- illuminate/database: ^13
- illuminate/filesystem: ^13
- illuminate/support: ^13
Requires (Dev)
- filament/filament: ^5.8
- larastan/larastan: ^3.8
- laravel/pint: ^1.17
- mockery/mockery: ^1.6
- nunomaduro/collision: ^8.9
- orchestra/testbench: 11.*
- pestphp/pest: ^5.0
- pestphp/pest-plugin-laravel: ^5.0
- pestphp/pest-plugin-livewire: ^5.0
- phpstan/extension-installer: ^1.4
- phpstan/phpstan-deprecation-rules: ^2.0
- rector/rector: ^2.6
Suggests
- filament/filament: Required to use the admin screen and the picker field.
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-10-31 15:30:40 UTC
README
Media library for Laravel: files on a Laravel filesystem disk, their metadata in the database, a folder hierarchy for editors, and a Filament admin screen.
Moving a file between folders changes metadata only, so published URLs never break.
📋 Contents
- Requirements
- Installation
- Configuration
- The admin screen
- Permissions
- Uploads
- Deleting and restoring
- Using media from your own code
- Custom views and translations
- Security
- Limitations
- Development
🧰 Requirements
- PHP 8.4 or 8.5
- Laravel 13
- Filament 5 (optional — only the admin screen needs it)
⬇️ Installation
composer require basekit-laravel/basekit-laravel-media
Package discovery registers the service provider and runs the migration. Publish it only if you want to own the file:
php artisan vendor:publish --tag="basekit-laravel-media-migrations"
php artisan migrate
The admin screen needs Filament:
composer require filament/filament
The screen's stylesheet ships as a Filament asset, so publishing the assets is what puts it on the panel. Run this again after every upgrade:
php artisan filament:assets
⚙️ Configuration
php artisan vendor:publish --tag="basekit-laravel-media-config"
Everything lives in config/basekit-laravel-media.php:
return [ // Where uploads are stored: a Laravel disk and a directory on it. 'disk' => env('BASEKIT_MEDIA_DISK', 'public'), 'path' => env('BASEKIT_MEDIA_PATH', 'media'), // true: delete() keeps the row and restore() brings it back. // false: delete() removes the row and the file. 'soft_deletes' => true, 'uploads' => [ 'max_size' => env('BASEKIT_MEDIA_MAX_SIZE'), // kilobytes; null for Filament's 12 MB 'accepted_file_types' => ['image/*'], ], // Gate names. null allows the ability without asking. 'permissions' => [ 'view' => env('BASEKIT_MEDIA_VIEW_PERMISSION'), 'create' => env('BASEKIT_MEDIA_CREATE_PERMISSION'), 'update' => env('BASEKIT_MEDIA_UPDATE_PERMISSION'), 'delete' => env('BASEKIT_MEDIA_DELETE_PERMISSION'), ], ];
Use a public disk so stored files get a web URL. A page stores that URL, so keep the disk alive for as long as pages refer to files on it.
soft_deletes belongs in this file rather than in .env: it decides what deleting means for rows already in the table, so it should not flip with a deploy.
🖥️ The admin screen
Register the plugin on a panel:
use BasekitLaravel\BasekitLaravelMedia\Filament\MediaPlugin; public function panel(Panel $panel): Panel { return $panel // ... ->plugin(new MediaPlugin); }
The plugin adds a single Media screen that holds the folders and the files together.
🔒 Permissions
By default anyone who can reach the panel can use the media screen — installing the package does not lock an existing panel out of its own library.
To restrict an ability, define a gate and point the ability at it:
Gate::define('manage-media', fn (User $user): bool => $user->isEditor());
'permissions' => [ 'view' => 'manage-media', ],
The same thing through .env is BASEKIT_MEDIA_VIEW_PERMISSION=manage-media. A null name — the default — allows the ability without asking.
| Ability | Covers |
|---|---|
view |
Opening the Media screen. |
create |
Upload and New folder. |
update |
Edit, Move, and dragging a file onto a folder. |
delete |
Delete on a file or a folder. |
If your application already has a policy on Media or MediaFolder, that policy is asked first and is about the individual row — you do not need to define these gate names as well.
⬆️ Uploads
Set uploads.max_size in kilobytes (null falls back to Filament's 12 MB) and uploads.accepted_file_types. Filament checks both what the browser sends and what actually arrives, so a file outside the limits is refused rather than written.
Media::maxUploadSize(); // 5120, or null Media::acceptedFileTypes(); // ['image/*']
A file is stored at path/folder-slug, under the folder that is open when it is uploaded.
🗑️ Deleting and restoring
$media->delete(); // gone from the library, still on the disk $media->restore(); // back in the library, still on the disk $media->forceDelete(); // row and file gone for good
Turning soft deletes off
An application that must not keep user-supplied files after a removal can have every deletion take the row and the file together:
'soft_deletes' => false,
With it off, delete() is a hard delete and there is nothing for restore() to bring back; the confirmation an editor reads says so.
- The
deleted_atcolumn is created either way, so changing the setting needs no migration. - Folders are always deleted for good, in both modes. Their files fall back to All files.
💻 Using media from your own code
use BasekitLaravel\BasekitLaravelMedia\Models\Media; Media::query()->orderBy('id', 'desc')->paginate(24); // index pages $media->storageUrl(); // web URL for an <img> $media->humanSize(); // "1.2 MB" for a listing Media::findByStorageValue('/storage/media/cover.jpg'); // resolve a stored value
findByStorageValue() matches a stored web URL or path back to its row.
🎨 Custom views and translations
php artisan vendor:publish --tag="basekit-laravel-media-views" php artisan vendor:publish --tag="basekit-laravel-media-translations"
They land in resources/views/vendor/basekit-laravel-media and lang/vendor/basekit-laravel-media. The views render standalone and never assume your application's layout.
The stylesheets are not part of that: they are registered as Filament assets from resources/css/dist/, so a published view carries no CSS of its own.
Class names follow BEM with bkm as the package prefix: bkm-tile, bkm-tile__preview, bkm-folder--over. bkm on its own is the prefix, never a block.
🚧 Limitations
The package does not convert, resize or process files, and it does not read image dimensions.
It does not provide:
- image, video or PDF previews beyond the stored URL
- tagging, favouriting or search beyond the file name
- per-application tenancy of the library
🧪 Development
composer install npm install # once, for the stylesheet build npm run css:dist # build resources/css/dist from resources/css/src composer test # Pest suite (Orchestra Testbench) composer test-coverage # Pest with an HTML report in build/coverage composer analyse # PHPStan / Larastan, over src and tests composer lint # Pint --test composer format # Pint, apply fixes composer refactor-dry # Rector, reporting only composer check # lint + analyse + test composer audit # Known dependency vulnerabilities
📄 License
Basekit Laravel Media is open-source software licensed under the MIT License.