diff --git a/src/Commands/Create.php b/src/Commands/Create.php index f8254ec..fefe105 100644 --- a/src/Commands/Create.php +++ b/src/Commands/Create.php @@ -75,12 +75,24 @@ public function run() /** @var string */ $name = $this->getArgument('name'); + /** @var boolean */ + $useDb = $this->getOption('from-database'); + $parser = new Parser($name); $class = new Migration($name); $class->setParser($parser); + if ($parser->isCreateTable() && $useDb && $this->driver) + { + $table = $parser->getTable(); + + $columns = $this->driver->columns($table); + + $class->withColumns($columns); + } + if ($parser->isCreateColumn() || $parser->isDeleteColumn()) { /** @var string */ @@ -88,7 +100,9 @@ public function run() $column = $this->setColumn($column); - $class->withColumn($column); + $columns = array($column); + + $class->withColumns($columns); } $maker = new Generator; diff --git a/src/Parser.php b/src/Parser.php index 64c8057..13d38d6 100644 --- a/src/Parser.php +++ b/src/Parser.php @@ -89,6 +89,14 @@ public function isCreateColumn() return ($this->getType() === Migration::TYPE_ADD || $this->getType() === Migration::TYPE_CREATE) && $this->getColumn() !== null; } + /** + * @return boolean + */ + public function isCreateTable() + { + return $this->getType() === Migration::TYPE_CREATE && $this->getColumn() === null; + } + /** * @return boolean */ diff --git a/src/Template/Migration.php b/src/Template/Migration.php index b302e62..f70a794 100644 --- a/src/Template/Migration.php +++ b/src/Template/Migration.php @@ -30,9 +30,9 @@ class Migration extends Classidy const TYPE_UPDATE = 'update'; /** - * @var \Rougin\Describe\Column|null + * @var \Rougin\Describe\Column[] */ - protected $column = null; + protected $columns = array(); /** * @var \Rougin\Refinery\Parser @@ -79,13 +79,13 @@ public function setParser($parser) } /** - * @param \Rougin\Describe\Column $column + * @param \Rougin\Describe\Column[] $columns * * @return self */ - public function withColumn(Column $column) + public function withColumns($columns) { - $this->column = $column; + $this->columns = $columns; return $this; } @@ -103,17 +103,14 @@ protected function setDownMethod() $fn = $this->getDeleteTable($table); - if ($this->column) + if ($this->parser->isCreateColumn()) { - if ($this->parser->isCreateColumn()) - { - $fn = $this->getDeleteColumn($this->column, $table); - } + $fn = $this->getDeleteColumn($table); + } - if ($this->parser->isDeleteColumn()) - { - $fn = $this->getCreateColumn($this->column, $table); - } + if ($this->parser->isDeleteColumn()) + { + $fn = $this->getCreateColumn($table); } if ($this->parser->isDeleteTable()) @@ -139,17 +136,14 @@ protected function setUpMethod() $fn = $this->getCreateTable($table); - if ($this->column) + if ($this->parser->isCreateColumn()) { - if ($this->parser->isCreateColumn()) - { - $fn = $this->getCreateColumn($this->column, $table); - } + $fn = $this->getCreateColumn($table); + } - if ($this->parser->isDeleteColumn()) - { - $fn = $this->getDeleteColumn($this->column, $table); - } + if ($this->parser->isDeleteColumn()) + { + $fn = $this->getDeleteColumn($table); } if ($this->parser->isDeleteTable()) @@ -163,34 +157,25 @@ protected function setUpMethod() } /** - * @param \Rougin\Describe\Column $column - * @param string $table + * @param string $table * * @return callable */ - protected function getCreateColumn(Column $column, $table) + protected function getCreateColumn($table) { - return function ($lines) use ($column, $table) + $columns = $this->columns; + + return function ($lines) use ($columns, $table) { - $default = $column->getDefaultValue(); - $default = $default ? '"' . $default . '"' : 'null'; - $increment = $column->isAutoIncrement() ? 'true' : 'false'; - $length = $column->getLength(); - $name = $column->getField(); - $null = $column->isNull() ? 'true' : 'false'; - $type = $column->getDataType(); - $unsigned = $column->isUnsigned() ? 'true' : 'false'; - - $lines[] = '$data = array(\'' . $name . '\' => array());'; - $lines[] = ''; - $lines[] = '$data[\'' . $name . '\'][\'type\'] = \'' . $type . '\';'; - $lines[] = '$data[\'' . $name . '\'][\'constraint\'] = ' . $length . ';'; - $lines[] = '$data[\'' . $name . '\'][\'auto_increment\'] = ' . $increment . ';'; - $lines[] = '$data[\'' . $name . '\'][\'default\'] = ' . $default . ';'; - $lines[] = '$data[\'' . $name . '\'][\'null\'] = ' . $null . ';'; - $lines[] = '$data[\'' . $name . '\'][\'unsigned\'] = ' . $unsigned . ';'; - $lines[] = ''; - $lines[] = '$this->dbforge->add_column(\'' . $table . '\', $data);'; + foreach ($columns as $index => $column) + { + if ($index !== 0) + { + $lines[] = ''; + } + + $lines = $this->parseColumn($lines, $table, $column); + } return $lines; }; @@ -203,14 +188,25 @@ protected function getCreateColumn(Column $column, $table) */ protected function getCreateTable($table) { - return function ($lines) use ($table) + $columns = $this->columns; + + if (count($columns) === 0) { - $lines[] = '$data = array(\'id\' => array());'; - $lines[] = '$data[\'id\'][\'type\'] = \'integer\';'; - $lines[] = '$data[\'id\'][\'auto_increment\'] = true;'; - $lines[] = '$data[\'id\'][\'constraint\'] = 10;'; - $lines[] = '$this->dbforge->add_field($data);'; - $lines[] = '$this->dbforge->add_key(\'id\', true);'; + $columns[] = $this->newIdColumn(); + } + + return function ($lines) use ($columns, $table) + { + foreach ($columns as $index => $column) + { + if ($index !== 0) + { + $lines[] = ''; + } + + $lines = $this->parseColumn($lines, $table, $column); + } + $lines[] = ''; $lines[] = '$this->dbforge->create_table(\'' . $table . '\');'; @@ -234,20 +230,89 @@ protected function getDeleteTable($table) } /** - * @param \Rougin\Describe\Column $column - * @param string $table + * @param string $table * * @return callable */ - protected function getDeleteColumn(Column $column, $table) + protected function getDeleteColumn($table) { - return function ($lines) use ($column, $table) + $columns = $this->columns; + + return function ($lines) use ($columns, $table) { - $name = $column->getField(); + foreach ($columns as $column) + { + $name = $column->getField(); - $lines[] = '$this->dbforge->drop_column(\'' . $table . '\', \'' . $name . '\');'; + $lines[] = '$this->dbforge->drop_column(\'' . $table . '\', \'' . $name . '\');'; + } return $lines; }; } + + /** + * @return \Rougin\Describe\Column + */ + protected function newIdColumn() + { + $column = new Column; + + $column->setDataType('integer'); + $column->setField('id'); + $column->setAutoIncrement(true); + $column->setLength(10); + $column->setNull(false); + $column->setPrimary(true); + + return $column; + } + + /** + * @param string[] $lines + * @param string $table + * @param \Rougin\Describe\Column $column + * + * @return string[] + */ + protected function parseColumn($lines, $table, Column $column) + { + $default = $column->getDefaultValue(); + $default = $default ? '"' . $default . '"' : 'null'; + $increment = $column->isAutoIncrement() ? 'true' : 'false'; + $length = $column->getLength(); + $name = $column->getField(); + $null = $column->isNull() ? 'true' : 'false'; + $type = strtolower($column->getDataType()); + $type = str_replace('string', 'varchar', $type); + $unsigned = $column->isUnsigned() ? 'true' : 'false'; + + $lines[] = '$data = array(\'' . $name . '\' => array());'; + $lines[] = '$data[\'' . $name . '\'][\'type\'] = \'' . $type . '\';'; + $lines[] = '$data[\'' . $name . '\'][\'auto_increment\'] = ' . $increment . ';'; + $lines[] = '$data[\'' . $name . '\'][\'constraint\'] = ' . $length . ';'; + + if (! $column->isPrimaryKey()) + { + $lines[] = '$data[\'' . $name . '\'][\'default\'] = ' . $default . ';'; + $lines[] = '$data[\'' . $name . '\'][\'null\'] = ' . $null . ';'; + $lines[] = '$data[\'' . $name . '\'][\'unsigned\'] = ' . $unsigned . ';'; + } + + if ($this->parser->isCreateTable() || $this->parser->isDeleteTable()) + { + $lines[] = '$this->dbforge->add_field($data);'; + } + else + { + $lines[] = '$this->dbforge->add_column(\'' . $table . '\', $data);'; + } + + if ($column->isPrimaryKey()) + { + $lines[] = '$this->dbforge->add_key(\'' . $name . '\', true);'; + } + + return $lines; + } } diff --git a/tests/Fixture/Plates/CreateColumn.php b/tests/Fixture/Plates/CreateColumn.php index 4618766..75645a4 100644 --- a/tests/Fixture/Plates/CreateColumn.php +++ b/tests/Fixture/Plates/CreateColumn.php @@ -10,14 +10,12 @@ class Migration_add_name_in_users_table extends Migration public function up() { $data = array('name' => array()); - - $data['name']['type'] = 'VARCHAR'; - $data['name']['constraint'] = 100; + $data['name']['type'] = 'varchar'; $data['name']['auto_increment'] = false; + $data['name']['constraint'] = 100; $data['name']['default'] = null; $data['name']['null'] = true; $data['name']['unsigned'] = false; - $this->dbforge->add_column('users', $data); } diff --git a/tests/Fixture/Plates/DeleteColumn.php b/tests/Fixture/Plates/DeleteColumn.php index 9035f6f..bec8182 100644 --- a/tests/Fixture/Plates/DeleteColumn.php +++ b/tests/Fixture/Plates/DeleteColumn.php @@ -18,14 +18,12 @@ public function up() public function down() { $data = array('name' => array()); - - $data['name']['type'] = 'VARCHAR'; - $data['name']['constraint'] = 100; + $data['name']['type'] = 'varchar'; $data['name']['auto_increment'] = false; + $data['name']['constraint'] = 100; $data['name']['default'] = null; $data['name']['null'] = true; $data['name']['unsigned'] = false; - $this->dbforge->add_column('users', $data); } } diff --git a/tests/Fixture/Plates/WithDatabase.php b/tests/Fixture/Plates/WithDatabase.php new file mode 100644 index 0000000..1d2cf55 --- /dev/null +++ b/tests/Fixture/Plates/WithDatabase.php @@ -0,0 +1,38 @@ + array()); + $data['id']['type'] = 'integer'; + $data['id']['auto_increment'] = true; + $data['id']['constraint'] = 10; + $this->dbforge->add_field($data); + $this->dbforge->add_key('id', true); + + $data = array('name' => array()); + $data['name']['type'] = 'varchar'; + $data['name']['auto_increment'] = false; + $data['name']['constraint'] = 100; + $data['name']['default'] = null; + $data['name']['null'] = true; + $data['name']['unsigned'] = false; + $this->dbforge->add_field($data); + + $this->dbforge->create_table('users'); + } + + /** + * @return void + */ + public function down() + { + $this->dbforge->drop_table('users'); + } +} diff --git a/tests/ManagerTest.php b/tests/ManagerTest.php index 5ac92b1..21d950b 100644 --- a/tests/ManagerTest.php +++ b/tests/ManagerTest.php @@ -44,7 +44,7 @@ public function doSetUp() /** * @return void */ - public function test_empty_migrations() + public function test_00_empty_migrations() { $test = $this->findCommand('migrate'); @@ -58,11 +58,11 @@ public function test_empty_migrations() } /** - * @depends test_empty_migrations + * @depends test_00_empty_migrations * * @return void */ - public function test_migrating_files() + public function test_01_migrating_files() { $this->useMysqlConfig(); @@ -98,11 +98,11 @@ public function test_migrating_files() } /** - * @depends test_migrating_files + * @depends test_01_migrating_files * * @return void */ - public function test_migrating_next_file() + public function test_02_migrating_next_file() { $test = $this->findCommand('migrate'); @@ -116,11 +116,11 @@ public function test_migrating_next_file() } /** - * @depends test_migrating_next_file + * @depends test_02_migrating_next_file * * @return void */ - public function test_nothing_to_migrate() + public function test_03_nothing_to_migrate() { $test = $this->findCommand('migrate'); @@ -134,29 +134,29 @@ public function test_nothing_to_migrate() } /** - * @depends test_reset_to_0 + * @depends test_03_nothing_to_migrate * * @return void */ - public function test_nothing_to_rollback() + public function test_04_rolling_back() { $test = $this->findCommand('rollback'); $test->execute(array()); - $expected = '[PASS] Nothing to roll back.'; + $expected = 1; - $actual = $this->getActualDisplay($test); + $actual = $this->describe->columns('users'); - $this->assertEquals($expected, $actual); + $this->assertCount($expected, $actual); } /** - * @depends test_rolling_back + * @depends test_04_rolling_back * * @return void */ - public function test_reset_to_0() + public function test_05_reset_to_0() { $this->expectException('Exception'); @@ -168,21 +168,57 @@ public function test_reset_to_0() } /** - * @depends test_nothing_to_migrate + * @depends test_05_reset_to_0 * * @return void */ - public function test_rolling_back() + public function test_06_nothing_to_rollback() { $test = $this->findCommand('rollback'); $test->execute(array()); - $expected = 1; + $expected = '[PASS] Nothing to roll back.'; - $actual = $this->describe->columns('users'); + $actual = $this->getActualDisplay($test); - $this->assertCount($expected, $actual); + $this->assertEquals($expected, $actual); + } + + /** + * @depends test_06_nothing_to_rollback + * + * @return void + */ + public function test_07_create_with_database() + { + // Migrate again the said migration files --- + $test = $this->findCommand('migrate'); + $test->execute(array()); + // ------------------------------------------ + + // Then clear the said files --- + $this->clearFiles(); + // ----------------------------- + + // Create a new migration based on database --- + $test = $this->findCommand('create'); + + $input = array('name' => 'create_users_table'); + $input['--from-database'] = true; + $test->execute($input); + // -------------------------------------------- + + // Clean database by rolling back to version 0 --- + $test = $this->findCommand('rollback'); + $test->execute(array('--target' => '0')); + // ----------------------------------------------- + + $expected = $this->getTemplate('WithDatabase'); + + $actual = $this->getActualFile($input['name']); + + $this->assertEquals($expected, $actual); } /** @@ -195,10 +231,7 @@ protected function clearFiles() /** @var string[] */ $files = glob($path . '/migrations/*.php'); - foreach ($files as $file) - { - unlink($file); - } + array_map('unlink', $files); } /** @@ -225,6 +258,55 @@ protected function getActualDisplay(CommandTester $tester) return str_replace("\n", '', $actual); } + /** + * @param string $name + * + * @return string + */ + protected function getActualFile($name) + { + $path = $this->app->getAppPath(); + + /** @var string[] */ + $files = glob($path . '/migrations/*.php'); + + $selected = ''; + + foreach ($files as $file) + { + $base = basename($file); + + $parsed = substr($base, 15, strlen($base)); + + if ($parsed === $name . '.php') + { + $selected = $file; + + break; + } + } + + /** @var string */ + $result = file_get_contents($selected); + + return str_replace("\r\n", "\n", $result); + } + + /** + * @param string $name + * + * @return string + */ + protected function getTemplate($name) + { + $path = __DIR__ . '/Fixture/Plates/' . $name . '.php'; + + /** @var string */ + $file = file_get_contents($path); + + return str_replace("\r\n", "\n", $file); + } + /** * @param string $type * @@ -262,12 +344,4 @@ protected function useMysqlConfig() { $this->useDatabaseConfig('mysql'); } - - /** - * @return void - */ - protected function useSqliteConfig() - { - $this->useDatabaseConfig('sqlite'); - } } diff --git a/tests/PlateTest.php b/tests/PlateTest.php index 4917af4..ee8929d 100644 --- a/tests/PlateTest.php +++ b/tests/PlateTest.php @@ -165,7 +165,7 @@ protected function getActualFile($name) /** @var string[] */ $files = glob($path . '/migrations/*.php'); - $selected = null; + $selected = ''; foreach ($files as $file) { @@ -181,11 +181,6 @@ protected function getActualFile($name) } } - if ($selected === null) - { - throw new \Exception('"' . $name . '" file not found'); - } - /** @var string */ $result = file_get_contents($selected);