diff --git a/config/entity-generator.php b/config/entity-generator.php index bff879b..8919cd2 100644 --- a/config/entity-generator.php +++ b/config/entity-generator.php @@ -32,8 +32,6 @@ 'routes' => 'entity-generator::routes', 'use_routes' => 'entity-generator::use_routes', 'factory' => 'entity-generator::factory', - 'legacy_factory' => 'entity-generator::legacy_factory', - 'legacy_empty_factory' => 'entity-generator::legacy_empty_factory', 'seeder' => 'entity-generator::seeder', 'legacy_seeder' => 'entity-generator::legacy_seeder', 'database_empty_seeder' => 'entity-generator::database_empty_seeder', diff --git a/src/Generators/FactoryGenerator.php b/src/Generators/FactoryGenerator.php index 3f993bb..6e0aa0b 100644 --- a/src/Generators/FactoryGenerator.php +++ b/src/Generators/FactoryGenerator.php @@ -7,9 +7,7 @@ use Illuminate\Support\Str; use InvalidArgumentException; use RonasIT\Support\Exceptions\FakerMethodNotFound; -use RonasIT\Support\Exceptions\ModelFactoryNotFound; use RonasIT\Support\Exceptions\ClassNotExistsException; -use RonasIT\Support\Exceptions\ModelFactoryNotFoundedException; use RonasIT\Support\Exceptions\ClassAlreadyExistsException; use RonasIT\Support\Events\SuccessCreateMessage; @@ -28,21 +26,12 @@ class FactoryGenerator extends EntityGenerator ]; public function generate(): void - { - $createMessage = ($this->allowedToCreateFactoryInSeparateClass()) - ? $this->generateSeparateClass() - : $this->generateToGenericClass(); - - event(new SuccessCreateMessage($createMessage)); - } - - protected function generateSeparateClass(): string { if (!$this->classExists('models', $this->model)) { $this->throwFailureException( exceptionClass: ClassNotExistsException::class, failureMessage: "Cannot create {$this->model}Factory cause {$this->model} Model does not exists.", - recommendedMessage: "Create a {$this->model} Model by itself or run command 'php artisan make:entity {$this->model} --only-model'." + recommendedMessage: "Create a {$this->model} Model by itself or run command 'php artisan make:entity {$this->model} --only-model'.", ); } @@ -50,94 +39,19 @@ protected function generateSeparateClass(): string $this->throwFailureException( exceptionClass: ClassAlreadyExistsException::class, failureMessage: "Cannot create {$this->model}Factory cause {$this->model}Factory already exists.", - recommendedMessage: "Remove {$this->model}Factory." + recommendedMessage: "Remove {$this->model}Factory.", ); } $factoryContent = $this->getStub('factory', [ 'namespace' => $this->getOrCreateNamespace('factory'), 'entity' => $this->model, - 'fields' => $this->prepareFields() + 'fields' => $this->prepareFields(), ]); $this->saveClass('factory', "{$this->model}Factory", $factoryContent); - return "Created a new Factory: {$this->model}Factory"; - } - - protected function generateToGenericClass(): string - { - if (!file_exists($this->paths['factory'])) { - $this->prepareEmptyFactory(); - } - - if (!$this->checkExistModelFactory() && $this->checkExistRelatedModelsFactories()) { - $stubPath = config("entity-generator.stubs.legacy_factory"); - - $content = view($stubPath)->with([ - 'entity' => $this->model, - 'fields' => $this->prepareFields(), - 'modelsNamespace' => $this->getOrCreateNamespace('models') - ])->render(); - - $content = "\n\n" . $content; - - $createMessage = "Created a new Test factory for {$this->model} model in '{$this->paths['factory']}'"; - - file_put_contents(base_path($this->paths['factory']), $content, FILE_APPEND); - - $this->prepareRelatedFactories(); - } else { - $createMessage = "Factory for {$this->model} model has already created, so new factory not necessary create."; - } - - return $createMessage; - } - - protected function allowedToCreateFactoryInSeparateClass(): bool - { - return version_compare(app()->version(), '8', '>='); - } - - protected function prepareEmptyFactory(): void - { - $stubPath = config('entity-generator.stubs.legacy_empty_factory'); - $content = " $this->getOrCreateNamespace('models') - ])->render(); - - list($basePath, $databaseFactoryDir) = extract_last_part(config('entity-generator.paths.factory'), '/'); - - $databaseFactoryDir = base_path($databaseFactoryDir); - - if (!is_dir($databaseFactoryDir)) { - mkdir($databaseFactoryDir); - } - - file_put_contents(base_path($this->paths['factory']), $content); - } - - protected function checkExistRelatedModelsFactories(): bool - { - $modelFactoryContent = file_get_contents(base_path($this->paths['factory'])); - $relatedModels = $this->getRelatedModels($this->model); - $modelNamespace = $this->getOrCreateNamespace('models'); - - foreach ($relatedModels as $relatedModel) { - $relatedFactoryClass = "{$modelNamespace}\\$relatedModel::class"; - $existModelFactory = Str::contains($modelFactoryContent, $relatedFactoryClass); - - if (!$existModelFactory) { - $this->throwFailureException( - exceptionClass: ModelFactoryNotFoundedException::class, - failureMessage: "Not found {$relatedModel} factory for {$relatedModel} model in '{$this->paths['factory']}.", - recommendedMessage: "Please declare a factory for {$relatedModel} model on '{$this->paths['factory']}' " - . "path and run your command with option '--only-tests'." - ); - } - } - - return true; + event(new SuccessCreateMessage("Created a new Factory: {$this->model}Factory")); } protected static function getFakerMethod($field): string @@ -161,40 +75,6 @@ protected static function getCustomMethod($field): string throw new FakerMethodNotFound($message); } - protected function prepareRelatedFactories(): void - { - $relations = array_merge( - $this->relations['hasOne'], - $this->relations['hasMany'], - ); - - foreach ($relations as $relation) { - $modelFactoryContent = file_get_contents(base_path($this->paths['factory'])); - - if (!Str::contains($modelFactoryContent, $this->getModelClass($relation))) { - $this->throwFailureException( - exceptionClass: ModelFactoryNotFound::class, - failureMessage: "Model factory for model {$relation} not found.", - recommendedMessage: "Please create it and after thar you can run this command with flag '--only-tests'." - ); - } - - $matches = []; - - preg_match($this->getFactoryPattern($relation), $modelFactoryContent, $matches); - - foreach ($matches as $match) { - $field = Str::snake($this->model) . '_id'; - - $newField = "\n \"{$field}\" => 1,"; - - $modelFactoryContent = str_replace($match, $match . $newField, $modelFactoryContent); - } - - file_put_contents(base_path($this->paths['factory']), $modelFactoryContent); - } - } - public static function getFactoryFieldsContent($field): string { /** @var Faker $faker */ @@ -218,15 +98,6 @@ public static function getFactoryFieldsContent($field): string return self::getFakerMethod($field); } - protected function checkExistModelFactory(): bool - { - $modelFactoryContent = file_get_contents(base_path($this->paths['factory'])); - $modelNamespace = $this->getOrCreateNamespace('models'); - $factoryClass = "{$modelNamespace}\\$this->model::class"; - - return Str::contains($modelFactoryContent, $factoryClass); - } - protected function prepareFields(): array { $result = []; @@ -242,44 +113,4 @@ protected function prepareFields(): array return $result; } - - protected function getFactoryPattern($model): string - { - $modelNamespace = "App\\\\Models\\\\" . $model; - $return = "return \\["; - - return "/{$modelNamespace}.*{$return}/sU"; - } - - protected function getModelClass($model): string - { - $modelNamespace = $this->getOrCreateNamespace('models'); - - return "{$modelNamespace}\\{$model}"; - } - - protected function getRelatedModels($model) - { - $content = $this->getModelClassContent($model); - - preg_match_all('/(?<=belongsTo\().*(?=::class)/', $content, $matches); - - return head($matches); - } - - protected function getModelClassContent($model): string - { - $path = base_path("{$this->paths['models']}/{$model}.php"); - - if (!$this->classExists('models', $model)) { - $this->throwFailureException( - exceptionClass: ClassNotExistsException::class, - failureMessage: "Cannot get {$model} Model class content cause {$model} Model does not exists.", - recommendedMessage: "Create a {$model} Model by itself or run command " - . "'php artisan make:entity {$model} --only-model'." - ); - } - - return file_get_contents($path); - } } diff --git a/tests/FactoryGeneratorTest.php b/tests/FactoryGeneratorTest.php index edb644a..90ad599 100644 --- a/tests/FactoryGeneratorTest.php +++ b/tests/FactoryGeneratorTest.php @@ -7,8 +7,6 @@ use RonasIT\Support\Events\SuccessCreateMessage; use RonasIT\Support\Exceptions\ClassAlreadyExistsException; use RonasIT\Support\Exceptions\ClassNotExistsException; -use RonasIT\Support\Exceptions\ModelFactoryNotFound; -use RonasIT\Support\Exceptions\ModelFactoryNotFoundedException; use RonasIT\Support\Generators\FactoryGenerator; use RonasIT\Support\Tests\Support\Factory\FactoryMockTrait; @@ -18,25 +16,17 @@ class FactoryGeneratorTest extends TestCase public function testModelNotExists() { - Event::fake(); - $this->expectException(ClassNotExistsException::class); $this->expectExceptionMessage("Cannot create PostFactory cause Post Model does not exists. " . "Create a Post Model by itself or run command 'php artisan make:entity Post --only-model'."); - $this->getFactoryGeneratorMockForMissingModel(); - app(FactoryGenerator::class) ->setModel('Post') ->generate(); - - Event::assertDispatched(SuccessCreateMessage::class); } public function testFactoryClassExists() { - Event::fake(); - $this->expectException(ClassAlreadyExistsException::class); $this->expectExceptionMessage("Cannot create PostFactory cause PostFactory already exists. Remove PostFactory."); @@ -45,123 +35,12 @@ public function testFactoryClassExists() app(FactoryGenerator::class) ->setModel('Post') ->generate(); - - Event::assertDispatched(SuccessCreateMessage::class); - } - - public function testCannotGetContentForGenericFactory() - { - Event::fake(); - - $this->expectException(ClassNotExistsException::class); - $this->expectExceptionMessage("Cannot get Post Model class content cause Post Model does not exists. " - . "Create a Post Model by itself or run command 'php artisan make:entity Post --only-model'."); - - $this->mockForFileExists('database/factories/ModelFactory.php'); - - $this->mockConfigurations(); - $this->mockFilesystem(); - $this->mockFactoryGenerator(); - - app(FactoryGenerator::class) - ->setModel('Post') - ->generate(); - - Event::assertDispatched(SuccessCreateMessage::class); - } - - public function testRelatedModelWithoutFactory() - { - Event::fake(); - - $this->expectException(ModelFactoryNotFoundedException::class); - $this->expectExceptionMessage("Not found Post factory for Post model in 'database/factories/ModelFactory.php. " - . "Please declare a factory for Post model on 'database/factories/ModelFactory.php' " - . "path and run your command with option '--only-tests'."); - - $this->mockConfigurations(); - $this->mockFilesystemForNonExistingRelatedModelFactory(); - $this->mockFactoryGeneratorForMissingRelatedModelFactory(); - - app(FactoryGenerator::class) - ->setModel('Post') - ->setFields([ - 'integer-required' => ['author_id'], - 'string' => ['title'], - ]) - ->generate(); - - Event::assertDispatched(SuccessCreateMessage::class); - } - - public function testRevertedModelFactoryNotExists() - { - $this->expectException(ModelFactoryNotFound::class); - $this->expectExceptionMessage("Model factory for model comment not found. " - . "Please create it and after thar you can run this command with flag '--only-tests'."); - - $this->mockConfigurations(); - $this->getMockGeneratorForMissingRevertedRelationModelFactory(); - $this->mockFilesystemForMissingRevertedRelationModelFactory(); - - app(FactoryGenerator::class) - ->setRelations([ - 'hasOne' => ['comment'], - 'hasMany' => ['comment'], - 'belongsTo' => ['user'], - ]) - ->setModel('Post') - ->generate(); - } - - public function testAlreadyExistsFactory() - { - Event::fake(); - - $this->mockConfigurations(); - $this->mockFactoryGeneratorForAlreadyExistsFactory(); - - $this->mockForFileExists('database/factories/ModelFactory.php'); - - app(FactoryGenerator::class) - ->setModel('Post') - ->generate(); - - Event::assertDispatched(SuccessCreateMessage::class); - } - - public function testCreateGenericFactory() - { - Event::fake(); - - $this->mockConfigurations(); - $this->mockFilesystemForGenericStyleCreation(); - $this->mockFactoryGeneratorForGenericTypeCreation(); - - app(FactoryGenerator::class) - ->setFields([ - 'integer-required' => ['author_id'], - 'string' => ['title', 'iban', 'something'], - 'json' => ['json_text'], - ]) - ->setRelations([ - 'hasOne' => ['User'], - 'hasMany' => [], - 'belongsTo' => ['user'], - ]) - ->setModel('Post') - ->generate(); - - $this->assertGeneratedFileEquals('model_factory.php', '/database/factories/ModelFactory.php'); - - Event::assertDispatched(SuccessCreateMessage::class); } public function testProcessUnknownFieldType() { $this->mockConfigurations(); - $this->mockFilesystemForGenericStyleCreation(); - $this->mockFactoryGeneratorForGenericTypeCreation(); + $this->mockFilesystem(); $this->expectException(ViewException::class); $this->expectExceptionMessage("Cannot generate fake data for unsupported another_type field type. " @@ -181,13 +60,12 @@ public function testProcessUnknownFieldType() } - public function testCreateClassStyleFactory() + public function testCreateSuccess() { Event::fake(); - $this->mockConfigurationsForClassStyleFactory(); - $this->mockFilesystemForClassStyleFactoryCreation(); - $this->mockFactoryGeneratorForClassTypeCreation(); + $this->mockConfigurations(); + $this->mockFilesystem(); app(FactoryGenerator::class) ->setFields([ @@ -205,6 +83,9 @@ public function testCreateClassStyleFactory() $this->assertGeneratedFileEquals('post_factory.php', '/database/factories/PostFactory.php'); - Event::assertDispatched(SuccessCreateMessage::class); + $this->assertEventPushed( + className: SuccessCreateMessage::class, + message: 'Created a new Factory: PostFactory', + ); } } diff --git a/tests/Support/Factory/FactoryMockTrait.php b/tests/Support/Factory/FactoryMockTrait.php index 107ca4b..e6d498c 100644 --- a/tests/Support/Factory/FactoryMockTrait.php +++ b/tests/Support/Factory/FactoryMockTrait.php @@ -2,9 +2,7 @@ namespace RonasIT\Support\Tests\Support\Factory; -use Illuminate\Support\Arr; use org\bovigo\vfs\vfsStream; -use ReflectionClass; use RonasIT\Support\Generators\FactoryGenerator; use RonasIT\Support\Tests\Support\GeneratorMockTrait; use RonasIT\Support\Traits\MockTrait; @@ -13,17 +11,6 @@ trait FactoryMockTrait { use GeneratorMockTrait, MockTrait; - public function getFactoryGeneratorMockForMissingModel(): void - { - $this->mockClass(FactoryGenerator::class, [ - [ - 'function' => 'classExists', - 'arguments' => ['models', 'Post'], - 'result' => false, - ], - ]); - } - public function getFactoryGeneratorMockForExistingFactory(): void { $this->mockClass(FactoryGenerator::class, [ @@ -40,125 +27,9 @@ public function getFactoryGeneratorMockForExistingFactory(): void ]); } - public function getMockGeneratorForMissingRevertedRelationModelFactory(): void - { - $this->mockClass(FactoryGenerator::class, [ - [ - 'function' => 'checkExistRelatedModelsFactories', - 'arguments' => [], - 'result' => true, - ], - [ - 'function' => 'allowedToCreateFactoryInSeparateClass', - 'arguments' => [], - 'result' => false, - ], - ]); - } - - public function mockFactoryGenerator(): void - { - $this->mockClass(FactoryGenerator::class, [ - [ - 'function' => 'classExists', - 'arguments' => ['models', 'Post'], - 'result' => false, - ], - [ - 'function' => 'allowedToCreateFactoryInSeparateClass', - 'arguments' => [], - 'result' => false, - ], - ]); - } - - public function mockFactoryGeneratorForAlreadyExistsFactory(): void - { - $this->mockClass(FactoryGenerator::class, [ - [ - 'function' => 'checkExistModelFactory', - 'arguments' => [], - 'result' => true, - ], - [ - 'function' => 'allowedToCreateFactoryInSeparateClass', - 'arguments' => [], - 'result' => false, - ], - ]); - } - - public function mockFactoryGeneratorForGenericTypeCreation(): void - { - $this->mockClass(FactoryGenerator::class, [ - [ - 'function' => 'allowedToCreateFactoryInSeparateClass', - 'arguments' => [], - 'result' => false, - ], - ]); - } - - public function mockFactoryGeneratorForClassTypeCreation(): void - { - $this->mockClass(FactoryGenerator::class, [ - [ - 'function' => 'allowedToCreateFactoryInSeparateClass', - 'arguments' => [], - 'result' => true, - ], - ]); - } - - public function mockFactoryGeneratorForMissingRelatedModelFactory(): void - { - $this->mockClass(FactoryGenerator::class, [ - [ - 'function' => 'classExists', - 'arguments' => ['models', 'Post'], - 'result' => true, - ], - [ - 'function' => 'allowedToCreateFactoryInSeparateClass', - 'arguments' => [], - 'result' => false, - ], - ]); - } - - public function mockForFileExists(string $filePath, bool $result = true): void - { - $this->mockNativeFunction( - namespace: '\\RonasIT\\Support\\Generators', - callChain: [ - [ - 'function' => 'file_exists', - 'arguments' => Arr::wrap($filePath), - 'result' => $result, - ], - ], - ); - } - public function mockConfigurations(): void { config([ - 'entity-generator.stubs.factory' => 'entity-generator::factory', - 'entity-generator.stubs.legacy_factory' => 'entity-generator::legacy_factory', - 'entity-generator.stubs.legacy_empty_factory' => 'entity-generator::legacy_empty_factory', - 'entity-generator.paths' => [ - 'models' => 'app/Models', - 'factory' => 'database/factories/ModelFactory.php', - ], - ]); - } - - public function mockConfigurationsForClassStyleFactory(): void - { - config([ - 'entity-generator.stubs.factory' => 'entity-generator::factory', - 'entity-generator.stubs.legacy_factory' => 'entity-generator::legacy_factory', - 'entity-generator.stubs.legacy_empty_factory' => 'entity-generator::legacy_empty_factory', 'entity-generator.paths' => [ 'models' => 'app/Models', 'factory' => 'database/factories', @@ -167,90 +38,6 @@ public function mockConfigurationsForClassStyleFactory(): void } public function mockFilesystem(): void - { - $structure = [ - 'app' => [ - 'Services' => [ - 'PostService.php' => ' [], - 'Models' => [], - ], - 'database' => [ - 'factories' => [ - 'ModelFactory.php' => 'getFileName(); - - $structure = [ - 'app' => [ - 'Services' => [ - 'PostService.php' => ' [], - 'Models' => [ - 'Post.php' => file_get_contents($postModelFileName), - 'User.php' => ' [ - 'factories' => [ - 'ModelFactory.php' => ' [ - 'Services' => [ - 'PostService.php' => ' [], - 'Models' => [ - 'Post.php' => ' ' [ - 'factories' => [ - 'ModelFactory.php' => file_get_contents(getcwd() . '/tests/Support/Factory/ModelFactory.php'), - ], - ], - ]; - - vfsStream::create($structure); - } - - public function mockFilesystemForGenericStyleCreation(): void - { - $structure = [ - 'app' => [ - 'Models' => [ - 'Post.php' => file_get_contents(getcwd() . '/tests/Support/Factory/Post.php'), - 'User.php' => ' [], - ]; - - vfsStream::create($structure); - } - - public function mockFilesystemForClassStyleFactoryCreation(): void { $structure = [ 'app' => [ diff --git a/tests/fixtures/FactoryGeneratorTest/model_factory.php b/tests/fixtures/FactoryGeneratorTest/model_factory.php deleted file mode 100644 index 858c0d2..0000000 --- a/tests/fixtures/FactoryGeneratorTest/model_factory.php +++ /dev/null @@ -1,45 +0,0 @@ -define(App\Models\User::class, function (Faker\Generator $faker) { - static $password; - - return [ - "post_id" => 1, - 'name' => $faker->name, - 'email' => $faker->unique()->safeEmail, - 'password' => $password ?: $password = bcrypt('secret'), - 'remember_token' => Str::random(10), - ]; -}); - -$factory->define(App\Models\Role::class, function () { - return [ - 'name' => 'user' - ]; -}); - - -$factory->define(App\Models\Post::class, function (Faker\Generator $faker) { - return [ - 'author_id' => 1, - 'user_id' => 1, - 'title' => $faker->title, - 'iban' => $faker->iban, - 'something' => $faker->word, - 'json_text' => [], - ]; -}); \ No newline at end of file