{"id":14109446,"url":"https://github.com/spatie/laravel-deleted-models","last_synced_at":"2025-05-14T20:10:28.239Z","repository":{"id":65224882,"uuid":"588046834","full_name":"spatie/laravel-deleted-models","owner":"spatie","description":"Automatically copy deleted records to a separate table","archived":false,"fork":false,"pushed_at":"2025-05-12T19:45:24.000Z","size":144,"stargazers_count":390,"open_issues_count":0,"forks_count":26,"subscribers_count":5,"default_branch":"main","last_synced_at":"2025-05-12T20:50:04.424Z","etag":null,"topics":["deletion","eloquent","laravel","php"],"latest_commit_sha":null,"homepage":"https://freek.dev/2416-a-package-to-automatically-copy-deleted-records-to-a-separate-table","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/spatie.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"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}},"created_at":"2023-01-12T07:41:48.000Z","updated_at":"2025-05-12T19:45:22.000Z","dependencies_parsed_at":"2023-02-14T18:45:59.073Z","dependency_job_id":"7aafb1d2-fc75-46f7-9bec-df58959d5085","html_url":"https://github.com/spatie/laravel-deleted-models","commit_stats":{"total_commits":68,"total_committers":7,"mean_commits":9.714285714285714,"dds":0.5588235294117647,"last_synced_commit":"1932c6b9fb6925958fd6e60ec9e03ab59a7ed464"},"previous_names":[],"tags_count":14,"template":false,"template_full_name":"spatie/package-skeleton-laravel","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spatie%2Flaravel-deleted-models","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spatie%2Flaravel-deleted-models/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spatie%2Flaravel-deleted-models/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spatie%2Flaravel-deleted-models/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/spatie","download_url":"https://codeload.github.com/spatie/laravel-deleted-models/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253823352,"owners_count":21969844,"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","eloquent","laravel","php"],"created_at":"2024-08-14T10:02:18.714Z","updated_at":"2025-05-14T20:10:28.216Z","avatar_url":"https://github.com/spatie.png","language":"PHP","funding_links":[],"categories":["PHP"],"sub_categories":[],"readme":"# Automatically copy deleted records to a separate table\n\n[![Latest Version on Packagist](https://img.shields.io/packagist/v/spatie/laravel-deleted-models.svg?style=flat-square)](https://packagist.org/packages/spatie/laravel-deleted-models)\n[![GitHub Tests Action Status](https://img.shields.io/github/actions/workflow/status/spatie/laravel-deleted-models/run-tests.yml?branch=main\u0026label=tests\u0026style=flat-square)](https://github.com/spatie/laravel-deleted-models/actions?query=workflow%3Arun-tests+branch%3Amain)\n[![GitHub Code Style Action Status](https://img.shields.io/github/actions/workflow/status/spatie/laravel-deleted-models/fix-php-code-style-issues.yml?branch=main\u0026label=code%20style\u0026style=flat-square)](https://github.com/spatie/laravel-deleted-models/actions?query=workflow%3A\"Fix+PHP+code+style+issues\"+branch%3Amain)\n[![Total Downloads](https://img.shields.io/packagist/dt/spatie/laravel-deleted-models.svg?style=flat-square)](https://packagist.org/packages/spatie/laravel-deleted-models)\n\nWhen deleting an Eloquent model, this package will copy the attributes of that model to a new table called `deleted_models`. You can view this as a sort of \"Recycle bin for models\".\n\n```php\n$blogPost = BlogPost::find(5); // an Eloquent model\n\n$blogPost-\u003edelete(); // values will be copied to the `deleted_models` table.\n```\n\nTo restore a previous model you can call `restore` and pass the id.\n\n```php\n$blogPost = BlogPost::restore(5); // $blogPost will be restored and returned\n```\n\nThis way of preserving information when deleting can be seen as an alternative to soft deletes. You can read more on the trade-offs [in this blog post](https://freek.dev/2416-a-package-to-automatically-copy-deleted-records-to-a-separate-table).\n\n## Support us\n\n[\u003cimg src=\"https://github-ads.s3.eu-central-1.amazonaws.com/laravel-deleted-models.jpg?t=1\" width=\"419px\" /\u003e](https://spatie.be/github-ad-click/laravel-deleted-models)\n\nWe invest a lot of resources into creating [best in class open source packages](https://spatie.be/open-source). You can support us by [buying one of our paid products](https://spatie.be/open-source/support-us).\n\nWe highly appreciate you sending us a postcard from your hometown, mentioning which of our package(s) you are using. You'll find our address on [our contact page](https://spatie.be/about-us). We publish all received postcards on [our virtual postcard wall](https://spatie.be/open-source/postcards).\n\n## Installation\n\nYou can install the package via composer:\n\n```bash\ncomposer require spatie/laravel-deleted-models\n```\n\nTo create the `deleted_models` table, you can publish and run the migrations with:\n\n```bash\nphp artisan vendor:publish --tag=\"deleted-models-migrations\"\nphp artisan migrate\n```\n\nOptionally, you can publish the config file with:\n\n```bash\nphp artisan vendor:publish --tag=\"deleted-models-config\"\n```\n\nThis is the contents of the published config file:\n\n```php\nreturn [\n    /*\n     * The model uses to store deleted models.\n     */\n    'model' =\u003e Spatie\\DeletedModels\\Models\\DeletedModel::class,\n\n    /*\n     * After this amount of days, the records in `deleted_models` will be deleted\n     *\n     * This functionality uses Laravel's native pruning feature.\n     */\n    'prune_after_days' =\u003e 365,\n];\n```\n\nThe pruning of the `deleted_models` table depends on Laravel's native pruning feature. Don't forget to schedule the `model:prune` as instructed [in Laravel's docs](https://laravel.com/docs/9.x/eloquent#pruning-models).\n\n```php\n$schedule-\u003ecommand('model:prune', [\n    '--model' =\u003e [\\Spatie\\DeletedModels\\Models\\DeletedModel::class],\n])-\u003edaily();\n```\n\n## Usage\n\nYou should add the `KeepsDeletedModels` trait to all models whose attributes should be written to `deleted_models` whenever the model is deleted.\n\n```php\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Spatie\\DeletedModels\\Models\\Concerns\\KeepsDeletedModels;\n\nclass BlogPost extends Model\n{\n    use KeepsDeletedModels;\n}\n```\n\nWith this in place, the attributes will be written to `deleted_models` when the model is deleted.\n\n```php\n$blogPost = BlogPost::find(5);\n\n$blogPost-\u003edelete(); // values will be copied to the `deleted_models` table.\n```\n\nTo restore a previous model you can call `restore` and pass the id.\n\n```php\n$blogPost = BlogPost::restore(5); // $blogPost will be restored and returned\n```\n\nIf the model to be restored can't be found in the `deleted_models` table, a `Spatie\\DeletedModels\\Exceptions\\NoModelFoundToRestore` exception will be thrown.\n\n### Restoring without saving\n\nTo restore in memory, without actually saving it, you can call `makeRestored`.\nKeep in mind that calling this method will also remove the record in the `deleted_models_table`.\n\n```php\n// $blogPost will be return, but it is not saved in the db yet\n$blogPost = Blogpost::makeRestored($id); \n\n$blogPost-\u003esave();\n```\n\nIf the model to be restored can't be found in the `deleted_models` table, `null` will be returned by `makeRestored`.\n\n### Restoring without emitting events\n\nBy default, the `Spatie\\DeletedModels\\Events\\RestoringDeletedModelEvent` and `Spatie\\DeletedModels\\Events\\DeletedModelEvent` will be dispatched when calling `restore` on a model.\n\nIf you don't want these events to be dispatched, call `restoreQuietly`.\n\n```php\nBlogPost::restoreQuietly(); // no events will be dispatched\n```\n\n### Customizing the restore process\n\n#### Using closures passed to `restore`\n\nThe `restore` function accepts a callable as the second argument. The `beforeSaving` callable will be executed when the restored model was created in memory, but before saving it in the db.\n\n```php\nBlogPost::restore(5, function(BlogPost $post, DeletedModel $deletedModel) {\n    $post-\u003etitle = \"{$post-\u003etitle} (restored)\";\n})\n```\n\n#### Using methods on the model\n\nIf you need to run some logic to before and after restoring a model, you can implement `beforeRestoringModel` and `afterRestoringModel` on your model.\n\n```php\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Spatie\\DeletedModels\\Models\\Concerns\\KeepsDeletedModels;\n\nclass BlogPost extends Model\n{\n    use KeepsDeletedModels;\n    \n    public static function beforeRestoringModel(DeletedModel $deletedModel): void\n    {\n        // this will be executed right before restoring a model\n    }\n\n    public static function afterRestoringModel(\n        Model $restoredMode,\n        DeletedModel $deletedModel\n    ): void\n    {\n        // this will be executed right after restoring a model\n    }\n}\n```\n\nTo determine which attributes and values should be kept in `deleted_models`, you can implement `attributesToKeep`\n\n```php\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Spatie\\DeletedModels\\Models\\Concerns\\KeepsDeletedModels;\n\nclass BlogPost extends Model\n{\n    use KeepsDeletedModels;\n    \n    public function attributesToKeep(): array\n    {\n        // here you can customize which values should be kept. This is\n        // the default implementation.\n        \n        return $this-\u003etoArray();\n    }\n}\n```\n\n### Pruning deleted models\n\nAfter a while, the `deleted_models` table can become large. The `DeletedModel` implements [Laravel's native `MassPrunable` trait](https://laravel.com/docs/9.x/eloquent#pruning-models).\n\nYou can configure the number of days records in the `deleted_models` will be pruned in the `prune_after_days` key of the `deleted-models.php` config file. By default, all deleted models will be kept for 365 days.\n\nDon't forget to schedule the `model:prune` as instructed [in Laravel's docs](https://laravel.com/docs/9.x/eloquent#pruning-models).\n\n### Low-level customization of the delete and restoration process\n\nThe `DeletedModel` model implements most logic to keep and restore deleted models. You can modify any of the behaviour by creating a class that extends `Spatie\\DeletedModels\\Models\\DeletedModel`. You should put the class name of your extended class in the `model` key of the `deleted-models.php` config file.\n\nWith this in place you can override any of the methods in `DeletedModel`.\n\n```php\nuse Spatie\\DeletedModels\\Models\\DeletedModel;\n\nclass CustomDeletedModel extends DeletedModel\n{\n    protected function makeRestoredModel(string $modelClass): mixed\n    {\n        // add custom logic\n    \n        return parent::makeRestoredModel($modelClass)\n    }\n}\n```\n\n## Testing\n\n```bash\ncomposer test\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- [Freek Van der Herten](https://github.com/freekmurze)\n- [All Contributors](../../contributors)\n\nThis package was inspired by these two blog posts:\n- [Easy, alternative soft deletion](https://brandur.org/fragments/deleted-record-insert) \n- [this one](Soft Deletion Probably Isn't Worth It).\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%2Fspatie%2Flaravel-deleted-models","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fspatie%2Flaravel-deleted-models","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fspatie%2Flaravel-deleted-models/lists"}