A Laravel package developed by the Internal Organization of the University of Pancasila, designed to simplify file storage management. This package provides an intuitive facade for uploading, retrieving, and managing files across organizational applications through a unified API.
univpancasila/storage-up is a Laravel package for a laravel package developed by the internal organization of the university of pancasila, designed to simplify file storage management. this package provides an intuitive facade for uploading, retrieving, and managing files across organizational applications through a unified api..
It currently has 0 GitHub stars and 45 downloads on Packagist (latest version v1.1.0).
Install it with composer require univpancasila/storage-up.
Discover more Laravel packages by univpancasila
or browse all Laravel packages to compare alternatives.
Last updated
A Laravel package by the Internal Organization of the University of Pancasila. Provides a clean facade for uploading, retrieving, and deleting files via a unified storage API.
1. Install via Composer
composer require univpancasila/storage-up
2. Publish configuration
php artisan vendor:publish --tag=storageup-config
3. Publish and run migrations
php artisan vendor:publish --tag=storageup-migrations
php artisan migrate
4. Configure environment
STORAGE_UP_API_URL=https://storage.univpancasila.ac.id
STORAGE_UP_API_KEY=your-api-key-here
# Optional
STORAGE_UP_UPLOAD_ENDPOINT=/api/v1/storage/upload
STORAGE_UP_DELETE_ENDPOINT=/api/v1/storage/delete
STORAGE_UP_UPLOAD_RETRY=3
STORAGE_UP_DELETE_RETRY=10
STORAGE_UP_MAX_SIZE=10240
use Univpancasila\StorageUp\Facades\StorageUp;
$file = StorageUp::apiKey(config('storageup.api_keys.default'))
->for($user)
->collection('documents')
->upload($request->file('document'));
// $file is a StorageFile model:
// id, original_name, filename, file_id, url, url_thumbnail,
// collection_name, model_type, model_id, timestamps
// All files in a collection
$documents = StorageUp::getFile($user, 'documents');
// Latest file only
$latest = StorageUp::getFile($user, 'documents', latest: true);
// Delete a specific file
StorageUp::deleteFile($file);
// Delete all files in a collection
StorageUp::deleteAllFiles($user, 'documents');
// Delete all files for a model
StorageUp::deleteAllFiles($user);
$file = StorageUp::apiKey('custom-key')
->apiUrl('https://custom-storage.example.com')
->for($user)
->collection('profile-pictures')
->upload($request->file('avatar'));
$project = Project::find(1);
StorageUp::apiKey(config('storageup.api_keys.default'))
->for($project)
->collection('blueprints')
->upload($request->file('blueprint'));
Add a relationship to any model that needs file storage:
use Univpancasila\StorageUp\Models\StorageFile;
class User extends Model
{
public function storageFiles()
{
return $this->morphMany(StorageFile::class, 'model');
}
}
Usage:
// Eager load to avoid N+1
$users = User::with('storageFiles')->get();
// Filter by collection
$documents = $user->storageFiles()
->where('collection_name', 'documents')
->get();
use Univpancasila\StorageUp\Facades\StorageUp;
use Univpancasila\StorageUp\Models\StorageFile;
class FileController extends Controller
{
public function upload(Request $request)
{
$request->validate([
'file' => 'required|file|max:10240',
'collection' => 'required|string',
]);
$file = StorageUp::apiKey(config('storageup.api_keys.default'))
->for(auth()->user())
->collection($request->collection)
->upload($request->file('file'));
return response()->json([
'id' => $file->id,
'name' => $file->original_name,
'url' => $file->url,
'thumbnail' => $file->url_thumbnail,
]);
}
public function index(Request $request)
{
$user = auth()->user();
$collection = $request->get('collection');
$files = $collection
? StorageUp::getFile($user, $collection)
: $user->storageFiles;
return response()->json($files);
}
public function destroy($id)
{
$file = StorageFile::findOrFail($id);
abort_if($file->model_id !== auth()->id(), 403);
StorageUp::deleteFile($file);
return response()->json(['message' => 'File deleted']);
}
}
| Method | Description |
|--------|-------------|
| apiKey(string $apiKey): self | Set API key |
| apiUrl(string $url): self | Set custom API URL |
| collection(string $name): self | Set collection name |
| for(Model $model): self | Bind to an Eloquent model |
| upload(UploadedFile $file, ?string $type = null): StorageFile | Upload file |
| getFile(Model $model, string $collectionName, bool $latest = false) | Retrieve files |
| deleteFile(StorageFile $file): ?bool | Delete a file |
| deleteAllFiles(Model $model, ?string $collectionName = null): void | Bulk delete |
$file->id
$file->model_type // polymorphic type
$file->model_id // polymorphic id
$file->collection_name
$file->original_name
$file->filename
$file->file_id // remote storage ID
$file->url
$file->url_thumbnail
$file->created_at
$file->updated_at
// Delete file from remote storage and database
$file->deleteFile(?string $apiKey = null, ?string $apiUrl = null): bool;
// Static bulk delete
StorageFile::deleteAllFiles(string $modelType, $modelId, ?string $collectionName = null): void;
config/storageup.php:
return [
'api_url' => env('STORAGE_UP_API_URL', 'https://storage.univpancasila.ac.id'),
'api_keys' => [
'default' => env('STORAGE_UP_API_KEY'),
],
'endpoints' => [
'upload' => env('STORAGE_UP_UPLOAD_ENDPOINT', '/api/v1/storage/upload'),
'delete' => env('STORAGE_UP_DELETE_ENDPOINT', '/api/v1/storage/delete'),
],
'retry' => [
'upload' => env('STORAGE_UP_UPLOAD_RETRY', 3),
'delete' => env('STORAGE_UP_DELETE_RETRY', 10),
],
'validation' => [
'max_size' => env('STORAGE_UP_MAX_SIZE', 10240), // KB
'allowed_mimes' => ['jpg', 'jpeg', 'png', 'gif', 'pdf', 'doc', 'docx',
'xls', 'xlsx', 'txt', 'csv', 'zip', 'rar'],
],
];
Use multiple API keys:
StorageUp::apiKey(config('storageup.api_keys.admin'))->...
Apply validation in controllers:
$request->validate([
'file' => [
'required', 'file',
'max:' . config('storageup.validation.max_size'),
'mimes:' . implode(',', config('storageup.validation.allowed_mimes')),
],
]);
try {
$file = StorageUp::apiKey(config('storageup.api_keys.default'))
->for($user)
->collection('documents')
->upload($request->file('document'));
} catch (\Exception $e) {
Log::error('File upload failed', ['error' => $e->getMessage()]);
throw $e;
}
Possible exception messages:
"API key not set. Use apiKey() method first." — call apiKey() before upload()"Model not set. Use for() method first." — call for() before upload()"Failed to upload file to storage service." — network or API errorcomposer test # Run all tests
composer test-coverage # With coverage
composer analyse # PHPStan static analysis
composer format # Pint code style
Mocking in your application tests:
use Illuminate\Support\Facades\Http;
Http::fake([
'*/api/v1/storage/upload' => Http::response([
'status' => 'success',
'data' => [
'fileName' => 'test.pdf',
'fileId' => 'file-123',
'link' => 'https://storage.example.com/test.pdf',
],
], 200),
]);
@forelse($user->storageFiles as $file)
<div>
@if($file->url_thumbnail)
<img src="{{ $file->url_thumbnail }}" alt="{{ $file->original_name }}">
@endif
<p>{{ $file->original_name }}</p>
<p>{{ $file->collection_name ?? 'Default' }}</p>
<a href="{{ $file->url }}" target="_blank">View</a>
<form action="{{ route('files.destroy', $file->id) }}" method="POST">
@csrf @method('DELETE')
<button type="submit">Delete</button>
</form>
</div>
@empty
<p>No files uploaded yet.</p>
@endforelse
Cache frequently accessed URLs:
$url = Cache::remember("user.{$user->id}.avatar", now()->addHours(24),
fn() => StorageUp::getFile($user, 'avatars', latest: true)?->url
);
Eager load relationships:
$users = User::with('storageFiles')->get();
// Or scoped to a collection
$users = User::with(['storageFiles' => fn($q) =>
$q->where('collection_name', 'documents')
])->get();
Facade not found
php artisan config:clear && php artisan package:discover && composer dump-autoload
Files not in database
php artisan vendor:publish --tag=storageup-migrations && php artisan migrate
Upload fails — verify API key, URL reachability, and file size against STORAGE_UP_MAX_SIZE.
See CHANGELOG for recent changes.
Pull requests are welcome. For development setup:
git clone https://github.com/univpancasila/storageup-facade.git
cd storageup-facade
composer install
composer test
Report security issues to [email protected] instead of the issue tracker.
MIT — see LICENSE.