From 875fb77124d877eb5f260087981377329a7ef34d Mon Sep 17 00:00:00 2001 From: nojimage Date: Wed, 24 Apr 2019 10:42:20 +0900 Subject: [PATCH] ADD time_interval_int type --- README.md | 6 +- config/bootstrap.php | 2 + src/Database/Type/TimeIntervalAsIntType.php | 67 ++++++++++ .../Type/TimeIntervalMarshalTrait.php | 38 ++++++ src/Database/Type/TimeIntervalType.php | 35 +---- tests/Fixture/WorkTimesFixture.php | 7 +- .../Type/BaseTimeIntervalTypeTest.php | 120 ++++++++++++++++++ .../Type/TimeIntervalAsIntTypeTest.php | 57 +++++++++ .../Database/Type/TimeIntervalTypeTest.php | 94 +------------- .../Model/Table/WorkTimesTableTest.php | 31 +++++ tests/test_models.php | 6 + 11 files changed, 336 insertions(+), 127 deletions(-) create mode 100644 src/Database/Type/TimeIntervalAsIntType.php create mode 100644 src/Database/Type/TimeIntervalMarshalTrait.php create mode 100644 tests/TestCase/Database/Type/BaseTimeIntervalTypeTest.php create mode 100644 tests/TestCase/Database/Type/TimeIntervalAsIntTypeTest.php diff --git a/README.md b/README.md index 93b454d..d8b4548 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,8 @@

