diff --git a/src/Generators/SeederGenerator.php b/src/Generators/SeederGenerator.php new file mode 100644 index 00000000..fe93580f --- /dev/null +++ b/src/Generators/SeederGenerator.php @@ -0,0 +1,92 @@ +files = $files; + } + + public function output(array $tree): array + { + if (empty($tree['seeders'])) { + return []; + } + + $output = []; + $stub = $this->files->stub('seeder.stub'); + + $this->registerModels($tree); + + foreach ($tree['seeders'] as $model) { + $path = $this->getPath($model); + $this->files->put($path, $this->populateStub($stub, $model)); + + $output['created'][] = $path; + } + + return $output; + } + + private function getPath($model) + { + return 'database/seeds/' . $model . 'Seeder.php'; + } + + protected function populateStub(string $stub, string $model) + { + $stub = str_replace('DummyClass', $this->getClassName($model), $stub); + $stub = str_replace('//', $this->build($model), $stub); + + return $stub; + } + + private function getClassName(string $model) + { + return $model . 'Seeder'; + } + + private function build(string $model) + { + return sprintf('factory(\\%s::class, 5)->create();', $this->fqcnForContext($model)); + } + + private function registerModels(array $tree) + { + $this->models = array_merge($tree['cache'] ?? [], $tree['models'] ?? []); + } + + private function fqcnForContext(string $context) + { + if (isset($this->models[$context])) { + return $this->models[$context]->fullyQualifiedClassName(); + } + + $matches = array_filter(array_keys($this->models), function ($key) use ($context) { + return Str::endsWith($key, '\\' . Str::studly($context)); + }); + + if (count($matches) === 1) { + return $this->models[current($matches)]->fullyQualifiedClassName(); + } + + $fqn = config('blueprint.namespace'); + if (config('blueprint.models_namespace')) { + $fqn .= '\\' . config('blueprint.models_namespace'); + } + + return $fqn . '\\' . $context; + } +} diff --git a/src/Lexers/SeederLexer.php b/src/Lexers/SeederLexer.php new file mode 100644 index 00000000..33ee3867 --- /dev/null +++ b/src/Lexers/SeederLexer.php @@ -0,0 +1,39 @@ + [], + ]; + + if (!empty($tokens['seeders'])) { + $registry['seeders'] = $this->analyzeValue($tokens['seeders']); + } + + return $registry; + } + + private function analyzeValue($value) + { + return preg_split('/,([ \t]+)?/', $value); + } +} diff --git a/stubs/seeder.stub b/stubs/seeder.stub new file mode 100644 index 00000000..4aa38454 --- /dev/null +++ b/stubs/seeder.stub @@ -0,0 +1,16 @@ +subject->parse($blueprint)); } + public function it_parses_seeders() + { + $blueprint = $this->fixture('definitions/seeders.bp'); + + $this->assertEquals([ + 'models' => [ + 'Post' => [ + 'title' => 'string:400', + 'content' => 'longtext', + 'published_at' => 'nullable timestamp', + ], + 'Comment' => [ + 'post_id' => 'id', + 'content' => 'longtext', + 'approved' => 'boolean', + 'user_id' => 'id', + ], + ], + 'seeders' => 'Post, Comment' + ], $this->subject->parse($blueprint)); + } + /** * @test */ diff --git a/tests/Feature/Generator/SeederGeneratorTest.php b/tests/Feature/Generator/SeederGeneratorTest.php new file mode 100644 index 00000000..06c5383c --- /dev/null +++ b/tests/Feature/Generator/SeederGeneratorTest.php @@ -0,0 +1,92 @@ +files = \Mockery::mock(); + + $this->subject = new SeederGenerator($this->files); + + $this->blueprint = new Blueprint(); + $this->blueprint->registerLexer(new \Blueprint\Lexers\ModelLexer()); + $this->blueprint->registerLexer(new \Blueprint\Lexers\SeederLexer()); + $this->blueprint->registerGenerator($this->subject); + } + + /** + * @test + */ + public function output_generates_nothing_for_empty_tree() + { + $this->files->shouldNotHaveReceived('put'); + + $this->assertEquals([], $this->subject->output(['seeders' => []])); + } + + /** + * @test + */ + public function output_generates_seeders() + { + $this->files->expects('stub') + ->with('seeder.stub') + ->andReturn(file_get_contents('stubs/seeder.stub')); + + $this->files->expects('put') + ->with('database/seeds/PostSeeder.php', $this->fixture('seeders/PostSeeder.php')); + $this->files->expects('put') + ->with('database/seeds/CommentSeeder.php', $this->fixture('seeders/CommentSeeder.php')); + + $tokens = $this->blueprint->parse($this->fixture('definitions/seeders.bp')); + $tree = $this->blueprint->analyze($tokens); + + $this->assertEquals(['created' => ['database/seeds/PostSeeder.php', 'database/seeds/CommentSeeder.php']], $this->subject->output($tree)); + } + + /** + * @test + */ + public function output_generates_seeders_from_traced_models() + { + $this->files->expects('stub') + ->with('seeder.stub') + ->andReturn(file_get_contents('stubs/seeder.stub')); + + $this->files->expects('put') + ->with('database/seeds/PostSeeder.php', $this->fixture('seeders/PostSeeder.php')); + $this->files->expects('put') + ->with('database/seeds/CommentSeeder.php', $this->fixture('seeders/CommentSeeder.php')); + + $tokens = $this->blueprint->parse($this->fixture('definitions/seeders.bp')); + $tree = $this->blueprint->analyze($tokens); + $tree['cache'] = $tree['models']; + unset($tree['models']); + + $this->assertEquals(['created' => ['database/seeds/PostSeeder.php', 'database/seeds/CommentSeeder.php']], $this->subject->output($tree)); + } +} diff --git a/tests/Feature/Lexers/SeederLexerTest.php b/tests/Feature/Lexers/SeederLexerTest.php new file mode 100644 index 00000000..abdf1a8d --- /dev/null +++ b/tests/Feature/Lexers/SeederLexerTest.php @@ -0,0 +1,79 @@ +subject = new SeederLexer(); + } + + /** + * @test + */ + public function it_returns_nothing_without_seeders_token() + { + $this->assertEquals([ + 'seeders' => [] + ], $this->subject->analyze([])); + } + + /** + * @test + */ + public function it_returns_seeders() + { + $tokens = [ + 'seeders' => 'Post' + ]; + + $actual = $this->subject->analyze($tokens); + + $this->assertIsArray($actual['seeders']); + $this->assertCount(1, $actual['seeders']); + + $this->assertSame(['Post'], $actual['seeders']); + } + + /** + * @test + */ + public function it_returns_multiple_seeders() + { + $tokens = [ + 'seeders' => 'Post, Comment' + ]; + + $actual = $this->subject->analyze($tokens); + + $this->assertIsArray($actual['seeders']); + $this->assertCount(2, $actual['seeders']); + + $this->assertSame(['Post', 'Comment'], $actual['seeders']); + } +} diff --git a/tests/fixtures/definitions/models-only.bp b/tests/fixtures/definitions/models-only.bp index cccfee8c..d123f579 100644 --- a/tests/fixtures/definitions/models-only.bp +++ b/tests/fixtures/definitions/models-only.bp @@ -4,4 +4,4 @@ models: ModelTwo: column: datatype - another_column: datatype modifier \ No newline at end of file + another_column: datatype modifier diff --git a/tests/fixtures/definitions/seeders.bp b/tests/fixtures/definitions/seeders.bp new file mode 100644 index 00000000..36ea7045 --- /dev/null +++ b/tests/fixtures/definitions/seeders.bp @@ -0,0 +1,14 @@ +models: + Post: + title: string:400 + content: longtext + published_at: nullable timestamp + + Blog\Comment: + post_id: id + content: longtext + approved: boolean + user_id: id + +seeders: Post, Comment + diff --git a/tests/fixtures/seeders/CommentSeeder.php b/tests/fixtures/seeders/CommentSeeder.php new file mode 100644 index 00000000..63a631d8 --- /dev/null +++ b/tests/fixtures/seeders/CommentSeeder.php @@ -0,0 +1,16 @@ +create(); + } +} diff --git a/tests/fixtures/seeders/PostSeeder.php b/tests/fixtures/seeders/PostSeeder.php new file mode 100644 index 00000000..7e085018 --- /dev/null +++ b/tests/fixtures/seeders/PostSeeder.php @@ -0,0 +1,16 @@ +create(); + } +}