diff --git a/docs/en/configuration.rst b/docs/en/configuration.rst index bf53a4e92..d6271bf05 100644 --- a/docs/en/configuration.rst +++ b/docs/en/configuration.rst @@ -512,3 +512,18 @@ Within the bootstrap script, the following variables will be available: * @var \Symfony\Component\Console\Output\OutputInterface $output The executing command's output object * @var \Phinx\Console\Command\AbstractCommand $context the executing command object */ + +Feature Flags +------------- + +For some breaking changes, Phinx offers a way to opt-out of new behavior. The following flags are available: + +* ``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``) + +These values can also be set by modifying class fields on the ```Phinx\Config\FeatureFlags``` class, converting +the flag name to ``camelCase``, for example: + +.. code-block:: php + + Phinx\Config\FeatureFlags::$unsignedPrimaryKeys = false; diff --git a/src/Phinx/Config/Config.php b/src/Phinx/Config/Config.php index 0eb92249f..91cfbd499 100644 --- a/src/Phinx/Config/Config.php +++ b/src/Phinx/Config/Config.php @@ -57,6 +57,10 @@ public function __construct(array $configArray, ?string $configFilePath = null) { $this->configFilePath = $configFilePath; $this->values = $this->replaceTokens($configArray); + + if (isset($this->values['feature_flags'])) { + FeatureFlags::setFlagsFromConfig($this->values['feature_flags']); + } } /** diff --git a/src/Phinx/Config/FeatureFlags.php b/src/Phinx/Config/FeatureFlags.php new file mode 100644 index 000000000..dded535b8 --- /dev/null +++ b/src/Phinx/Config/FeatureFlags.php @@ -0,0 +1,41 @@ +setName($options['id']) ->setType('integer') ->setOptions([ - 'signed' => $options['signed'] ?? false, + 'signed' => $options['signed'] ?? !FeatureFlags::$unsignedPrimaryKeys, 'identity' => true, ]); diff --git a/src/Phinx/Db/Table/Column.php b/src/Phinx/Db/Table/Column.php index deae90a7f..f70ffa7a6 100644 --- a/src/Phinx/Db/Table/Column.php +++ b/src/Phinx/Db/Table/Column.php @@ -7,6 +7,7 @@ namespace Phinx\Db\Table; +use Phinx\Config\FeatureFlags; use Phinx\Db\Adapter\AdapterInterface; use Phinx\Db\Adapter\PostgresAdapter; use RuntimeException; @@ -158,6 +159,14 @@ class Column */ protected $values; + /** + * Column constructor + */ + public function __construct() + { + $this->null = FeatureFlags::$columnNullDefault; + } + /** * Sets the column name. * diff --git a/tests/Phinx/Config/FeatureFlagsTest.php b/tests/Phinx/Config/FeatureFlagsTest.php new file mode 100644 index 000000000..0f5b262dd --- /dev/null +++ b/tests/Phinx/Config/FeatureFlagsTest.php @@ -0,0 +1,25 @@ + false, + 'column_null_default' => false, + ]; + $this->assertTrue(FeatureFlags::$unsignedPrimaryKeys); + $this->assertTrue(FeatureFlags::$columnNullDefault); + FeatureFlags::setFlagsFromConfig($config); + $this->assertFalse(FeatureFlags::$unsignedPrimaryKeys); + $this->assertFalse(FeatureFlags::$columnNullDefault); + } +} diff --git a/tests/Phinx/Db/Adapter/MysqlAdapterTest.php b/tests/Phinx/Db/Adapter/MysqlAdapterTest.php index e6b0e1c44..853adef93 100644 --- a/tests/Phinx/Db/Adapter/MysqlAdapterTest.php +++ b/tests/Phinx/Db/Adapter/MysqlAdapterTest.php @@ -4,6 +4,7 @@ namespace Test\Phinx\Db\Adapter; use PDOException; +use Phinx\Config\FeatureFlags; use Phinx\Db\Adapter\AdapterInterface; use Phinx\Db\Adapter\MysqlAdapter; use Phinx\Util\Literal; @@ -156,6 +157,11 @@ public function testCreateTable() $this->assertTrue($this->adapter->hasColumn('ntable', 'realname')); $this->assertTrue($this->adapter->hasColumn('ntable', 'email')); $this->assertFalse($this->adapter->hasColumn('ntable', 'address')); + + $columns = $this->adapter->getColumns('ntable'); + $this->assertCount(3, $columns); + $this->assertSame('id', $columns[0]->getName()); + $this->assertFalse($columns[0]->isSigned()); } public function testCreateTableWithComment() @@ -421,6 +427,25 @@ public function testCreateTableWithLatin1Collate() $this->assertEquals('latin1_general_ci', $row['Collation']); } + public function testCreateTableWithSignedPK() + { + $table = new \Phinx\Db\Table('ntable', ['signed' => true], $this->adapter); + $table->addColumn('realname', 'string') + ->addColumn('email', 'integer') + ->save(); + $this->assertTrue($this->adapter->hasTable('ntable')); + $this->assertTrue($this->adapter->hasColumn('ntable', 'id')); + $this->assertTrue($this->adapter->hasColumn('ntable', 'realname')); + $this->assertTrue($this->adapter->hasColumn('ntable', 'email')); + $this->assertFalse($this->adapter->hasColumn('ntable', 'address')); + $column_definitions = $this->adapter->getColumns('ntable'); + foreach ($column_definitions as $column_definition) { + if ($column_definition->getName() === 'id') { + $this->assertTrue($column_definition->getSigned()); + } + } + } + public function testCreateTableWithUnsignedPK() { $table = new \Phinx\Db\Table('ntable', ['signed' => false], $this->adapter); @@ -459,6 +484,24 @@ public function testCreateTableWithUnsignedNamedPK() $this->assertFalse($this->adapter->hasColumn('ntable', 'address')); } + /** + * @runInSeparateProcess + */ + public function testUnsignedPksFeatureFlag() + { + $this->adapter->connect(); + + FeatureFlags::$unsignedPrimaryKeys = false; + + $table = new \Phinx\Db\Table('table1', [], $this->adapter); + $table->create(); + + $columns = $this->adapter->getColumns('table1'); + $this->assertCount(1, $columns); + $this->assertSame('id', $columns[0]->getName()); + $this->assertTrue($columns[0]->getSigned()); + } + public function testCreateTableWithLimitPK() { $table = new \Phinx\Db\Table('ntable', ['id' => 'id', 'limit' => 4], $this->adapter); diff --git a/tests/Phinx/Db/Table/ColumnTest.php b/tests/Phinx/Db/Table/ColumnTest.php index 40bf654b5..d2000ce0d 100644 --- a/tests/Phinx/Db/Table/ColumnTest.php +++ b/tests/Phinx/Db/Table/ColumnTest.php @@ -2,6 +2,7 @@ namespace Test\Phinx\Db\Table; +use Phinx\Config\FeatureFlags; use Phinx\Db\Table\Column; use PHPUnit\Framework\TestCase; use RuntimeException; @@ -28,4 +29,17 @@ public function testSetOptionsIdentity() $this->assertFalse($column->isNull()); $this->assertTrue($column->isIdentity()); } + + /** + * @runInSeparateProcess + */ + public function testColumnNullFeatureFlag() + { + $column = new Column(); + $this->assertTrue($column->isNull()); + + FeatureFlags::$columnNullDefault = false; + $column = new Column(); + $this->assertFalse($column->isNull()); + } }