-This plugin provide `time_interval` custom type for MySQL's `TIME`, Postgres's `INTERVAL`. +This plugin provide `time_interval` custom type for MySQL's `TIME`, Postgres's `INTERVAL`, + and provide `time_interval_int` custom type for seconds as `INTEGER`. This is a custom type to represent intervals, which CakePHP can treat as a `TimeInterval` object that inherits from `DateInterval`. ## Installation @@ -59,6 +60,9 @@ class WorkTimesTable extends Table // CakePHP <= 3.4.x use columnType() instead. $schema->columnType('duration', 'time_interval'); + // If your column type is seconds as INTEGER, Use `time_interval_int` instead. + $schema->setColumnType('duration_sec', 'time_interval_int'); + return $schema; } } diff --git a/config/bootstrap.php b/config/bootstrap.php index dbd0704..7594cca 100644 --- a/config/bootstrap.php +++ b/config/bootstrap.php @@ -7,12 +7,14 @@ */ use Cake\Database\Type; use Cake\Validation\Validator; +use Elastic\TimeInterval\Database\Type\TimeIntervalAsIntType; use Elastic\TimeInterval\Database\Type\TimeIntervalType; use Elastic\TimeInterval\Validation\TimeIntervalValidation; $getMap = method_exists(Type::class, 'getMap') ? 'getMap' : 'map'; if (!Type::$getMap('time_interval')) { Type::map('time_interval', TimeIntervalType::class); + Type::map('time_interval_int', TimeIntervalAsIntType::class); } if (method_exists(Validator::class, 'addDefaultProvider')) { diff --git a/src/Database/Type/TimeIntervalAsIntType.php b/src/Database/Type/TimeIntervalAsIntType.php new file mode 100644 index 0000000..add9a73 --- /dev/null +++ b/src/Database/Type/TimeIntervalAsIntType.php @@ -0,0 +1,67 @@ +marshal($value); + } + + return $value->toSeconds(); + } + + /** + * {@inheritDoc} + */ + public function toStatement($value, Driver $driver) + { + if ($value === null) { + return PDO::PARAM_NULL; + } + + return PDO::PARAM_INT; + } +} diff --git a/src/Database/Type/TimeIntervalMarshalTrait.php b/src/Database/Type/TimeIntervalMarshalTrait.php new file mode 100644 index 0000000..3df84fc --- /dev/null +++ b/src/Database/Type/TimeIntervalMarshalTrait.php @@ -0,0 +1,38 @@ +marshal($value); } - return (string)$this->marshal($value); + return (string)$value; } } diff --git a/tests/Fixture/WorkTimesFixture.php b/tests/Fixture/WorkTimesFixture.php index d43366f..901a38e 100644 --- a/tests/Fixture/WorkTimesFixture.php +++ b/tests/Fixture/WorkTimesFixture.php @@ -19,6 +19,7 @@ class WorkTimesFixture extends TestFixture 'start' => ['type' => 'datetime', 'null' => false], 'end' => ['type' => 'datetime', 'null' => false], 'rest' => ['type' => 'time', 'null' => false, 'default' => '00:00:00'], + 'rest_seconds' => ['type' => 'integer', 'null' => false, 'default' => '0'], 'duration' => ['type' => 'time', 'null' => false, 'default' => '00:00:00'], '_constraints' => ['primary' => ['type' => 'primary', 'columns' => ['id']]], ]; @@ -29,8 +30,8 @@ class WorkTimesFixture extends TestFixture * @var array */ public $records = [ - ['start' => '2019-04-01 10:00:00', 'end' => '2019-04-01 19:00:00', 'rest' => '01:00:00', 'duration' => '08:00:00'], - ['start' => '2019-04-02 09:30:00', 'end' => '2019-04-02 12:30:00', 'rest' => '00:30:00', 'duration' => '02:30:00'], - ['start' => '2019-04-03 09:45:00', 'end' => '2019-04-04 19:30:00', 'rest' => '08:00:00', 'duration' => '25:45:00'], + ['start' => '2019-04-01 10:00:00', 'end' => '2019-04-01 19:00:00', 'rest' => '01:00:00', 'rest_seconds' => 3600, 'duration' => '08:00:00'], + ['start' => '2019-04-02 09:30:00', 'end' => '2019-04-02 12:30:00', 'rest' => '00:30:00', 'rest_seconds' => 1800, 'duration' => '02:30:00'], + ['start' => '2019-04-03 09:45:00', 'end' => '2019-04-04 19:30:00', 'rest' => '08:00:00', 'rest_seconds' => 28800, 'duration' => '25:45:00'], ]; } diff --git a/tests/TestCase/Database/Type/BaseTimeIntervalTypeTest.php b/tests/TestCase/Database/Type/BaseTimeIntervalTypeTest.php new file mode 100644 index 0000000..fb89a30 --- /dev/null +++ b/tests/TestCase/Database/Type/BaseTimeIntervalTypeTest.php @@ -0,0 +1,120 @@ +type, $this->driver); + parent::tearDown(); + } + + /** + * test convert DB to PHP + * + * @dataProvider dataToPHP + */ + public function testToPHP($database, $expected) + { + $result = $this->type->toPHP($database, $this->driver); + $this->assertInstanceOf(TimeInterval::class, $result); + $this->assertSame($expected, (string)$result); + } + + /** + * data for testToPHP + * + * @return array + */ + abstract public function dataToPHP(); + + /** + * test convert null value to PHP + */ + public function testToPHPWithNull() + { + $this->assertNull($this->type->toPHP(null, $this->driver)); + } + + /** + * test convert value + * + * @dataProvider dataMarshal + */ + public function testMarshal($value, $expected) + { + $result = $this->type->marshal($value); + $this->assertInstanceOf(TimeInterval::class, $result); + $this->assertSame($expected, (string)$result); + } + + /** + * data for testMarshal + * + * @return array + */ + public function dataMarshal() + { + $a = new FrozenTime('2019-01-01 00:00:00'); + $b = new FrozenTime('2019-01-02 02:15:01'); + $c = new FrozenTime('2019-01-31 00:00:00'); + $d = new FrozenTime('2019-03-01 02:15:01'); + + return [ + ['00:00:01', '00:00:01'], + ['00:15:01', '00:15:01'], + ['25:15:01', '25:15:01'], + ['-25:15:01', '-25:15:01'], + ['25:15', '25:15:00'], + ['-25:15', '-25:15:00'], + [new \DateInterval('PT25H15M1S'), '25:15:01'], + [new \DateInterval('P1DT2H15M1S'), '26:15:01'], + [$a->diff($b), '26:15:01'], + [$c->diff($d), '698:15:01'], + [0, '00:00:00'], + [1, '00:00:01'], + [-1, '-00:00:01'], + [3599, '00:59:59'], + [-3599, '-00:59:59'], + [86401, '24:00:01'], + [-86401, '-24:00:01'], + ]; + } + + /** + * test convert null value + */ + public function testMarshalWithNull() + { + $this->assertNull($this->type->marshal(null)); + } + + /** + * test convert PHP to DB + */ + abstract public function testToDatabase(); + + /** + * test get statement + */ + abstract public function testToStatement(); +} diff --git a/tests/TestCase/Database/Type/TimeIntervalAsIntTypeTest.php b/tests/TestCase/Database/Type/TimeIntervalAsIntTypeTest.php new file mode 100644 index 0000000..a9a3978 --- /dev/null +++ b/tests/TestCase/Database/Type/TimeIntervalAsIntTypeTest.php @@ -0,0 +1,57 @@ +type = new TimeIntervalAsIntType(); + $this->driver = $this->getMockForAbstractClass(Driver::class); + } + + /** + * data for testToPHP + * + * @return array + */ + public function dataToPHP() + { + return [ + [0, '00:00:00'], + [1, '00:00:01'], + [901, '00:15:01'], + [90901, '25:15:01'], + [-90901, '-25:15:01'], + ]; + } + + /** + * test convert PHP to DB + */ + public function testToDatabase() + { + $this->assertNull($this->type->toDatabase(null, $this->driver)); + $this->assertSame(1, $this->type->toDatabase(TimeInterval::createFromString('00:00:01'), $this->driver)); + $this->assertSame(1, $this->type->toDatabase(TimeInterval::createFromSeconds(1), $this->driver)); + $this->assertSame(86400, $this->type->toDatabase(TimeInterval::createFromSeconds(86400), $this->driver)); + $this->assertSame(86401, $this->type->toDatabase(TimeInterval::createFromSeconds(86401), $this->driver)); + $this->assertSame(0, $this->type->toDatabase(TimeInterval::createFromSeconds(0), $this->driver)); + $this->assertSame(-86401, $this->type->toDatabase(TimeInterval::createFromSeconds(-86401), $this->driver)); + } + + /** + * test get statement + */ + public function testToStatement() + { + $this->assertSame(PDO::PARAM_NULL, $this->type->toStatement(null, $this->driver)); + $this->assertSame(PDO::PARAM_INT, $this->type->toStatement(TimeInterval::createFromSeconds(1), $this->driver)); + } +} diff --git a/tests/TestCase/Database/Type/TimeIntervalTypeTest.php b/tests/TestCase/Database/Type/TimeIntervalTypeTest.php index 4f1f7b7..5a2d478 100644 --- a/tests/TestCase/Database/Type/TimeIntervalTypeTest.php +++ b/tests/TestCase/Database/Type/TimeIntervalTypeTest.php @@ -3,25 +3,12 @@ namespace Elastic\TimeInterval\Test\TestCase\Database\Type; use Cake\Database\Driver; -use Cake\Database\Driver\Mysql; -use Cake\I18n\FrozenTime; -use Cake\TestSuite\TestCase; use Elastic\TimeInterval\Database\Type\TimeIntervalType; use Elastic\TimeInterval\ValueObject\TimeInterval; use PDO; -class TimeIntervalTypeTest extends TestCase +class TimeIntervalTypeTest extends BaseTimeIntervalTypeTest { - /** - * @var TimeIntervalType - */ - private $type; - - /** - * @var Driver|\PHPUnit_Framework_MockObject_MockObject - */ - private $driver; - public function setUp() { parent::setUp(); @@ -29,24 +16,6 @@ public function setUp() $this->driver = $this->getMockForAbstractClass(Driver::class); } - public function tearDown() - { - unset($this->type, $this->driver); - parent::tearDown(); - } - - /** - * test convert DB to PHP - * - * @dataProvider dataToPHP - */ - public function testToPHP($database, $expected) - { - $result = $this->type->toPHP($database, $this->driver); - $this->assertInstanceOf(TimeInterval::class, $result); - $this->assertSame($expected, (string)$result); - } - /** * data for testToPHP * @@ -62,67 +31,6 @@ public function dataToPHP() ]; } - /** - * test convert null value to PHP - */ - public function testToPHPWithNull() - { - $this->assertNull($this->type->toPHP(null, $this->driver)); - } - - /** - * test convert value - * - * @dataProvider dataMarshal - */ - public function testMarshal($value, $expected) - { - $result = $this->type->marshal($value); - $this->assertInstanceOf(TimeInterval::class, $result); - $this->assertSame($expected, (string)$result); - } - - /** - * data for testMarshal - * - * @return array - */ - public function dataMarshal() - { - $a = new FrozenTime('2019-01-01 00:00:00'); - $b = new FrozenTime('2019-01-02 02:15:01'); - $c = new FrozenTime('2019-01-31 00:00:00'); - $d = new FrozenTime('2019-03-01 02:15:01'); - - return [ - ['00:00:01', '00:00:01'], - ['00:15:01', '00:15:01'], - ['25:15:01', '25:15:01'], - ['-25:15:01', '-25:15:01'], - ['25:15', '25:15:00'], - ['-25:15', '-25:15:00'], - [new \DateInterval('PT25H15M1S'), '25:15:01'], - [new \DateInterval('P1DT2H15M1S'), '26:15:01'], - [$a->diff($b), '26:15:01'], - [$c->diff($d), '698:15:01'], - [0, '00:00:00'], - [1, '00:00:01'], - [-1, '-00:00:01'], - [3599, '00:59:59'], - [-3599, '-00:59:59'], - [86401, '24:00:01'], - [-86401, '-24:00:01'], - ]; - } - - /** - * test convert null value - */ - public function testMarshalWithNull() - { - $this->assertNull($this->type->marshal(null)); - } - /** * test convert PHP to DB */ diff --git a/tests/TestCase/Model/Table/WorkTimesTableTest.php b/tests/TestCase/Model/Table/WorkTimesTableTest.php index 18e12d6..e4e8872 100644 --- a/tests/TestCase/Model/Table/WorkTimesTableTest.php +++ b/tests/TestCase/Model/Table/WorkTimesTableTest.php @@ -36,6 +36,10 @@ public function testGetFromDb() $record = $this->table->get(1); $this->assertInstanceOf(TimeInterval::class, $record->rest); $this->assertSame('01:00:00', (string)$record->rest); + + $this->assertInstanceOf(TimeInterval::class, $record->rest_seconds); + $this->assertSame('01:00:00', (string)$record->rest_seconds); + $this->assertInstanceOf(TimeInterval::class, $record->duration); $this->assertSame('08:00:00', (string)$record->duration); } @@ -113,4 +117,31 @@ public function testSaveAs() $this->assertInstanceOf(TimeInterval::class, $recordFromSeconds->rest); $this->assertSame('02:03:04', (string)$recordFromSeconds->rest); } + + public function testSaveAsInt() + { + $record = $this->table->get(1); + + // set with time string and save + $record->rest_seconds = '00:15:01'; + $this->assertNotFalse($this->table->save($record)); + $recordFromTimeString = $this->table->get($record->id); + $this->assertInstanceOf(TimeInterval::class, $recordFromTimeString->rest_seconds); + $this->assertSame('00:15:01', (string)$recordFromTimeString->rest_seconds); + + // set with DateInterval object and save + $now = FrozenTime::now(); + $record->rest_seconds = $now->diff($now->addDays(2)->addHour()->addMinutes(2)->addSeconds(3)); + $this->assertNotFalse($this->table->save($record)); + $recordFromDateInterval = $this->table->get($record->id); + $this->assertInstanceOf(TimeInterval::class, $recordFromDateInterval->rest_seconds); + $this->assertSame('49:02:03', (string)$recordFromDateInterval->rest_seconds); + + // set with seconds and save + $record->rest_seconds = 7200 + 180 + 4; + $this->assertNotFalse($this->table->save($record)); + $recordFromSeconds = $this->table->get($record->id); + $this->assertInstanceOf(TimeInterval::class, $recordFromSeconds->rest_seconds); + $this->assertSame('02:03:04', (string)$recordFromSeconds->rest_seconds); + } } diff --git a/tests/test_models.php b/tests/test_models.php index f81dd1c..46bac6c 100644 --- a/tests/test_models.php +++ b/tests/test_models.php @@ -12,6 +12,7 @@ * @property FrozenTime $start * @property FrozenTime $end * @property TimeInterval $rest + * @property TimeInterval $rest_seconds * @property TimeInterval $duration */ class WorkTime extends Entity @@ -53,6 +54,7 @@ protected function _initializeSchema(TableSchema $schema) error_reporting(E_ALL & ~E_USER_DEPRECATED); $schema->columnType('rest', 'time_interval'); + $schema->columnType('rest_seconds', 'time_interval_int'); $schema->columnType('duration', 'time_interval'); error_reporting(E_ALL); @@ -70,6 +72,10 @@ public function validationDefault(Validator $validator) 'rule' => 'timeInterval', 'provider' => 'timeInterval', ]); + $validator->add('rest_seconds', 'timeInterval', [ + 'rule' => 'timeInterval', + 'provider' => 'timeInterval', + ]); $validator->add('duration', 'timeInterval', [ 'rule' => 'timeInterval', 'provider' => 'timeInterval',