diff --git a/docs/en/configuration.rst b/docs/en/configuration.rst index 021348a36..045086569 100644 --- a/docs/en/configuration.rst +++ b/docs/en/configuration.rst @@ -521,6 +521,11 @@ For some breaking changes, Phinx offers a way to opt-out of new behavior. The fo * ``unsigned_primary_keys``: Should Phinx create primary keys as unsigned integers? (default: ``true``) * ``column_null_default``: Should Phinx create columns as null by default? (default: ``true``) +Since MySQL ``TIMESTAMP`` fields do not support dates past 2038-01-19, you have the option to use ``DATETIME`` field +types for fields created by the ``addTimestamps()`` function: + +* ``add_timestamps_use_datetime``: Should Phinx create created_at and updated_at fields as datetime? (default: ``false``) + .. code-block:: yaml feature_flags: diff --git a/src/Phinx/Config/FeatureFlags.php b/src/Phinx/Config/FeatureFlags.php index a9c272b17..67da55d29 100644 --- a/src/Phinx/Config/FeatureFlags.php +++ b/src/Phinx/Config/FeatureFlags.php @@ -22,6 +22,10 @@ class FeatureFlags * @var bool Should Phinx create columns NULL by default? */ public static bool $columnNullDefault = true; + /** + * @var bool Should Phinx create datetime columns for addTimestamps instead of timestamp? + */ + public static bool $addTimestampsUseDateTime = false; /** * Set the feature flags from the `feature_flags` section of the overall @@ -37,5 +41,8 @@ public static function setFlagsFromConfig(array $config): void if (isset($config['column_null_default'])) { self::$columnNullDefault = (bool)$config['column_null_default']; } + if (isset($config['add_timestamps_use_datetime'])) { + self::$addTimestampsUseDateTime = (bool)$config['add_timestamps_use_datetime']; + } } } diff --git a/src/Phinx/Db/Adapter/MysqlAdapter.php b/src/Phinx/Db/Adapter/MysqlAdapter.php index e7791c655..0b3a6d186 100644 --- a/src/Phinx/Db/Adapter/MysqlAdapter.php +++ b/src/Phinx/Db/Adapter/MysqlAdapter.php @@ -472,6 +472,10 @@ public function getColumns(string $tableName): array $column->setIdentity(true); } + if ($columnInfo['Extra'] === 'on update CURRENT_TIMESTAMP') { + $column->setUpdate('CURRENT_TIMESTAMP'); + } + if (isset($phinxType['values'])) { $column->setValues($phinxType['values']); } diff --git a/src/Phinx/Db/Table.php b/src/Phinx/Db/Table.php index bf77dc5b0..2137acb37 100644 --- a/src/Phinx/Db/Table.php +++ b/src/Phinx/Db/Table.php @@ -9,6 +9,7 @@ namespace Phinx\Db; use InvalidArgumentException; +use Phinx\Config\FeatureFlags; use Phinx\Db\Action\AddColumn; use Phinx\Db\Action\AddForeignKey; use Phinx\Db\Action\AddIndex; @@ -542,8 +543,10 @@ public function addTimestamps(string|false|null $createdAt = 'created_at', strin throw new RuntimeException('Cannot set both created_at and updated_at columns to false'); } + $columnType = FeatureFlags::$addTimestampsUseDateTime ? 'datetime' : 'timestamp'; + if ($createdAt) { - $this->addColumn($createdAt, 'timestamp', [ + $this->addColumn($createdAt, $columnType, [ 'null' => false, 'default' => 'CURRENT_TIMESTAMP', 'update' => '', @@ -551,7 +554,7 @@ public function addTimestamps(string|false|null $createdAt = 'created_at', strin ]); } if ($updatedAt) { - $this->addColumn($updatedAt, 'timestamp', [ + $this->addColumn($updatedAt, $columnType, [ 'null' => true, 'default' => null, 'update' => 'CURRENT_TIMESTAMP', diff --git a/tests/Phinx/Config/FeatureFlagsTest.php b/tests/Phinx/Config/FeatureFlagsTest.php index 0f5b262dd..c4efafcc2 100644 --- a/tests/Phinx/Config/FeatureFlagsTest.php +++ b/tests/Phinx/Config/FeatureFlagsTest.php @@ -15,11 +15,14 @@ public function testSetFlagsFromConfig(): void $config = [ 'unsigned_primary_keys' => false, 'column_null_default' => false, + 'add_timestamps_use_datetime' => true, ]; $this->assertTrue(FeatureFlags::$unsignedPrimaryKeys); $this->assertTrue(FeatureFlags::$columnNullDefault); + $this->assertFalse(FeatureFlags::$addTimestampsUseDateTime); FeatureFlags::setFlagsFromConfig($config); $this->assertFalse(FeatureFlags::$unsignedPrimaryKeys); $this->assertFalse(FeatureFlags::$columnNullDefault); + $this->assertTrue(FeatureFlags::$addTimestampsUseDateTime); } } diff --git a/tests/Phinx/Db/Adapter/MysqlAdapterTest.php b/tests/Phinx/Db/Adapter/MysqlAdapterTest.php index 62a8332d1..c71c5f687 100644 --- a/tests/Phinx/Db/Adapter/MysqlAdapterTest.php +++ b/tests/Phinx/Db/Adapter/MysqlAdapterTest.php @@ -509,6 +509,36 @@ public function testUnsignedPksFeatureFlag() $this->assertTrue($columns[0]->getSigned()); } + /** + * @runInSeparateProcess + */ + public function testAddTimestampsFeatureFlag() + { + $this->adapter->connect(); + + FeatureFlags::$addTimestampsUseDateTime = true; + + $table = new Table('table1', [], $this->adapter); + $table->addTimestamps(); + $table->create(); + + $columns = $this->adapter->getColumns('table1'); + + $this->assertCount(3, $columns); + $this->assertSame('id', $columns[0]->getName()); + + $this->assertEquals('created_at', $columns[1]->getName()); + $this->assertEquals('datetime', $columns[1]->getType()); + $this->assertEquals('CURRENT_TIMESTAMP', $columns[1]->getDefault()); + $this->assertEquals('', $columns[1]->getUpdate()); + + $this->assertEquals('updated_at', $columns[2]->getName()); + $this->assertEquals('datetime', $columns[2]->getType()); + $this->assertEquals('CURRENT_TIMESTAMP', $columns[2]->getUpdate()); + $this->assertTrue($columns[2]->isNull()); + $this->assertNull($columns[2]->getDefault()); + } + public function testCreateTableWithLimitPK() { $table = new Table('ntable', ['id' => 'id', 'limit' => 4], $this->adapter);