arshad1114 / laravel-dms-disk
A custom Laravel filesystem disk driver for Document Management Services over HTTP.
Requires
- php: ^8.1
- illuminate/http: ^10.0|^11.0|^12.0
- illuminate/support: ^10.0|^11.0|^12.0
- league/flysystem: ^3.0
Requires (Dev)
- guzzlehttp/guzzle: ^7.0
- mockery/mockery: ^1.6
- orchestra/testbench: ^8.0|^9.0
- phpunit/phpunit: ^10.0|^11.0
README
A custom Laravel filesystem disk driver that lets any Laravel microservice store, retrieve and manage files on a remote Document Management Service (DMS) using the native Storage facade — no custom HTTP calls, no helper functions, no boilerplate.
Try it online — no install needed
Click the button above to launch a live demo in your browser using GitHub Codespaces. Both services start automatically — no setup required.
Once the Codespace loads:
bash .devcontainer/start.sh
Open a new terminal:
cd consumer-service && php artisan tinker
Then try:
Storage::disk('dms')->put('test/hello.txt', 'Hello World!'); Storage::disk('dms')->get('test/hello.txt'); Storage::disk('dms')->delete('test/hello.txt');
The problem
In a microservice architecture, when a service needs to store files on a dedicated DMS service, developers typically write custom HTTP calls in every service:
// ❌ what developers do today — repeated in every service $response = Http::attach('file', $contents, 'invoice.pdf') ->post('https://dms.internal/upload', ['path' => 'invoices/001.pdf']);
The solution
Install this package and use the native Storage facade as you always have:
// ✅ with laravel-dms-disk Storage::disk('dms')->put('invoices/001.pdf', $contents); Storage::disk('dms')->get('invoices/001.pdf'); Storage::disk('dms')->delete('invoices/001.pdf');
The HTTP transport is completely invisible.
How it works
Consumer service DMS service
──────────────── ───────────────────────────
Storage::disk('dms')->put(...) Receives the HTTP request
│ Calls Storage::put(...)
│ HTTPS using its own
└──────────────────────────────► filesystems.php config
Requirements
- PHP 8.1+
- Laravel 10, 11, or 12
Installation
composer require arshad1114/laravel-dms-disk
The DmsServiceProvider is auto-discovered — no manual registration needed.
Publish the config:
php artisan vendor:publish --tag=dms-disk-config
Configuration
Add to your .env:
DMS_URL=https://your-dms-service.internal DMS_TOKEN=your-strong-secret-token
Add the dms disk to config/filesystems.php:
'disks' => [ // ... your existing disks 'dms' => [ 'driver' => 'dms', ], ],
Disk selection
By default the DMS server uses its own configured default disk (FILESYSTEM_DISK in the DMS .env). You only need to set DMS_DISK if you want to target a specific disk on the DMS server:
# Use DMS server default disk — recommended DMS_DISK= # Or target a specific disk on the DMS server DMS_DISK=client
You can also set it per disk in config/filesystems.php:
'dms' => [ 'driver' => 'dms', 'disk' => 'client', // store on the client disk on the DMS server ],
Full config reference
All options in config/dms-disk.php:
| Key | Env variable | Default | Description |
|---|---|---|---|
url |
DMS_URL |
'' |
Base URL of your DMS service |
token |
DMS_TOKEN |
'' |
Bearer token for authentication |
disk |
DMS_DISK |
null |
Disk name on the DMS server. If not set, DMS server uses its own default disk |
timeout |
DMS_TIMEOUT |
30 |
HTTP timeout in seconds |
retry |
DMS_RETRY |
3 |
Retry attempts on connection failure |
retry_delay |
DMS_RETRY_DELAY |
200 |
Milliseconds between retries |
Multiple DMS disks
You can point multiple disks to different DMS services or different disks on the same DMS service:
'disks' => [ // Uses DMS server default disk 'dms' => [ 'driver' => 'dms', 'url' => env('DMS_URL'), 'token' => env('DMS_TOKEN'), ], // Targets the client disk on the DMS server 'dms-client' => [ 'driver' => 'dms', 'url' => env('DMS_URL'), 'token' => env('DMS_TOKEN'), 'disk' => 'client', ], // Points to a completely different DMS service 'dms-archive' => [ 'driver' => 'dms', 'url' => env('DMS_ARCHIVE_URL'), 'token' => env('DMS_ARCHIVE_TOKEN'), ], ],
Usage
Upload a file
// From a string Storage::disk('dms')->put('invoices/001.pdf', $pdfContents); // From an uploaded file in a controller $request->file('document')->store('documents', 'dms'); // With a custom filename $request->file('document')->storeAs('documents', 'invoice-001.pdf', 'dms'); // As public visibility Storage::disk('dms')->put('avatars/user-1.jpg', $imageContents, 'public');
Download a file
// Get file contents as string $contents = Storage::disk('dms')->get('invoices/001.pdf'); // Stream download directly to browser return Storage::disk('dms')->download('invoices/001.pdf'); // Stream with custom filename return Storage::disk('dms')->download('invoices/001.pdf', 'my-invoice.pdf');
Check existence
if (Storage::disk('dms')->exists('invoices/001.pdf')) { // file exists } if (Storage::disk('dms')->missing('invoices/001.pdf')) { // file does not exist }
Delete a file
Storage::disk('dms')->delete('invoices/001.pdf');
Move and copy
// Move (rename) Storage::disk('dms')->move('old/path.pdf', 'new/path.pdf'); // Copy Storage::disk('dms')->copy('original.pdf', 'copy.pdf');
List files
// Files in a directory $files = Storage::disk('dms')->files('invoices'); // Files recursively $files = Storage::disk('dms')->allFiles('invoices');
File metadata
$size = Storage::disk('dms')->size('invoices/001.pdf'); $mime = Storage::disk('dms')->mimeType('invoices/001.pdf'); $timestamp = Storage::disk('dms')->lastModified('invoices/001.pdf');
URLs
// Public URL $url = Storage::disk('dms')->url('avatars/user-1.jpg'); // Temporary signed URL $url = Storage::disk('dms')->temporaryUrl('invoices/001.pdf', now()->addHour());
Visibility
Storage::disk('dms')->setVisibility('avatars/user-1.jpg', 'public'); Storage::disk('dms')->setVisibility('invoices/001.pdf', 'private'); $visibility = Storage::disk('dms')->visibility('avatars/user-1.jpg'); // returns 'public' or 'private'
Troubleshooting
401 Unauthorized
DMS_TOKEN in the consumer does not match DMS_SERVER_TOKEN in the DMS service. Make sure both values are identical.
Driver [dms] not supported
The dms disk is missing from config/filesystems.php. Add it as shown in the configuration section above.
Connection refused / timeout
DMS_URL is wrong or the DMS service is not running. Double check the URL and port.
Routes not found on DMS side
Run php artisan route:clear on the DMS service and check php artisan route:list --path=dms-disk.
File storing on wrong disk
If files are storing on the wrong disk on the DMS server, check DMS_DISK in your consumer .env. If it is set to local explicitly, clear it so the DMS server uses its own default:
DMS_DISK=
ServiceProvider not found
If you get Driver [dms] not supported, run:
php artisan package:discover php artisan config:clear
If still not working, register the provider manually in bootstrap/providers.php (Laravel 11+):
Arshad1114\DmsDisk\Consumer\DmsServiceProvider::class,
Or in config/app.php (Laravel 10):
'providers' => [ Arshad1114\DmsDisk\Consumer\DmsServiceProvider::class, ],
DMS server packages
Your DMS service can be written in any language that implements the API contract. Official server packages:
| Framework | Package |
|---|---|
| Laravel | arshad1114/laravel-dms-disk-server |
| Node.js | Coming soon |
Contributing
Contributions are welcome. Please:
- Fork the repo
- Create a feature branch:
git checkout -b feat/your-feature - Write tests for your change
- Make sure all tests pass:
./vendor/bin/phpunit - Open a pull request
License
MIT — see LICENSE file.