{"id":21558728,"url":"https://github.com/medilies/rm-q","last_synced_at":"2026-05-20T09:07:15.561Z","repository":{"id":254631991,"uuid":"847103868","full_name":"medilies/rm-q","owner":"medilies","description":"Queue and avoid disastrous file deletions.","archived":false,"fork":false,"pushed_at":"2024-09-02T20:38:04.000Z","size":74,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-01-24T10:47:36.666Z","etag":null,"topics":["deletion","file","laravel","rollback","safe","transaction"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/medilies.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"medilies"}},"created_at":"2024-08-24T21:25:48.000Z","updated_at":"2024-09-02T20:38:07.000Z","dependencies_parsed_at":"2024-08-27T22:04:51.115Z","dependency_job_id":null,"html_url":"https://github.com/medilies/rm-q","commit_stats":null,"previous_names":["medilies/rm-q"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/medilies%2Frm-q","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/medilies%2Frm-q/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/medilies%2Frm-q/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/medilies%2Frm-q/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/medilies","download_url":"https://codeload.github.com/medilies/rm-q/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244153327,"owners_count":20406995,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["deletion","file","laravel","rollback","safe","transaction"],"created_at":"2024-11-24T08:15:40.047Z","updated_at":"2026-05-20T09:07:10.540Z","avatar_url":"https://github.com/medilies.png","language":"PHP","funding_links":["https://github.com/sponsors/medilies"],"categories":[],"sub_categories":[],"readme":"# Queue and avoid disastrous file deletions\n\n[![Latest Version on Packagist](https://img.shields.io/packagist/v/medilies/rm-q.svg?style=flat-square)](https://packagist.org/packages/medilies/rm-q)\n[![GitHub Tests Action Status](https://img.shields.io/github/actions/workflow/status/medilies/rm-q/run-tests.yml?branch=main\u0026label=tests\u0026style=flat-square)](https://github.com/medilies/rm-q/actions?query=workflow%3Arun-tests+branch%3Amain)\n[![phpstan](https://img.shields.io/github/actions/workflow/status/medilies/rm-q/phpstan.yml?branch=main\u0026label=phpstan\u0026style=flat-square)](https://github.com/medilies/rm-q/actions?query=workflow%3A\"phpstan\"+branch%3Amain)\n\u003c!-- [![Total Downloads](https://img.shields.io/packagist/dt/medilies/rm-q.svg?style=flat-square)](https://packagist.org/packages/medilies/rm-q) --\u003e\n\n\u003cdiv style=\"text-align: center;\"\u003e\n  \u003cimg src=\"./concept-meme.webp\" alt=\"concept meme\" width=\"666px\"\u003e\n\u003c/div\u003e\n\nSince file deletion is often irreversible, this Laravel package queues file deletions within a database transaction, allowing for rollback in case of errors.\n\n## The problem\n\nLet's say you have a use case that resembles this:\n\n```php\nuse Illuminate\\Support\\Facades\\DB;\nuse Illuminate\\Support\\Facades\\Storage;\n\nDB::transaction(function () use ($images) {\n    /** @var \\App\\Models\\Image $image */\n    foreach ($images as $image) {\n        $image-\u003edelete();\n        Storage::delete($image-\u003epath);\n\n        // more logic ...\n    }\n});\n```\n\nIf an error occurs while handling the second image, the database rows for both the first and second images will be rolled back by the transaction, but the actual file for the first image will be gone forever.\n\n## The solution\n\n```php\nuse Illuminate\\Support\\Facades\\Storage;\nuse Medilies\\RmQ\\Facades\\RmQ;\n\nRmQ::transaction(function () use ($images) {\n    /** @var \\App\\Models\\Image $image */\n    foreach ($images as $image) {\n        $image-\u003edelete();\n        RmQ::stage($image-\u003epath);\n\n        // more logic ...\n    }\n});\n\nRmQ::delete();\n```\n\nThis way, the file deletion is queued and the deletion can be fully rolled back.\n\n## Installation\n\nRequirements:\n\n- PHP \u003e= 8.2\n- Laravel \u003e= 10 (not tested on older versions).\n\nInstall the package via composer:\n\n```bash\ncomposer require medilies/rm-q\n```\n\nPublish and run the migrations with:\n\n```bash\nphp artisan vendor:publish --tag=\"rm-q-migrations\"\nphp artisan migrate\n```\n\nYou can publish the config file with:\n\n```bash\nphp artisan vendor:publish --tag=\"rm-q-config\"\n```\n\n## Usage\n\n### Phase 1: Staging the files\n\n```php\nuse Medilies\\RmQ\\Facades\\RmQ;\n\nRmQ::transaction(function () {\n    // ...\n    \n    $files = '/path/to/file';\n    // or\n    $files = [\n        '/path/to/file1',\n        '/path/to/file2',\n    ];\n\n    // ...\n\n    RmQ::stage($files);\n});\n```\n\n\u003e [!IMPORTANT]  \n\u003e If you use `DB::transaction` instead of `RmQ::transaction` make sure to not call `Rmq::stage` within a loop since each call will perform a database insertion.\n\u003e\n\u003e Using the middleware will optimize the performance further more by not doing any query until the end of the request performing a total of 1 to 3 queries.\n\n### Phase 2: Deleting the files\n\nDelete the files staged by the singleton:\n\n```php\nuse Medilies\\RmQ\\Facades\\RmQ;\n\nRmQ::delete();\n```\n\nDelete all the staged files:\n\n```php\nuse Medilies\\RmQ\\Facades\\RmQ;\n\nRmQ::deleteAll();\n```\n\nDelete all the staged files using a command (you can also [schedule](https://laravel.com/docs/11.x/scheduling#scheduling-artisan-commands) it):\n\n```shell\nphp artisan rm-q:delete\n```\n\n\u003e `deleteAll` takes into consideration the `after` config to fetch staged entries.\n\nAutomatically delete the staged files at the end of the request using the middleware:\n\n```php\nuse Medilies\\RmQ\\Middleware\\RmqMiddleware;\n\nRoute::put('edit-user-details', function (Request $request) {\n    // ...\n})-\u003emiddleware(RmqMiddleware::class);\n```\n\n## Changelog\n\nPlease see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently.\n\n## Contributing\n\nPlease see [CONTRIBUTING](CONTRIBUTING.md) for details.\n\n## Security Vulnerabilities\n\nPlease review [our security policy](../../security/policy) on how to report security vulnerabilities.\n\n## Credits\n\n- [medilies](https://github.com/medilies)\n- [All Contributors](../../contributors)\n\n## License\n\nThe MIT License (MIT). Please see [License File](LICENSE.md) for more information.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmedilies%2Frm-q","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmedilies%2Frm-q","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmedilies%2Frm-q/lists"}