From f7921b11c8138a1ecc8bd1814d4bf043be28303d Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Sun, 15 Dec 2024 13:37:25 -0500 Subject: [PATCH 01/12] feat: make model command --- src/Console/Commands/MakeModel.php | 52 ++++++++++ src/Providers/CommandsServiceProvider.php | 2 + tests/Unit/Console/MakeModelCommandTest.php | 103 ++++++++++++++++++++ 3 files changed, 157 insertions(+) create mode 100644 src/Console/Commands/MakeModel.php create mode 100644 tests/Unit/Console/MakeModelCommandTest.php diff --git a/src/Console/Commands/MakeModel.php b/src/Console/Commands/MakeModel.php new file mode 100644 index 00000000..25cebe3e --- /dev/null +++ b/src/Console/Commands/MakeModel.php @@ -0,0 +1,52 @@ +setHelp('This command allows you to create a new model.'); + + $this->addArgument('name', InputArgument::REQUIRED, 'The model name'); + + $this->addOption('force', 'f', InputOption::VALUE_NONE, 'Force to create model'); + // $this->addOption('api', 'a', InputOption::VALUE_NONE, 'Add API methods to model'); + } + + protected function outputDirectory(): string + { + return 'app' . DIRECTORY_SEPARATOR . 'Models'; + } + + protected function stub(): string + { + // return $this->input->getOption('api') ? 'controller.api.stub' : 'controller.stub'; + return 'model.stub'; + } + + protected function commonName(): string + { + return 'Model'; + } +} diff --git a/src/Providers/CommandsServiceProvider.php b/src/Providers/CommandsServiceProvider.php index 4779e945..0c2512e2 100644 --- a/src/Providers/CommandsServiceProvider.php +++ b/src/Providers/CommandsServiceProvider.php @@ -6,6 +6,7 @@ use Phenix\Console\Commands\MakeController; use Phenix\Console\Commands\MakeMiddleware; +use Phenix\Console\Commands\MakeModel; use Phenix\Console\Commands\MakeRequest; use Phenix\Console\Commands\MakeServiceProvider; use Phenix\Console\Commands\MakeTest; @@ -19,6 +20,7 @@ public function boot(): void MakeRequest::class, MakeController::class, MakeMiddleware::class, + MakeModel::class, MakeServiceProvider::class, ]); } diff --git a/tests/Unit/Console/MakeModelCommandTest.php b/tests/Unit/Console/MakeModelCommandTest.php new file mode 100644 index 00000000..c1992add --- /dev/null +++ b/tests/Unit/Console/MakeModelCommandTest.php @@ -0,0 +1,103 @@ +expect( + exists: fn (string $path) => false, + get: fn (string $path) => '', + put: fn (string $path) => true, + createDirectory: function (string $path): void { + // .. + } + ); + + $this->app->swap(File::class, $mock); + + /** @var CommandTester $command */ + $command = $this->phenix('make:model', [ + 'name' => 'User', + ]); + + $command->assertCommandIsSuccessful(); + + expect($command->getDisplay())->toContain('Model successfully generated!'); +}); + +it('does not create the model because it already exists', function () { + $mock = Mock::of(File::class)->expect( + exists: fn (string $path) => true, + ); + + $this->app->swap(File::class, $mock); + + $this->phenix('make:model', [ + 'name' => 'User', + ]); + + /** @var CommandTester $command */ + $command = $this->phenix('make:model', [ + 'name' => 'User', + ]); + + $command->assertCommandIsSuccessful(); + + expect($command->getDisplay())->toContain('Model already exists!'); +}); + +it('creates model successfully with force option', function () { + $tempDir = sys_get_temp_dir(); + $tempPath = $tempDir . DIRECTORY_SEPARATOR . 'User.php'; + + file_put_contents($tempPath, 'old content'); + + $this->assertEquals('old content', file_get_contents($tempPath)); + + $mock = Mock::of(File::class)->expect( + exists: fn (string $path) => false, + get: fn (string $path) => 'new content', + put: fn (string $path, string $content) => file_put_contents($tempPath, $content), + createDirectory: function (string $path): void { + // .. + } + ); + + $this->app->swap(File::class, $mock); + + /** @var CommandTester $command */ + $command = $this->phenix('make:model', [ + 'name' => 'User', + '--force' => true, + ]); + + $command->assertCommandIsSuccessful(); + + expect($command->getDisplay())->toContain('Model successfully generated!'); + expect('new content')->toBe(file_get_contents($tempPath)); +}); + +it('creates model successfully in nested namespace', function () { + $mock = Mock::of(File::class)->expect( + exists: fn (string $path) => false, + get: fn (string $path) => '', + put: fn (string $path) => true, + createDirectory: function (string $path): void { + // .. + } + ); + + $this->app->swap(File::class, $mock); + + /** @var \Symfony\Component\Console\Tester\CommandTester $command */ + $command = $this->phenix('make:model', [ + 'name' => 'Admin/User', + ]); + + $command->assertCommandIsSuccessful(); + + expect($command->getDisplay())->toContain('Model successfully generated!'); +}); From 47e80b7f243f054ffaf1a8ac497ef6bbd993ef93 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Sun, 15 Dec 2024 13:50:56 -0500 Subject: [PATCH 02/12] feat: model stub --- src/Console/Commands/MakeModel.php | 2 -- src/stubs/model.stub | 15 +++++++++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) create mode 100644 src/stubs/model.stub diff --git a/src/Console/Commands/MakeModel.php b/src/Console/Commands/MakeModel.php index 25cebe3e..3d48a3fb 100644 --- a/src/Console/Commands/MakeModel.php +++ b/src/Console/Commands/MakeModel.php @@ -31,7 +31,6 @@ protected function configure(): void $this->addArgument('name', InputArgument::REQUIRED, 'The model name'); $this->addOption('force', 'f', InputOption::VALUE_NONE, 'Force to create model'); - // $this->addOption('api', 'a', InputOption::VALUE_NONE, 'Add API methods to model'); } protected function outputDirectory(): string @@ -41,7 +40,6 @@ protected function outputDirectory(): string protected function stub(): string { - // return $this->input->getOption('api') ? 'controller.api.stub' : 'controller.stub'; return 'model.stub'; } diff --git a/src/stubs/model.stub b/src/stubs/model.stub new file mode 100644 index 00000000..038c971f --- /dev/null +++ b/src/stubs/model.stub @@ -0,0 +1,15 @@ + Date: Mon, 16 Dec 2024 17:08:23 -0500 Subject: [PATCH 03/12] feat: make collection command --- src/Console/Commands/MakeCollection.php | 50 +++++++++ src/Providers/CommandsServiceProvider.php | 2 + src/stubs/collection.stub | 12 ++ .../Console/MakeCollectionCommandTest.php | 103 ++++++++++++++++++ 4 files changed, 167 insertions(+) create mode 100644 src/Console/Commands/MakeCollection.php create mode 100644 src/stubs/collection.stub create mode 100644 tests/Unit/Console/MakeCollectionCommandTest.php diff --git a/src/Console/Commands/MakeCollection.php b/src/Console/Commands/MakeCollection.php new file mode 100644 index 00000000..1df1f349 --- /dev/null +++ b/src/Console/Commands/MakeCollection.php @@ -0,0 +1,50 @@ +setHelp('This command allows you to create a new collection.'); + + $this->addArgument('name', InputArgument::REQUIRED, 'The collection name'); + + $this->addOption('force', 'f', InputOption::VALUE_NONE, 'Force to create collections'); + } + + protected function outputDirectory(): string + { + return 'app' . DIRECTORY_SEPARATOR . 'Collections'; + } + + protected function stub(): string + { + return 'collection.stub'; + } + + protected function commonName(): string + { + return 'Collection'; + } +} diff --git a/src/Providers/CommandsServiceProvider.php b/src/Providers/CommandsServiceProvider.php index 0c2512e2..a515417f 100644 --- a/src/Providers/CommandsServiceProvider.php +++ b/src/Providers/CommandsServiceProvider.php @@ -4,6 +4,7 @@ namespace Phenix\Providers; +use Phenix\Console\Commands\MakeCollection; use Phenix\Console\Commands\MakeController; use Phenix\Console\Commands\MakeMiddleware; use Phenix\Console\Commands\MakeModel; @@ -21,6 +22,7 @@ public function boot(): void MakeController::class, MakeMiddleware::class, MakeModel::class, + MakeCollection::class, MakeServiceProvider::class, ]); } diff --git a/src/stubs/collection.stub b/src/stubs/collection.stub new file mode 100644 index 00000000..fc0c98cd --- /dev/null +++ b/src/stubs/collection.stub @@ -0,0 +1,12 @@ +expect( + exists: fn (string $path) => false, + get: fn (string $path) => '', + put: fn (string $path) => true, + createDirectory: function (string $path): void { + // .. + } + ); + + $this->app->swap(File::class, $mock); + + /** @var CommandTester $command */ + $command = $this->phenix('make:collection', [ + 'name' => 'User', + ]); + + $command->assertCommandIsSuccessful(); + + expect($command->getDisplay())->toContain('Collection successfully generated!'); +}); + +it('does not create the collection because it already exists', function () { + $mock = Mock::of(File::class)->expect( + exists: fn (string $path) => true, + ); + + $this->app->swap(File::class, $mock); + + $this->phenix('make:collection', [ + 'name' => 'User', + ]); + + /** @var CommandTester $command */ + $command = $this->phenix('make:collection', [ + 'name' => 'User', + ]); + + $command->assertCommandIsSuccessful(); + + expect($command->getDisplay())->toContain('Collection already exists!'); +}); + +it('creates collection successfully with force option', function () { + $tempDir = sys_get_temp_dir(); + $tempPath = $tempDir . DIRECTORY_SEPARATOR . 'User.php'; + + file_put_contents($tempPath, 'old content'); + + $this->assertEquals('old content', file_get_contents($tempPath)); + + $mock = Mock::of(File::class)->expect( + exists: fn (string $path) => false, + get: fn (string $path) => 'new content', + put: fn (string $path, string $content) => file_put_contents($tempPath, $content), + createDirectory: function (string $path): void { + // .. + } + ); + + $this->app->swap(File::class, $mock); + + /** @var CommandTester $command */ + $command = $this->phenix('make:collection', [ + 'name' => 'User', + '--force' => true, + ]); + + $command->assertCommandIsSuccessful(); + + expect($command->getDisplay())->toContain('Collection successfully generated!'); + expect('new content')->toBe(file_get_contents($tempPath)); +}); + +it('creates collection successfully in nested namespace', function () { + $mock = Mock::of(File::class)->expect( + exists: fn (string $path) => false, + get: fn (string $path) => '', + put: fn (string $path) => true, + createDirectory: function (string $path): void { + // .. + } + ); + + $this->app->swap(File::class, $mock); + + /** @var \Symfony\Component\Console\Tester\CommandTester $command */ + $command = $this->phenix('make:collection', [ + 'name' => 'Admin/User', + ]); + + $command->assertCommandIsSuccessful(); + + expect($command->getDisplay())->toContain('Collection successfully generated!'); +}); From 9dbfd7de3c94af1fec8987371b9d246b23bf6c97 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Mon, 16 Dec 2024 18:29:22 -0500 Subject: [PATCH 04/12] feat: make model with collection --- src/Console/Commands/MakeModel.php | 65 ++++++++++++++++++++- src/stubs/model.collection.stub | 21 +++++++ tests/Unit/Console/MakeModelCommandTest.php | 26 +++++++++ 3 files changed, 111 insertions(+), 1 deletion(-) create mode 100644 src/stubs/model.collection.stub diff --git a/src/Console/Commands/MakeModel.php b/src/Console/Commands/MakeModel.php index 3d48a3fb..c3d1a9dc 100644 --- a/src/Console/Commands/MakeModel.php +++ b/src/Console/Commands/MakeModel.php @@ -4,9 +4,13 @@ namespace Phenix\Console\Commands; +use Phenix\Facades\File; use Phenix\Console\Maker; -use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\ArrayInput; use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; class MakeModel extends Maker { @@ -31,6 +35,8 @@ protected function configure(): void $this->addArgument('name', InputArgument::REQUIRED, 'The model name'); $this->addOption('force', 'f', InputOption::VALUE_NONE, 'Force to create model'); + + $this->addOption('collection', 'cn', InputOption::VALUE_NONE, 'Create a collection for the model'); } protected function outputDirectory(): string @@ -40,6 +46,10 @@ protected function outputDirectory(): string protected function stub(): string { + if ($this->input->getOption('collection')) { + return 'model.collection.stub'; + } + return 'model.stub'; } @@ -47,4 +57,57 @@ protected function commonName(): string { return 'Model'; } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $this->input = $input; + + $search = parent::SEARCH; + + $name = $this->input->getArgument('name'); + $force = $this->input->getOption('force'); + $withCollection = $input->getOption('collection'); + + $namespace = explode(DIRECTORY_SEPARATOR, $name); + $className = array_pop($namespace); + $fileName = $this->getCustomFileName() ?? $className; + + $filePath = $this->preparePath($namespace) . DIRECTORY_SEPARATOR . "{$fileName}.php"; + $namespace = $this->prepareNamespace($namespace); + + $replace = [$namespace, $className]; + + if (File::exists($filePath) && ! $force) { + $output->writeln(["{$this->commonName()} already exists!", self::EMPTY_LINE]); + + return parent::SUCCESS; + } + + $application = $this->getApplication(); + + if ($withCollection) { + $command = $application->find('make:collection'); + $collectionName = "{$name}Collection"; + + $arguments = new ArrayInput([ + 'name' => $collectionName, + ]); + + $command->run($arguments, $output); + + $search[] = '{collection_name}'; + $replace[] = $collectionName; + } + + $stub = $this->getStubContent(); + $stub = str_replace($search, $replace, $stub); + + File::put($filePath, $stub); + + $output->writeln(["{$this->commonName()} successfully generated!", self::EMPTY_LINE]); + + + return parent::SUCCESS; + } } + diff --git a/src/stubs/model.collection.stub b/src/stubs/model.collection.stub new file mode 100644 index 00000000..85b062ee --- /dev/null +++ b/src/stubs/model.collection.stub @@ -0,0 +1,21 @@ +getDisplay())->toContain('Model successfully generated!'); }); + +it('creates model with custom collection', function () { + $mock = Mock::of(File::class)->expect( + exists: fn (string $path): bool => false, + get: function (string $path): string { + return file_get_contents($path); + }, + put: fn (string $path): bool => true, + createDirectory: function (string $path): void { + // .. + } + ); + + $this->app->swap(File::class, $mock); + + /** @var CommandTester $command */ + $command = $this->phenix('make:model', [ + 'name' => 'User', + '--collection' => true, + ]); + + $command->assertCommandIsSuccessful(); + + expect($command->getDisplay())->toContain('Model successfully generated!'); + expect($command->getDisplay())->toContain('Collection successfully generated!'); +}); From ab58efef2f8d627f6bbaf111d0fcdc858697772d Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Mon, 16 Dec 2024 18:29:49 -0500 Subject: [PATCH 05/12] refactor: get stub content --- tests/Unit/Console/MakeModelCommandTest.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/Unit/Console/MakeModelCommandTest.php b/tests/Unit/Console/MakeModelCommandTest.php index 06ea0788..427c4dc3 100644 --- a/tests/Unit/Console/MakeModelCommandTest.php +++ b/tests/Unit/Console/MakeModelCommandTest.php @@ -9,7 +9,9 @@ it('creates model successfully', function () { $mock = Mock::of(File::class)->expect( exists: fn (string $path) => false, - get: fn (string $path) => '', + get: function (string $path): string { + return file_get_contents($path); + }, put: fn (string $path) => true, createDirectory: function (string $path): void { // .. From 9bf60f148db6d66e1ed1ade8711a511698ad0399 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Mon, 16 Dec 2024 18:36:34 -0500 Subject: [PATCH 06/12] feat: make query command --- src/Console/Commands/MakeQuery.php | 50 +++++++++ src/Providers/CommandsServiceProvider.php | 2 + src/stubs/query.stub | 12 ++ .../Console/MakeCollectionCommandTest.php | 4 +- tests/Unit/Console/MakeQueryCommandTest.php | 105 ++++++++++++++++++ 5 files changed, 172 insertions(+), 1 deletion(-) create mode 100644 src/Console/Commands/MakeQuery.php create mode 100644 src/stubs/query.stub create mode 100644 tests/Unit/Console/MakeQueryCommandTest.php diff --git a/src/Console/Commands/MakeQuery.php b/src/Console/Commands/MakeQuery.php new file mode 100644 index 00000000..cf0feac4 --- /dev/null +++ b/src/Console/Commands/MakeQuery.php @@ -0,0 +1,50 @@ +setHelp('This command allows you to create a new query.'); + + $this->addArgument('name', InputArgument::REQUIRED, 'The query name'); + + $this->addOption('force', 'f', InputOption::VALUE_NONE, 'Force to create queries'); + } + + protected function outputDirectory(): string + { + return 'app' . DIRECTORY_SEPARATOR . 'Queries'; + } + + protected function stub(): string + { + return 'query.stub'; + } + + protected function commonName(): string + { + return 'Query'; + } +} diff --git a/src/Providers/CommandsServiceProvider.php b/src/Providers/CommandsServiceProvider.php index a515417f..6b940c2c 100644 --- a/src/Providers/CommandsServiceProvider.php +++ b/src/Providers/CommandsServiceProvider.php @@ -8,6 +8,7 @@ use Phenix\Console\Commands\MakeController; use Phenix\Console\Commands\MakeMiddleware; use Phenix\Console\Commands\MakeModel; +use Phenix\Console\Commands\MakeQuery; use Phenix\Console\Commands\MakeRequest; use Phenix\Console\Commands\MakeServiceProvider; use Phenix\Console\Commands\MakeTest; @@ -23,6 +24,7 @@ public function boot(): void MakeMiddleware::class, MakeModel::class, MakeCollection::class, + MakeQuery::class, MakeServiceProvider::class, ]); } diff --git a/src/stubs/query.stub b/src/stubs/query.stub new file mode 100644 index 00000000..e4d6f496 --- /dev/null +++ b/src/stubs/query.stub @@ -0,0 +1,12 @@ +expect( exists: fn (string $path) => false, - get: fn (string $path) => '', + get: function (string $path): string { + return file_get_contents($path); + }, put: fn (string $path) => true, createDirectory: function (string $path): void { // .. diff --git a/tests/Unit/Console/MakeQueryCommandTest.php b/tests/Unit/Console/MakeQueryCommandTest.php new file mode 100644 index 00000000..d2003397 --- /dev/null +++ b/tests/Unit/Console/MakeQueryCommandTest.php @@ -0,0 +1,105 @@ +expect( + exists: fn (string $path) => false, + get: function (string $path): string { + return file_get_contents($path); + }, + put: fn (string $path) => true, + createDirectory: function (string $path): void { + // .. + } + ); + + $this->app->swap(File::class, $mock); + + /** @var CommandTester $command */ + $command = $this->phenix('make:query', [ + 'name' => 'UserQuery', + ]); + + $command->assertCommandIsSuccessful(); + + expect($command->getDisplay())->toContain('Query successfully generated!'); +}); + +it('does not create the query because it already exists', function () { + $mock = Mock::of(File::class)->expect( + exists: fn (string $path) => true, + ); + + $this->app->swap(File::class, $mock); + + $this->phenix('make:query', [ + 'name' => 'UserQuery', + ]); + + /** @var CommandTester $command */ + $command = $this->phenix('make:query', [ + 'name' => 'UserQuery', + ]); + + $command->assertCommandIsSuccessful(); + + expect($command->getDisplay())->toContain('Query already exists!'); +}); + +it('creates query successfully with force option', function () { + $tempDir = sys_get_temp_dir(); + $tempPath = $tempDir . DIRECTORY_SEPARATOR . 'User.php'; + + file_put_contents($tempPath, 'old content'); + + $this->assertEquals('old content', file_get_contents($tempPath)); + + $mock = Mock::of(File::class)->expect( + exists: fn (string $path) => false, + get: fn (string $path) => 'new content', + put: fn (string $path, string $content) => file_put_contents($tempPath, $content), + createDirectory: function (string $path): void { + // .. + } + ); + + $this->app->swap(File::class, $mock); + + /** @var CommandTester $command */ + $command = $this->phenix('make:query', [ + 'name' => 'UserQuery', + '--force' => true, + ]); + + $command->assertCommandIsSuccessful(); + + expect($command->getDisplay())->toContain('Query successfully generated!'); + expect('new content')->toBe(file_get_contents($tempPath)); +}); + +it('creates query successfully in nested namespace', function () { + $mock = Mock::of(File::class)->expect( + exists: fn (string $path) => false, + get: fn (string $path) => '', + put: fn (string $path) => true, + createDirectory: function (string $path): void { + // .. + } + ); + + $this->app->swap(File::class, $mock); + + /** @var \Symfony\Component\Console\Tester\CommandTester $command */ + $command = $this->phenix('make:query', [ + 'name' => 'Domain/UserQuery', + ]); + + $command->assertCommandIsSuccessful(); + + expect($command->getDisplay())->toContain('Query successfully generated!'); +}); From 24c665c60d148d4505af46b0a3fd7231e847bb2b Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Tue, 17 Dec 2024 10:07:51 -0500 Subject: [PATCH 07/12] fix: update collection namespace --- src/stubs/model.collection.stub | 2 +- tests/Unit/Console/MakeModelCommandTest.php | 15 ++++++++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/stubs/model.collection.stub b/src/stubs/model.collection.stub index 85b062ee..2339353f 100644 --- a/src/stubs/model.collection.stub +++ b/src/stubs/model.collection.stub @@ -4,7 +4,7 @@ declare(strict_types=1); namespace {namespace}; -use Phenix\Collections\{collection_name}; +use App\Collections\{collection_name}; use Phenix\Database\Models\DatabaseModel; class {name} extends DatabaseModel diff --git a/tests/Unit/Console/MakeModelCommandTest.php b/tests/Unit/Console/MakeModelCommandTest.php index 427c4dc3..55d82e71 100644 --- a/tests/Unit/Console/MakeModelCommandTest.php +++ b/tests/Unit/Console/MakeModelCommandTest.php @@ -110,7 +110,20 @@ get: function (string $path): string { return file_get_contents($path); }, - put: fn (string $path): bool => true, + put: function (string $path, string $content): bool { + if (str_ends_with($path, 'UserCollection.php')) { + expect($content)->toContain('namespace App\Collections;'); + expect($content)->toContain('class UserCollection extends Collection'); + } + + if (str_ends_with($path, 'User.php')) { + expect($content)->toContain('use App\Collections\UserCollection;'); + expect($content)->toContain('class User extends DatabaseModel'); + expect($content)->toContain('public function newCollection(): UserCollection'); + } + + return true; + }, createDirectory: function (string $path): void { // .. } From 0b2b8324639dd137d4f3df2d8a30d2784ab186c5 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Tue, 17 Dec 2024 10:14:22 -0500 Subject: [PATCH 08/12] feat: make model with custom query builder --- src/Console/Commands/MakeModel.php | 21 +++++++++-- src/stubs/model.query.stub | 21 +++++++++++ tests/Unit/Console/MakeModelCommandTest.php | 39 +++++++++++++++++++++ 3 files changed, 79 insertions(+), 2 deletions(-) create mode 100644 src/stubs/model.query.stub diff --git a/src/Console/Commands/MakeModel.php b/src/Console/Commands/MakeModel.php index c3d1a9dc..e3393901 100644 --- a/src/Console/Commands/MakeModel.php +++ b/src/Console/Commands/MakeModel.php @@ -37,6 +37,8 @@ protected function configure(): void $this->addOption('force', 'f', InputOption::VALUE_NONE, 'Force to create model'); $this->addOption('collection', 'cn', InputOption::VALUE_NONE, 'Create a collection for the model'); + + $this->addOption('query', 'qb', InputOption::VALUE_NONE, 'Create a query builder for the model'); } protected function outputDirectory(): string @@ -48,9 +50,11 @@ protected function stub(): string { if ($this->input->getOption('collection')) { return 'model.collection.stub'; + } elseif ($this->input->getOption('query')) { + return 'model.query.stub'; + } else { + return 'model.stub'; } - - return 'model.stub'; } protected function commonName(): string @@ -67,6 +71,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $name = $this->input->getArgument('name'); $force = $this->input->getOption('force'); $withCollection = $input->getOption('collection'); + $withQuery = $input->getOption('query'); $namespace = explode(DIRECTORY_SEPARATOR, $name); $className = array_pop($namespace); @@ -97,6 +102,18 @@ protected function execute(InputInterface $input, OutputInterface $output): int $search[] = '{collection_name}'; $replace[] = $collectionName; + } elseif ($withQuery) { + $command = $application->find('make:query'); + $queryName = "{$name}Query"; + + $arguments = new ArrayInput([ + 'name' => $queryName, + ]); + + $command->run($arguments, $output); + + $search[] = '{query_name}'; + $replace[] = $queryName; } $stub = $this->getStubContent(); diff --git a/src/stubs/model.query.stub b/src/stubs/model.query.stub new file mode 100644 index 00000000..9d03755f --- /dev/null +++ b/src/stubs/model.query.stub @@ -0,0 +1,21 @@ +getDisplay())->toContain('Model successfully generated!'); expect($command->getDisplay())->toContain('Collection successfully generated!'); }); + +it('creates model with custom query builder', function () { + $mock = Mock::of(File::class)->expect( + exists: fn (string $path): bool => false, + get: function (string $path): string { + return file_get_contents($path); + }, + put: function (string $path, string $content): bool { + if (str_ends_with($path, 'UserQuery.php')) { + expect($content)->toContain('namespace App\Queries;'); + expect($content)->toContain('class UserQuery extends DatabaseQueryBuilder'); + } + + if (str_ends_with($path, 'User.php')) { + expect($content)->toContain('use App\Queries\UserQuery;'); + expect($content)->toContain('class User extends DatabaseModel'); + expect($content)->toContain('protected static function newQueryBuilder(): UserQuery'); + } + + return true; + }, + createDirectory: function (string $path): void { + // .. + } + ); + + $this->app->swap(File::class, $mock); + + /** @var CommandTester $command */ + $command = $this->phenix('make:model', [ + 'name' => 'User', + '--query' => true, + ]); + + $command->assertCommandIsSuccessful(); + + expect($command->getDisplay())->toContain('Model successfully generated!'); + expect($command->getDisplay())->toContain('Query successfully generated!'); +}); From c9608b9bf405bd417372f117c11ec694833c5741 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Tue, 17 Dec 2024 10:23:16 -0500 Subject: [PATCH 09/12] feat: make model with all options --- src/Console/Commands/MakeModel.php | 24 +++++++---- src/stubs/model.all.stub | 27 ++++++++++++ tests/Unit/Console/MakeModelCommandTest.php | 46 +++++++++++++++++++++ 3 files changed, 88 insertions(+), 9 deletions(-) create mode 100644 src/stubs/model.all.stub diff --git a/src/Console/Commands/MakeModel.php b/src/Console/Commands/MakeModel.php index e3393901..7c0a8cac 100644 --- a/src/Console/Commands/MakeModel.php +++ b/src/Console/Commands/MakeModel.php @@ -39,6 +39,8 @@ protected function configure(): void $this->addOption('collection', 'cn', InputOption::VALUE_NONE, 'Create a collection for the model'); $this->addOption('query', 'qb', InputOption::VALUE_NONE, 'Create a query builder for the model'); + + $this->addOption('all', 'a', InputOption::VALUE_NONE, 'Create a model with custom query builder and collection'); } protected function outputDirectory(): string @@ -48,13 +50,17 @@ protected function outputDirectory(): string protected function stub(): string { - if ($this->input->getOption('collection')) { - return 'model.collection.stub'; + $stub = 'model.stub'; + + if ($this->input->getOption('all')) { + $stub = 'model.all.stub'; + } elseif ($this->input->getOption('collection')) { + $stub = 'model.collection.stub'; } elseif ($this->input->getOption('query')) { - return 'model.query.stub'; - } else { - return 'model.stub'; + $stub = 'model.query.stub'; } + + return $stub; } protected function commonName(): string @@ -70,8 +76,6 @@ protected function execute(InputInterface $input, OutputInterface $output): int $name = $this->input->getArgument('name'); $force = $this->input->getOption('force'); - $withCollection = $input->getOption('collection'); - $withQuery = $input->getOption('query'); $namespace = explode(DIRECTORY_SEPARATOR, $name); $className = array_pop($namespace); @@ -90,7 +94,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $application = $this->getApplication(); - if ($withCollection) { + if ($input->getOption('collection') || $input->getOption('all')) { $command = $application->find('make:collection'); $collectionName = "{$name}Collection"; @@ -102,7 +106,9 @@ protected function execute(InputInterface $input, OutputInterface $output): int $search[] = '{collection_name}'; $replace[] = $collectionName; - } elseif ($withQuery) { + } + + if ($input->getOption('query') || $input->getOption('all')) { $command = $application->find('make:query'); $queryName = "{$name}Query"; diff --git a/src/stubs/model.all.stub b/src/stubs/model.all.stub new file mode 100644 index 00000000..edd24346 --- /dev/null +++ b/src/stubs/model.all.stub @@ -0,0 +1,27 @@ +getDisplay())->toContain('Model successfully generated!'); expect($command->getDisplay())->toContain('Query successfully generated!'); }); + +it('creates model with all', function () { + $mock = Mock::of(File::class)->expect( + exists: fn (string $path): bool => false, + get: function (string $path): string { + return file_get_contents($path); + }, + put: function (string $path, string $content): bool { + if (str_ends_with($path, 'UserCollection.php')) { + expect($content)->toContain('namespace App\Collections;'); + expect($content)->toContain('class UserCollection extends Collection'); + } + + if (str_ends_with($path, 'UserQuery.php')) { + expect($content)->toContain('namespace App\Queries;'); + expect($content)->toContain('class UserQuery extends DatabaseQueryBuilder'); + } + + if (str_ends_with($path, 'User.php')) { + expect($content)->toContain('use App\Queries\UserQuery;'); + expect($content)->toContain('class User extends DatabaseModel'); + expect($content)->toContain('protected static function newQueryBuilder(): UserQuery'); + expect($content)->toContain('public function newCollection(): UserCollection'); + } + + return true; + }, + createDirectory: function (string $path): void { + // .. + } + ); + + $this->app->swap(File::class, $mock); + + /** @var CommandTester $command */ + $command = $this->phenix('make:model', [ + 'name' => 'User', + '--all' => true, + ]); + + $command->assertCommandIsSuccessful(); + + expect($command->getDisplay())->toContain('Model successfully generated!'); + expect($command->getDisplay())->toContain('Query successfully generated!'); + expect($command->getDisplay())->toContain('Collection successfully generated!'); +}); From 860f8fa346b59881186a1a542100021a7f77e04b Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Tue, 17 Dec 2024 12:09:09 -0500 Subject: [PATCH 10/12] refactor: reduce code duplications --- src/Console/Commands/MakeModel.php | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/Console/Commands/MakeModel.php b/src/Console/Commands/MakeModel.php index 7c0a8cac..59226d4b 100644 --- a/src/Console/Commands/MakeModel.php +++ b/src/Console/Commands/MakeModel.php @@ -5,14 +5,13 @@ namespace Phenix\Console\Commands; use Phenix\Facades\File; -use Phenix\Console\Maker; use Symfony\Component\Console\Input\ArrayInput; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; -class MakeModel extends Maker +class MakeModel extends CommonMaker { /** * @var string @@ -30,11 +29,7 @@ class MakeModel extends Maker protected function configure(): void { - $this->setHelp('This command allows you to create a new model.'); - - $this->addArgument('name', InputArgument::REQUIRED, 'The model name'); - - $this->addOption('force', 'f', InputOption::VALUE_NONE, 'Force to create model'); + parent::configure(); $this->addOption('collection', 'cn', InputOption::VALUE_NONE, 'Create a collection for the model'); From b37e53879044472f536760d7fb67b5e28cbc26d6 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Tue, 17 Dec 2024 12:09:23 -0500 Subject: [PATCH 11/12] style: phpcs --- src/Console/Commands/MakeCollection.php | 2 +- src/Console/Commands/MakeModel.php | 4 +--- src/Console/Commands/MakeQuery.php | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/Console/Commands/MakeCollection.php b/src/Console/Commands/MakeCollection.php index 1df1f349..c1799641 100644 --- a/src/Console/Commands/MakeCollection.php +++ b/src/Console/Commands/MakeCollection.php @@ -5,8 +5,8 @@ namespace Phenix\Console\Commands; use Phenix\Console\Maker; -use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputOption; class MakeCollection extends Maker { diff --git a/src/Console/Commands/MakeModel.php b/src/Console/Commands/MakeModel.php index 59226d4b..37a4dc44 100644 --- a/src/Console/Commands/MakeModel.php +++ b/src/Console/Commands/MakeModel.php @@ -6,9 +6,8 @@ use Phenix\Facades\File; use Symfony\Component\Console\Input\ArrayInput; -use Symfony\Component\Console\Input\InputOption; -use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; class MakeModel extends CommonMaker @@ -128,4 +127,3 @@ protected function execute(InputInterface $input, OutputInterface $output): int return parent::SUCCESS; } } - diff --git a/src/Console/Commands/MakeQuery.php b/src/Console/Commands/MakeQuery.php index cf0feac4..ce10970f 100644 --- a/src/Console/Commands/MakeQuery.php +++ b/src/Console/Commands/MakeQuery.php @@ -5,8 +5,8 @@ namespace Phenix\Console\Commands; use Phenix\Console\Maker; -use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputOption; class MakeQuery extends Maker { From 6f433c194072606cad4263094901e306492ea8d0 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Tue, 17 Dec 2024 15:17:31 -0500 Subject: [PATCH 12/12] ci: add step to check code format --- .github/workflows/run-tests.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 9873b0aa..56e4ce38 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -32,6 +32,10 @@ jobs: run: | composer install --no-interaction --prefer-dist --no-progress --no-suggest + - name: Check code formatting with PHP CS Fixer + run: | + vendor/bin/php-cs-fixer fix --dry-run --diff --ansi + - name: Check quality code with PHPInsights run: | vendor/bin/phpinsights -n --ansi --format=github-action