kdabrow/time-machine
Composer 安装命令:
composer require --dev kdabrow/time-machine
包简介
Laravel / Lumen library that allows to change dates in db
README 文档
README
Time machine
This package allows to move in time database data. It automatically selects all fields that store datetime and move them by given period or to particular date, relatively from it current value. See example to check more details.
Motivation
This package might be useful in a pre-prod environment to test log lasting processes. For example
generating customer invoice. Usually invoices are generated in a 30 days period. You might move
customer and all it's data into previous invoice cycle (30 days in to past) and effectively simulate
whole invoice cycle like that customer was created 30 days ago.
Installation
First install main package:
composer require kdabrow/time-machine
Then install database driver package:
| Database | Driver |
|---|---|
| mysql | composer require kdabrow/time-machine-mysql |
| postgres | composer require kdabrow/time-machine-postgres |
Advice is to install those packages as --dev dependencies.
Usage
Time traveller setup
First create TimeTraveller. Only Eloquent model can be TimeTraveller. Basic configuration look like this:
<?php use Kdabrow\TimeMachine\TimeTraveller; use App\Models\User; // provide model instance $traveller = new TimeTraveller(new User()); // or class name $traveller = new TimeTraveller(User::class);
Modify query
TimeMachine by default selects all rows related to given to TimeTraveller model. You're able to provide your conditions to restrict query
<?php use Illuminate\Database\Eloquent\Builder; use App\Models\User; use App\Models\Group; use Kdabrow\TimeMachine\TimeTraveller; use Kdabrow\TimeMachine\Result; use Illuminate\Support\Arr; // Result contains all previously changed models from all TimeTravellers // For example move Users only from previously changed Group $traveller = new TimeTraveller( User::class, function(Builder $builder, Result $result) { if ($result->isSuccessful(Group::class)) { return $query->whereIn( 'group_id', $result->getSuccessful(Group::class)->pluck('id') ); } } );
Additional columns
It's possible to add additional columns into query.
<?php use App\Models\User; use Kdabrow\TimeMachine\TimeTraveller; use Kdabrow\TimeMachine\Database\Column; use Kdabrow\TimeMachine\Result; use Illuminate\Database\Eloquent\Model; $traveller = new TimeTraveller(User::class); $traveller->alsoChange('date_of_creation'); // It's possible to provide callback and determine how given field should be changed // Column object has information about currently modified column // Model is selected instance of User // Result contains previously moved in time data // In this example only move if no errors appeared during previous time travels $traveller->alsoChange( 'date_of_creation', function($currentValue, Column $column, Model $model, Result $result) { if (count($result->getAllFailed())) { return $currentValue; } return null; } );
Exclude fields
Sometimes is need to omit some fields that would usually be selected to change.
<?php use App\Models\User; use Kdabrow\TimeMachine\TimeTraveller; $traveller = new TimeTraveller(User::class); $traveller->exclude('date_of_birth');
Set up keys
Records selected to time travel are based on primary key from the model. You're able to overwrite it.
<?php use App\Models\User; use Kdabrow\TimeMachine\TimeTraveller; $traveller = new TimeTraveller(User::class); $traveller->setKeys(['uuid']);
Time machine and direction of move
After TimeTravellers are created, create TimeMachine.
<?php use Kdabrow\TimeMachine\TimeMachine; $timeMachine = new TimeMachine(); // now add previously created TimeTravellers $timeMachine->take($traveller1); $timeMachine->take($traveller2); $timeMachine->take($traveller3);
Move to the past
First create DateChooser. It is information about period or date.
<?php use Kdabrow\TimeMachine\DateChooser; use Kdabrow\TimeMachine\Result; use DateInterval; // move by DateInterval $chooser = new DateChooser(new DateInterval("P1D")); // Move by 1 day // or move by some specific amount of seconds $chooser = new DateChooser(3600); // Move by 1 hour // Now set up direction and start travel /** @var Result $result */ $result = $timeMachine ->toPast($chooser) ->start();
Move to the future
First create DateChooser. It is information about period or date.
<?php use Kdabrow\TimeMachine\DateChooser; use Kdabrow\TimeMachine\Result; use DateInterval; // move by DateInterval $chooser = new DateChooser(new DateInterval("P1D")); // Move by 1 day // or move by some specific amount of seconds $chooser = new DateChooser(3600); // Move by 1 hour // Now set up direction and start travel /** @var Result $result */ $result = $timeMachine ->toFuture($chooser) ->start();
Move to particular date
First create DateChooser. It is information about period or date.
<?php use Kdabrow\TimeMachine\DateChooser; use Kdabrow\TimeMachine\Result; use DateTime; // put DateTimeInterface object $chooser = new DateChooser(new DateTime("2020-15-16 12:12:12")); // Move datetime columns to 2020-15-16 12:12:12 // or provide datetime string $chooser = new DateChooser("2020-15-16 12:12:12"); // Move to 2020-15-16 12:12:12 // Now set up direction and start travel /** @var Result $result */ $result = $timeMachine ->toDate($chooser) ->start();
Examples
Move customer, it's payments and orders 10 days in the past
Database structure before and after change:
customers (before)
| id | date_of_birth | activated_at | created_at | updated_at | |
|---|---|---|---|---|---|
| 100 | tesla@test.com | 1856-07-10 | 2000-06-15 12:12:12 | 1999-06-15 12:12:12 | 1999-06-15 12:12:12 |
customers (after)
| id | date_of_birth | activated_at | created_at | updated_at | |
|---|---|---|---|---|---|
| 100 | tesla@test.com | 1856-07-10 | 2000-06-05 12:12:12 | 1999-06-05 12:12:12 | 1999-06-05 12:12:12 |
payments (before)
| id | customer_id | amount | paid_at | created_at | updated_at |
|---|---|---|---|---|---|
| 200 | 100 | 120 | 2020-03-24 13:10:45 | 2020-03-24 10:10:45 | 2020-03-24 13:10:45 |
payments (after)
| id | customer_id | amount | paid_at | created_at | updated_at |
|---|---|---|---|---|---|
| 200 | 100 | 120 | 2020-03-14 13:10:45 | 2020-03-14 10:10:45 | 2020-03-14 13:10:45 |
orders
| id | payment_id | name | sent_at | created_at | updated_at |
|---|---|---|---|---|---|
| 300 | 200 | Engine | 2020-03-25 | 2020-03-24 13:11:22 | 2020-03-25 15:32:17 |
orders
| id | payment_id | name | sent_at | created_at | updated_at |
|---|---|---|---|---|---|
| 300 | 200 | Engine | 2020-03-15 | 2020-03-14 13:11:22 | 2020-03-15 15:32:17 |
Script:
<?php use Kdabrow\TimeMachine\TimeTraveller; use Kdabrow\TimeMachine\Result; use Kdabrow\TimeMachine\TimeMachine; use App\Models\Customer; use App\Models\Payment; use App\Models\Order; use Illuminate\Support\Arr; $customerId = 100; $customerTraveller = new TimeTraveller( Customer::class, function(Builder $builder, Result $result) use ($customerId) { return $builder->where('id', '=', $customerId); } ); $customerTraveller->exclude('date_of_birth'); $paymentTraveller = new TimeTraveller( Payment::class, function(Builder $builder, Result $result) use ($customerId) { if ($result->isSuccessful(Customer::class)) { return $builder->whereIn( 'customer_id', $result->getSuccessful(Customer::class)->pluck('id') ); } } ); $orderTraveller = new TimeTraveller( Order::class, function(Builder $builder, Result $result) use ($customerId) { if ($result->isSuccessful(Payment::class)) { return $builder->whereIn( 'payment_id', $result->getSuccessful(Payment::class)->pluck('id') ); } } ); $timeMachine = new TimeMachine(); $result = $timeMachine ->take($customerTraveller) ->take($paymentTraveller) ->take($orderTraveller) ->toPast(new DateInterval("P10D")) ->start(); // Get instances that failed time travel $failed = $result->getAllFailed(); $sucessful = $result->getAllSuccessful();
Testing
Run tests from docker container
docker-compose exec php vendor/bin/phpunit
or directly from your machine
vendor/bin/phpunit
kdabrow/time-machine 适用场景与选型建议
kdabrow/time-machine 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 6.07k 次下载、GitHub Stars 达 5, 最近一次更新时间为 2020 年 06 月 15 日, 在 PHP 生态内属于活跃度较高的组件。
它主要适用于以下技术方向: 「database」 「php」 「testing」 「laravel」 「integration」 「dates」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。
我们在过去多个企业项目中使用过 kdabrow/time-machine 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。
基于 kdabrow/time-machine 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。
线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。
承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。
与 kdabrow/time-machine 相关的其它包
同方向 / 同关键字的高下载量 PHP Composer 包推荐,方便对比选型:
Dibi is Database Abstraction Library for PHP
Testing Suite For Lumen like Laravel does.
Store your language lines in the database, yaml or other sources
A package for automatically encrypting and decrypting Eloquent attributes in Laravel 5.5+, based on configuration settings.
A PSR-7 compatible library for making CRUD API endpoints
The PHP SDK for Checkmango
统计信息
- 总下载量: 6.07k
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 5
- 点击次数: 11
- 依赖项目数: 2
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2020-06-15