aaronheath / laravel-model-copy
Copy one Laravel Eloquent model from one table to another.
Installs: 1 416
Dependents: 0
Suggesters: 0
Security: 0
Stars: 1
Watchers: 2
Forks: 2
Open Issues: 1
Requires
- php: ^7.4|^8.0
- aaronheath/class-logger: ^1.0
- illuminate/support: ^8.61|^9.0
Requires (Dev)
- orchestra/testbench: ^6.21
- phpunit/phpunit: ^9
- sempro/phpunit-pretty-print: ^1.4
- spatie/laravel-ray: ^1.17
This package is auto-updated.
Last update: 2025-02-15 01:21:28 UTC
README
Laravel model copy helps you copy, move records from one database table to another. This solution is designed for moving un-needed records to another table in a safe manner which can then be backed-up and, if need, truncated.
The package is also able to assist in performing batch model deletions over using the same conditions as are made available when copying models.
Installation
You can install the package via composer:
composer require aaronheath/laravel-model-copy
Usage
The package can be used in one of three ways:
- A) Copy or move an individual model.
- B) Batch copy or move many models from a query.
- C) Batch deletion of models from a query.
Copy or move individual model
Copying an individual model is as easy as...
<?php use Heath\LaravelModelCopy\Action\CopyModel; use App\Models\ExampleA; use App\Models\ExampleB; CopyModel::make() ->copy(Example::find(1)) ->to(ExampleB::class) ->run();
Copying an individual model and deleting the original record is a easy as including ->deleteOriginal()
.
<?php use Heath\LaravelModelCopy\Action\CopyModel; use App\Models\ExampleA; use App\Models\ExampleB; CopyModel::make() ->copy(Example::find(1)) ->to(ExampleB::class) ->deleteOriginal() ->run();
We may not want to copy or move the model if it's after a certain time. This can be achieved by including ->processBefore(now()->addHour())
<?php use Heath\LaravelModelCopy\Action\CopyModel; use App\Models\ExampleA; use App\Models\ExampleB; CopyModel::make() ->copy(Example::find(1)) ->to(ExampleB::class) ->processBefore(now()->addHour()) ->run();
Batch copy or move many models from a query
Most likely you won't be wanting to move just one record, this is where batch copying or moving comes into play.
Here's a simple batch copy which will make a copy of all model ExampleA records where they were handled_at
more than three years ago.
<?php use Heath\LaravelModelCopy\Action\BatchCopyModels; use App\Models\ExampleA; use App\Models\ExampleB; BatchCopyModels::make() ->to(ExampleB::class) ->query( ExampleA::where('handled_at', '<', now()->subYears(3)) ) ->run();
If we want to instead delete the original model, all we need to do is include ->deleteOriginal()
.
<?php use Heath\LaravelModelCopy\Action\BatchCopyModels; use App\Models\ExampleA; use App\Models\ExampleB; BatchCopyModels::make() ->to(ExampleB::class) ->query( ExampleA::where('handled_at', '<', now()->subYears(3)) ) ->deleteOriginal() ->run();
If we want limit on how many records we want to copy / move in one go, we can use ->limit(1000)
.
<?php use Heath\LaravelModelCopy\Action\BatchCopyModels; use App\Models\ExampleA; use App\Models\ExampleB; BatchCopyModels::make() ->to(ExampleB::class) ->query( ExampleA::where('handled_at', '<', now()->subYears(3)) ) ->limit(1000) ->run();
By default queries will be chunked into 100 record batches. If you wish to use your own chunking value, this can be achieved by ->chunk(500)
.
<?php use Heath\LaravelModelCopy\Action\BatchCopyModels; use App\Models\ExampleA; use App\Models\ExampleB; BatchCopyModels::make() ->to(ExampleB::class) ->query( ExampleA::where('handled_at', '<', now()->subYears(3)) ) ->chunk(500) ->run();
To use a custom (not 'id') column to chunk by use ->chunkColumn()
.
<?php use Heath\LaravelModelCopy\Action\BatchCopyModels; use App\Models\ExampleA; use App\Models\ExampleB; BatchCopyModels::make() ->to(ExampleB::class) ->query( ExampleA::where('handled_at', '<', now()->subYears(3)) ) ->chunk(500) ->chunkColumn('created_at') ->run();
Up until now, all actions happen in one syncronious stream. In real world situation it's better to process individual copy / move model actions by pushing them to the queue. This can be achieved by including ->copyModelsAsJobs()
.
<?php use Heath\LaravelModelCopy\Action\BatchCopyModels; use App\Models\ExampleA; use App\Models\ExampleB; BatchCopyModels::make() ->to(ExampleB::class) ->query( ExampleA::where('handled_at', '<', now()->subYears(3)) ) ->copyModelsAsJobs() ->run();
If a queue besides the default wants to be used, then include ->onQueue('queue-name')
.
<?php use Heath\LaravelModelCopy\Action\BatchCopyModels; use App\Models\ExampleA; use App\Models\ExampleB; BatchCopyModels::make() ->to(ExampleB::class) ->query( ExampleA::where('handled_at', '<', now()->subYears(3)) ) ->copyModelsAsJobs() ->onQueue('queue-name') ->run();
When moving large sets of data it may take quite some time. In these cases you may want to group your moving batches into blocks of time. Let's say we want to run the script nightly at 23:00 and want to make sure we stop moving copying models at 05:00 the next day. This can be achieved by using ->processBefore(now()->addDay()->setTime(5, 0, 0)
.
<?php use Heath\LaravelModelCopy\Action\BatchCopyModels; use App\Models\ExampleA; use App\Models\ExampleB; BatchCopyModels::make() ->to(ExampleB::class) ->query( ExampleA::where('handled_at', '<', now()->subYears(3)) ) ->copyModelsAsJobs() ->processBefore(now()->addDay()->setTime(5, 0, 0)) // 05:00 tomorrow ->run();
We may also want to limit how many records are copied / moved in any given minute. To do this a rate per minute (rpm) can be defined. If we're wanting to ensure that we only copy 20 records per minute then we can use ->rpm(20)
. Using this feature requires ->copyModelsAsJobs()
to be used.
<?php use Heath\LaravelModelCopy\Action\BatchCopyModels; use App\Models\ExampleA; use App\Models\ExampleB; BatchCopyModels::make() ->to(ExampleB::class) ->query( ExampleA::where('handled_at', '<', now()->subYears(3)) ) ->copyModelsAsJobs() ->rpm(20) ->run();
Real world example
Let's say we want to move all records that were handled_at
over three years ago to another table. We want to only have the run until 06:00 the next day. We also want to limit load on the database, so we'll only move 100 records per minute. To achieve this we'd use the following...
<?php use Heath\LaravelModelCopy\Action\BatchCopyModels; use App\Models\ExampleA; use App\Models\ExampleB; BatchCopyModels::make() ->to(ExampleB::class) ->query( ExampleA::where('handled_at', '<', now()->subYears(3)) ) ->copyModelsAsJobs() ->processBefore(now()->addDay()->setTime(6, 0, 0)) // 06:00 tomorrow ->rpm(100) ->run();
Delete individual model
Deleting an individual model is as easy as...
<?php use Heath\LaravelModelCopy\Action\DeleteModel; use App\Models\ExampleA; DeleteModel::make() ->delete(ExampleA::find(1)) ->run();
Batch deleting models from a query
Most likely you won't be wanting to delete just one record, this is where batch deleting comes into play.
Here's a simple batch delete which will delete all model ExampleA records where they were handled_at
more than three years ago.
<?php use Heath\LaravelModelCopy\Action\BatchDeleteModels; use App\Models\ExampleA; BatchDeleteModels::make() ->query( ExampleA::where('handled_at', '<', now()->subYears(3)) ) ->run();
If we want limit on how many records we want to delete in one go, we can use ->limit(1000)
.
<?php use Heath\LaravelModelCopy\Action\BatchDeleteModels; use App\Models\ExampleA; BatchDeleteModels::make() ->query( ExampleA::where('handled_at', '<', now()->subYears(3)) ) ->limit(1000) ->run();
By default queries will be chunked into 100 record batches. If you wish to use your own chunking value, this can be achieved by ->chunk(500)
.
<?php use Heath\LaravelModelCopy\Action\BatchDeleteModels; use App\Models\ExampleA; BatchDeleteModels::make() ->query( ExampleA::where('handled_at', '<', now()->subYears(3)) ) ->chunk(500) ->run();
To use a custom (not 'id') column to chunk by use ->chunkColumn()
.
<?php use Heath\LaravelModelCopy\Action\BatchDeleteModels; use App\Models\ExampleA; BatchDeleteModels::make() ->query( ExampleA::where('handled_at', '<', now()->subYears(3)) ) ->chunk(500) ->chunkColumn('created_at') ->run();
Up until now, all actions happen in one syncronious stream. In real world situation it's better to process individual model deletion actions by pushing them to the queue. This can be achieved by including ->copyModelsAsJobs()
.
<?php use Heath\LaravelModelCopy\Action\BatchDeleteModels; use App\Models\ExampleA; BatchDeleteModels::make() ->query( ExampleA::where('handled_at', '<', now()->subYears(3)) ) ->deleteModelsAsJobs() ->run();
If a queue besides the default wants to be used, then include ->onQueue('queue-name')
.
<?php use Heath\LaravelModelCopy\Action\BatchDeleteModels; use App\Models\ExampleA; BatchDeleteModels::make() ->query( ExampleA::where('handled_at', '<', now()->subYears(3)) ) ->deleteModelsAsJobs() ->onQueue('queue-name') ->run();
When deleting large sets of data it may take quite some time. In these cases you may want to group your deleting batches into blocks of time. Let's say we want to run the script nightly at 23:00 and want to make sure we stop moving deleting models at 05:00 the next day. This can be achieved by using ->processBefore(now()->addDay()->setTime(5, 0, 0)
.
<?php use Heath\LaravelModelCopy\Action\BatchDeleteModels; use App\Models\ExampleA; BatchCopyModels::make() ->query( ExampleA::where('handled_at', '<', now()->subYears(3)) ) ->deleteModelsAsJobs() ->processBefore(now()->addDay()->setTime(5, 0, 0)) // 05:00 tomorrow ->run();
We may also want to limit how many records are deleted in any given minute. To do this a rate per minute (rpm) can be defined. If we're wanting to ensure that we only delete 20 records per minute then we can use ->rpm(20)
. Using this feature requires ->copyModelsAsJobs()
to be used.
<?php use Heath\LaravelModelCopy\Action\BatchDeleteModels; use App\Models\ExampleA; BatchDeleteModels::make() ->query( ExampleA::where('handled_at', '<', now()->subYears(3)) ) ->deleteModelsAsJobs() ->rpm(20) ->run();
Testing
composer test
Credits
License
The MIT License (MIT). Please see License File for more information.