diff --git a/src/Blueprint.php b/src/Blueprint.php index c5383017..f1c37260 100644 --- a/src/Blueprint.php +++ b/src/Blueprint.php @@ -37,6 +37,8 @@ public function parse($content, $strip_dashes = true) $content = preg_replace('/^(\s*)-\s*/m', '\1', $content); } + $content = preg_replace('/\s*,\s*/', ',', $content); + $content = preg_replace_callback('/^(\s+)(id|timestamps(Tz)?|softDeletes(Tz)?)$/mi', function ($matches) { return $matches[1].strtolower($matches[2]).': '.$matches[2]; }, $content); diff --git a/src/Generators/MigrationGenerator.php b/src/Generators/MigrationGenerator.php index f93ac779..72781b6b 100644 --- a/src/Generators/MigrationGenerator.php +++ b/src/Generators/MigrationGenerator.php @@ -11,6 +11,12 @@ class MigrationGenerator implements Generator { + const COMPOSITE_INDEXES = [ + '_index', + '_primary', + '_unique', + ]; + const INDENT = ' '; const NULLABLE_TYPES = [ @@ -129,11 +135,17 @@ protected function buildDefinition(Model $model) $column_definition .= '$table->id('; } elseif ($dataType === 'rememberToken') { $column_definition .= '$table->rememberToken('; + } elseif (in_array(mb_strtolower($column->name()), self::COMPOSITE_INDEXES)) { + $column_definition = []; + foreach ($column->attributes() as $attributes) { + $column_definition[] = self::INDENT.'$table->'.$dataType."(['".implode("', '", $attributes)."']);"; + } + $column_definition = implode(PHP_EOL, $column_definition).PHP_EOL; } else { $column_definition .= '$table->'.$dataType."('{$column->name()}'"; } - if (! empty($column->attributes()) && ! in_array($column->dataType(), ['id', 'uuid'])) { + if (! empty($column->attributes()) && ! in_array($column->dataType(), ['id', 'uuid']) && ! in_array($column->name(), self::COMPOSITE_INDEXES)) { $column_definition .= ', '; if (in_array($column->dataType(), ['set', 'enum'])) { $column_definition .= json_encode($column->attributes()); @@ -141,7 +153,9 @@ protected function buildDefinition(Model $model) $column_definition .= implode(', ', $column->attributes()); } } - $column_definition .= ')'; + if (!in_array(mb_strtolower($column->name()), self::COMPOSITE_INDEXES)) { + $column_definition .= ')'; + } $modifiers = $column->modifiers(); @@ -183,7 +197,9 @@ protected function buildDefinition(Model $model) } } - $column_definition .= ';'.PHP_EOL; + if (!in_array(mb_strtolower($column->name()), self::COMPOSITE_INDEXES)) { + $column_definition .= ';'.PHP_EOL; + } if (! empty($foreign)) { $column_definition .= $foreign.';'.PHP_EOL; } diff --git a/src/Lexers/ModelLexer.php b/src/Lexers/ModelLexer.php index c1302fcc..f3d5b624 100644 --- a/src/Lexers/ModelLexer.php +++ b/src/Lexers/ModelLexer.php @@ -98,6 +98,12 @@ class ModelLexer implements Lexer 'comment' => 'comment', ]; + private static $compositeIndexes = [ + '_index' => 'index', + '_primary' => 'primary', + '_unique' => 'unique', + ]; + public function analyze(array $tokens): array { $registry = [ @@ -217,7 +223,15 @@ private function buildColumn(string $name, string $definition) if (isset($parts[1])) { $attributes = [$parts[1]]; } - } elseif (isset(self::$dataTypes[strtolower($value)])) { + } + if (isset(self::$compositeIndexes[strtolower($name)])) { + $data_type = self::$compositeIndexes[strtolower($name)]; + $attributes = []; + foreach (explode(' ', $definition) as $attribute) { + $attributes[] = explode(',', $attribute); + } + } + if (isset(self::$dataTypes[strtolower($value)])) { $attributes = $parts[1] ?? null; $data_type = self::$dataTypes[strtolower($value)]; if (!empty($attributes)) { diff --git a/tests/Feature/BlueprintTest.php b/tests/Feature/BlueprintTest.php index 74fa2b3d..11e1848b 100644 --- a/tests/Feature/BlueprintTest.php +++ b/tests/Feature/BlueprintTest.php @@ -64,7 +64,7 @@ public function it_parses_seeders() 'user_id' => 'id', ], ], - 'seeders' => 'Post, Comment', + 'seeders' => 'Post,Comment', ], $this->subject->parse($blueprint)); } @@ -219,7 +219,7 @@ public function it_parses_the_readme_example() 'render' => 'post.index with:posts', ], 'store' => [ - 'validate' => 'title, content, author_id', + 'validate' => 'title,content,author_id', 'save' => 'post', 'send' => 'ReviewPost to:post.author.email with:post', 'dispatch' => 'SyncMedia with:post', @@ -262,7 +262,7 @@ public function it_parses_the_readme_example_with_different_platform_eols() 'render' => 'post.index with:posts', ], 'store' => [ - 'validate' => 'title, content, author_id', + 'validate' => 'title,content,author_id', 'save' => 'post', 'send' => 'ReviewPost to:post.author.email with:post', 'dispatch' => 'SyncMedia with:post', @@ -299,7 +299,7 @@ public function it_parses_yaml_with_dashed_syntax() 'render' => 'post.index with:posts', ], 'store' => [ - 'validate' => 'title, content', + 'validate' => 'title,content', 'save' => 'post', 'redirect' => 'post.index', ], diff --git a/tests/Feature/Generator/MigrationGeneratorTest.php b/tests/Feature/Generator/MigrationGeneratorTest.php index 7c9cf5f8..7334df24 100644 --- a/tests/Feature/Generator/MigrationGeneratorTest.php +++ b/tests/Feature/Generator/MigrationGeneratorTest.php @@ -755,6 +755,7 @@ public function modelTreeDataProvider() ['drafts/resource-statements.yaml', 'database/migrations/timestamp_create_users_table.php', 'migrations/resource-statements.php'], ['drafts/enum-options.yaml', 'database/migrations/timestamp_create_messages_table.php', 'migrations/enum-options.php'], ['drafts/columns-with-comments.yaml', 'database/migrations/timestamp_create_professions_table.php', 'migrations/columns-with-comments.php'], + ['drafts/migration-with-composite-indexes.yaml', 'database/migrations/timestamp_create_participations_table.php', 'migrations/migration-with-composite-indexes.php'], ]; } } diff --git a/tests/fixtures/drafts/migration-with-composite-indexes.yaml b/tests/fixtures/drafts/migration-with-composite-indexes.yaml new file mode 100644 index 00000000..c86e0ab2 --- /dev/null +++ b/tests/fixtures/drafts/migration-with-composite-indexes.yaml @@ -0,0 +1,8 @@ +models: + Participation: + project_id: bigInteger + user_id: bigInteger + name: string + _unique: project_id, user_id team_id,project_id + _index: project_id, user_id + _primary: project_id, user_id diff --git a/tests/fixtures/migrations/migration-with-composite-indexes.php b/tests/fixtures/migrations/migration-with-composite-indexes.php new file mode 100644 index 00000000..1cece6da --- /dev/null +++ b/tests/fixtures/migrations/migration-with-composite-indexes.php @@ -0,0 +1,38 @@ +id(); + $table->bigInteger('project_id'); + $table->bigInteger('user_id'); + $table->string('name'); + $table->unique(['project_id', 'user_id']); + $table->unique(['team_id', 'project_id']); + $table->index(['project_id', 'user_id']); + $table->primary(['project_id', 'user_id']); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('participations'); + } +}