diff --git a/framework/CHANGELOG.md b/framework/CHANGELOG.md index 13fb6e3d93b..a80668a4524 100644 --- a/framework/CHANGELOG.md +++ b/framework/CHANGELOG.md @@ -3,6 +3,7 @@ Yii Framework 2 Change Log 2.0.50 under development ------------------------ +- Bug #20045: Fix type `boolean` in `MySQL` (terabytesoftw) - Bug #20040: Fix type `boolean` in `MSSQL` (terabytesoftw) - Bug #20005: Fix `yii\console\controllers\ServeController` to specify the router script (terabytesoftw) - Bug #19060: Fix `yii\widgets\Menu` bug when using Closure for active item and adding additional tests in `tests\framework\widgets\MenuTest` (atrandafir) diff --git a/framework/db/mysql/Schema.php b/framework/db/mysql/Schema.php index fa2270eb77d..666279e3b98 100644 --- a/framework/db/mysql/Schema.php +++ b/framework/db/mysql/Schema.php @@ -279,7 +279,7 @@ protected function loadColumnSchema($info) if (isset($values[1])) { $column->scale = (int) $values[1]; } - if ($column->size === 1 && $type === 'bit') { + if ($column->size === 1 && ($type === 'tinyint' || $type === 'bit')) { $column->type = 'boolean'; } elseif ($type === 'bit') { if ($column->size > 32) { diff --git a/tests/framework/db/mysql/SchemaTest.php b/tests/framework/db/mysql/SchemaTest.php index 4e602a317ea..82342419a8c 100644 --- a/tests/framework/db/mysql/SchemaTest.php +++ b/tests/framework/db/mysql/SchemaTest.php @@ -228,9 +228,13 @@ public function getExpectedColumns() ] ); + $columns['bool_col']['type'] = 'boolean'; + $columns['bool_col']['phpType'] = 'boolean'; + $columns['bool_col2']['type'] = 'boolean'; + $columns['bool_col2']['phpType'] = 'boolean'; + if (version_compare($version, '5.7', '<')) { $columns['int_col3']['phpType'] = 'string'; - $columns['json_col']['type'] = 'text'; $columns['json_col']['dbType'] = 'longtext'; $columns['json_col']['phpType'] = 'string'; diff --git a/tests/framework/db/mysql/type/BooleanTest.php b/tests/framework/db/mysql/type/BooleanTest.php new file mode 100644 index 00000000000..bc9d307a78d --- /dev/null +++ b/tests/framework/db/mysql/type/BooleanTest.php @@ -0,0 +1,249 @@ +getConnection(true); + $schema = $db->getSchema(); + $tableName = '{{%boolean}}'; + + if ($db->getTableSchema($tableName)) { + $db->createCommand()->dropTable($tableName)->execute(); + } + + $db->createCommand()->createTable( + $tableName, + [ + 'id' => $schema->createColumnSchemaBuilder(Schema::TYPE_PK), + 'bool_col_tinyint' => $schema->createColumnSchemaBuilder(Schema::TYPE_BOOLEAN), + 'bool_col_bit' => $schema->createColumnSchemaBuilder('bit', 1), + ] + )->execute(); + + // test type `boolean` + $columnBoolColTinyint = $db->getTableSchema($tableName)->getColumn('bool_col_tinyint'); + $this->assertSame('boolean', $columnBoolColTinyint->phpType); + + $columnBoolColBit = $db->getTableSchema($tableName)->getColumn('bool_col_bit'); + $this->assertSame('boolean', $columnBoolColBit->phpType); + + // test value `false` + $db->createCommand()->insert($tableName, ['bool_col_tinyint' => false, 'bool_col_bit' => false])->execute(); + $boolValues = $db->createCommand("SELECT * FROM $tableName WHERE id = 1")->queryOne(); + $this->assertEquals(0, $boolValues['bool_col_tinyint']); + $this->assertEquals(0, $boolValues['bool_col_bit']); + + // test php typecast + $phpTypeCastBoolColTinyint = $columnBoolColTinyint->phpTypecast($boolValues['bool_col_tinyint']); + $this->assertFalse($phpTypeCastBoolColTinyint); + + $phpTypeCastBoolColBit = $columnBoolColBit->phpTypecast($boolValues['bool_col_bit']); + $this->assertFalse($phpTypeCastBoolColBit); + + // test value `true` + $db->createCommand()->insert($tableName, ['bool_col_tinyint' => true, 'bool_col_bit' => true])->execute(); + $boolValues = $db->createCommand("SELECT * FROM $tableName WHERE id = 2")->queryOne(); + $this->assertEquals(1, $boolValues['bool_col_tinyint']); + $this->assertEquals(1, $boolValues['bool_col_bit']); + + // test php typecast + $phpTypeCastBoolColTinyint = $columnBoolColTinyint->phpTypecast($boolValues['bool_col_tinyint']); + $this->assertTrue($phpTypeCastBoolColTinyint); + + $phpTypeCastBoolColBit = $columnBoolColBit->phpTypecast($boolValues['bool_col_bit']); + $this->assertTrue($phpTypeCastBoolColBit); + } + + public function testBooleanWithValueInteger() + { + $db = $this->getConnection(true); + $schema = $db->getSchema(); + $tableName = '{{%boolean}}'; + + if ($db->getTableSchema($tableName)) { + $db->createCommand()->dropTable($tableName)->execute(); + } + + $db->createCommand()->createTable( + $tableName, + [ + 'id' => $schema->createColumnSchemaBuilder(Schema::TYPE_PK), + 'bool_col_tinyint' => $schema->createColumnSchemaBuilder(Schema::TYPE_BOOLEAN), + 'bool_col_bit' => $schema->createColumnSchemaBuilder('bit', 1), + ] + )->execute(); + + // test type `boolean` + $columnBoolColTinyint = $db->getTableSchema($tableName)->getColumn('bool_col_tinyint'); + $this->assertSame('boolean', $columnBoolColTinyint->phpType); + + $columnBoolColBit = $db->getTableSchema($tableName)->getColumn('bool_col_bit'); + $this->assertSame('boolean', $columnBoolColBit->phpType); + + // test value `0` + $db->createCommand()->insert($tableName, ['bool_col_tinyint' => 0, 'bool_col_bit' => 0])->execute(); + $boolValues = $db->createCommand("SELECT * FROM $tableName WHERE id = 1")->queryOne(); + $this->assertEquals(0, $boolValues['bool_col_tinyint']); + $this->assertEquals(0, $boolValues['bool_col_bit']); + + // test php typecast + $phpTypeCastBoolColTinyint = $columnBoolColTinyint->phpTypecast($boolValues['bool_col_tinyint']); + $this->assertFalse($phpTypeCastBoolColTinyint); + + $phpTypeCastBoolColBit = $columnBoolColBit->phpTypecast($boolValues['bool_col_bit']); + $this->assertFalse($phpTypeCastBoolColBit); + + // test value `1` + $db->createCommand()->insert($tableName, ['bool_col_tinyint' => 1, 'bool_col_bit' => 1])->execute(); + $boolValues = $db->createCommand("SELECT * FROM $tableName WHERE id = 2")->queryOne(); + $this->assertEquals(1, $boolValues['bool_col_tinyint']); + $this->assertEquals(1, $boolValues['bool_col_bit']); + + // test php typecast + $phpTypeCastBoolColTinyint = $columnBoolColTinyint->phpTypecast($boolValues['bool_col_tinyint']); + $this->assertTrue($phpTypeCastBoolColTinyint); + + $phpTypeCastBoolColBit = $columnBoolColBit->phpTypecast($boolValues['bool_col_bit']); + $this->assertTrue($phpTypeCastBoolColBit); + } + + public function testBooleanWithValueNegative() + { + $db = $this->getConnection(true); + $schema = $db->getSchema(); + $tableName = '{{%boolean}}'; + + if ($db->getTableSchema($tableName)) { + $db->createCommand()->dropTable($tableName)->execute(); + } + + $db->createCommand()->createTable( + $tableName, + [ + 'id' => $schema->createColumnSchemaBuilder(Schema::TYPE_PK), + 'bool_col_tinyint' => $schema->createColumnSchemaBuilder(Schema::TYPE_BOOLEAN), + 'bool_col_bit' => $schema->createColumnSchemaBuilder('bit', 1), + ] + )->execute(); + + // test type `boolean` + $columnBoolColTinyint = $db->getTableSchema($tableName)->getColumn('bool_col_tinyint'); + $this->assertSame('boolean', $columnBoolColTinyint->phpType); + + $columnBoolColBit = $db->getTableSchema($tableName)->getColumn('bool_col_bit'); + $this->assertSame('boolean', $columnBoolColBit->phpType); + + // test value `-1` + $db->createCommand()->insert($tableName, ['bool_col_tinyint' => -1, 'bool_col_bit' => -1])->execute(); + $boolValues = $db->createCommand("SELECT * FROM $tableName WHERE id = 1")->queryOne(); + + $this->assertEquals(1, $boolValues['bool_col_tinyint']); + $this->assertEquals(1, $boolValues['bool_col_bit']); + + // test php typecast + $phpTypeCastBoolColTinyint = $columnBoolColTinyint->phpTypecast($boolValues['bool_col_tinyint']); + $this->assertTrue($phpTypeCastBoolColTinyint); + + $phpTypeCastBoolColBit = $columnBoolColBit->phpTypecast($boolValues['bool_col_bit']); + $this->assertTrue($phpTypeCastBoolColBit); + } + + public function testBooleanWithValueNull() + { + $db = $this->getConnection(true); + $schema = $db->getSchema(); + $tableName = '{{%boolean}}'; + + if ($db->getTableSchema($tableName)) { + $db->createCommand()->dropTable($tableName)->execute(); + } + + $db->createCommand()->createTable( + $tableName, + [ + 'id' => $schema->createColumnSchemaBuilder(Schema::TYPE_PK), + 'bool_col_tinyint' => $schema->createColumnSchemaBuilder(Schema::TYPE_BOOLEAN), + 'bool_col_bit' => $schema->createColumnSchemaBuilder('bit', 1), + ] + )->execute(); + + // test type `boolean` + $columnBoolColTinyint = $db->getTableSchema($tableName)->getColumn('bool_col_tinyint'); + $this->assertSame('boolean', $columnBoolColTinyint->phpType); + + $columnBoolColBit = $db->getTableSchema($tableName)->getColumn('bool_col_bit'); + $this->assertSame('boolean', $columnBoolColBit->phpType); + + // test value `null` + $db->createCommand()->insert($tableName, ['bool_col_tinyint' => null, 'bool_col_bit' => null])->execute(); + $boolValues = $db->createCommand("SELECT * FROM $tableName WHERE id = 1")->queryOne(); + + $this->assertNull($boolValues['bool_col_tinyint']); + $this->assertNull($boolValues['bool_col_bit']); + + // test php typecast + $phpTypeCastBoolColTinyint = $columnBoolColTinyint->phpTypecast($boolValues['bool_col_tinyint']); + $this->assertNull($phpTypeCastBoolColTinyint); + + $phpTypeCastBoolColBit = $columnBoolColBit->phpTypecast($boolValues['bool_col_bit']); + $this->assertNull($phpTypeCastBoolColBit); + } + + public function testBooleanWithValueOverflow() + { + $db = $this->getConnection(true); + $schema = $db->getSchema(); + $tableName = '{{%boolean}}'; + + if ($db->getTableSchema($tableName)) { + $db->createCommand()->dropTable($tableName)->execute(); + } + + $db->createCommand()->createTable( + $tableName, + [ + 'id' => $schema->createColumnSchemaBuilder(Schema::TYPE_PK), + 'bool_col_tinyint' => $schema->createColumnSchemaBuilder(Schema::TYPE_BOOLEAN), + 'bool_col_bit' => $schema->createColumnSchemaBuilder('bit', 1), + ] + )->execute(); + + // test type `boolean` + $columnBoolColTinyint = $db->getTableSchema($tableName)->getColumn('bool_col_tinyint'); + $this->assertSame('boolean', $columnBoolColTinyint->phpType); + + $columnBoolColBit = $db->getTableSchema($tableName)->getColumn('bool_col_bit'); + $this->assertSame('boolean', $columnBoolColBit->phpType); + + // test value `2` + $db->createCommand()->insert($tableName, ['bool_col_tinyint' => 2, 'bool_col_bit' => 2])->execute(); + $boolValues = $db->createCommand("SELECT * FROM $tableName WHERE id = 1")->queryOne(); + + $this->assertEquals(1, $boolValues['bool_col_tinyint']); + $this->assertEquals(1, $boolValues['bool_col_bit']); + + // test php typecast + $phpTypeCastBoolColTinyint = $columnBoolColTinyint->phpTypecast($boolValues['bool_col_tinyint']); + $this->assertTrue($phpTypeCastBoolColTinyint); + + $phpTypeCastBoolColBit = $columnBoolColBit->phpTypecast($boolValues['bool_col_bit']); + $this->assertTrue($phpTypeCastBoolColBit); + } +}