From f0ba2ee0d81b405e2b65c89902a05d342ed49385 Mon Sep 17 00:00:00 2001 From: Guillaume Turpin Date: Wed, 18 Dec 2024 16:01:54 +0100 Subject: [PATCH 1/9] :sparkles: Make the command with raw and class types --- src/Tempest/Core/src/PublishesFiles.php | 36 ++--- .../src/Commands/MakeMigrationCommand.php | 135 ++++++++++++++++++ .../Database/src/Enums/MigrationType.php | 16 +++ .../Database/src/Stubs/MigrationModelStub.php | 29 ++++ .../Database/src/Stubs/MigrationStub.php | 33 +++++ .../Database/src/Stubs/migration.stub.sql | 5 + 6 files changed, 238 insertions(+), 16 deletions(-) create mode 100644 src/Tempest/Database/src/Commands/MakeMigrationCommand.php create mode 100644 src/Tempest/Database/src/Enums/MigrationType.php create mode 100644 src/Tempest/Database/src/Stubs/MigrationModelStub.php create mode 100644 src/Tempest/Database/src/Stubs/MigrationStub.php create mode 100644 src/Tempest/Database/src/Stubs/migration.stub.sql diff --git a/src/Tempest/Core/src/PublishesFiles.php b/src/Tempest/Core/src/PublishesFiles.php index 5b6a7d203..017aba990 100644 --- a/src/Tempest/Core/src/PublishesFiles.php +++ b/src/Tempest/Core/src/PublishesFiles.php @@ -4,22 +4,23 @@ namespace Tempest\Core; -use Closure; -use Tempest\Console\Exceptions\ConsoleException; -use Tempest\Console\HasConsole; -use Tempest\Container\Inject; -use Tempest\Generation\ClassManipulator; -use Tempest\Generation\DataObjects\StubFile; -use Tempest\Generation\Enums\StubFileType; -use Tempest\Generation\Exceptions\FileGenerationAbortedException; -use Tempest\Generation\Exceptions\FileGenerationFailedException; -use Tempest\Generation\StubFileGenerator; -use Tempest\Support\NamespaceHelper; -use Tempest\Validation\Rules\EndsWith; -use Tempest\Validation\Rules\NotEmpty; -use Throwable; use function Tempest\path; use function Tempest\Support\str; +use Throwable; +use Tempest\Validation\Rules\NotEmpty; +use Tempest\Validation\Rules\EndsWith; +use Tempest\Validation\Rule; +use Tempest\Support\NamespaceHelper; +use Tempest\Generation\StubFileGenerator; +use Tempest\Generation\Exceptions\FileGenerationFailedException; +use Tempest\Generation\Exceptions\FileGenerationAbortedException; +use Tempest\Generation\Enums\StubFileType; +use Tempest\Generation\DataObjects\StubFile; +use Tempest\Generation\ClassManipulator; +use Tempest\Container\Inject; +use Tempest\Console\HasConsole; +use Tempest\Console\Exceptions\ConsoleException; +use Closure; /** * Provides a bunch of methods to publish and generate files and work with common user input. @@ -160,16 +161,19 @@ public function getSuggestedPath(string $className, ?string $pathPrefix = null, /** * Prompt the user for the target path to save the generated file. * @param string $suggestedPath The suggested path to show to the user. + * @param ?array Rules to use instead of the default ones. + * * @return string The target path that the user has chosen. */ - public function promptTargetPath(string $suggestedPath): string + public function promptTargetPath(string $suggestedPath, ?array $rules = null): string { $className = NamespaceHelper::toClassName($suggestedPath); + $rules ??= [new NotEmpty(), new EndsWith('.php')]; return $this->console->ask( question: sprintf('Where do you want to save the file "%s"?', $className), default: $suggestedPath, - validation: [new NotEmpty(), new EndsWith('.php')], + validation: $rules, ); } diff --git a/src/Tempest/Database/src/Commands/MakeMigrationCommand.php b/src/Tempest/Database/src/Commands/MakeMigrationCommand.php new file mode 100644 index 000000000..7d024377e --- /dev/null +++ b/src/Tempest/Database/src/Commands/MakeMigrationCommand.php @@ -0,0 +1,135 @@ +getStubFileFromMigrationType($migrationType); + $targetPath = match ($migrationType) { + MigrationType::RAW => $this->generateRawFile( $fileName, $stubFile ), + default => $this->generateClassFile( $fileName, $stubFile ), + }; + + $this->success(sprintf('Migration file successfully created at "%s".', $targetPath)); + } catch (FileGenerationAbortedException|FileGenerationFailedException|InvalidArgumentException $e) { + $this->error($e->getMessage()); + } + } + + /** + * Generates a raw migration file. + * @param string $fileName The name of the file. + * @param StubFile $stubFile The stub file to use. + * + * @return string The path to the generated file. + */ + protected function generateRawFile( + string $fileName, + StubFile $stubFile, + ): string { + $now = date('Y-m-d'); + $tableName = str($fileName)->snake()->toString(); + $suggestedPath = str($this->getSuggestedPath('Dummy')) + ->replace( + [ 'Dummy', '.php' ], + [ $now . '_' . $tableName, '.sql' ] + ) + ->toString(); + + $targetPath = $this->promptTargetPath($suggestedPath, rules: [ + new NotEmpty(), + new EndsWith('.sql'), + ]); + $shouldOverride = $this->askForOverride($targetPath); + + $this->stubFileGenerator->generateRawFile( + stubFile: $stubFile, + targetPath: $targetPath, + shouldOverride: $shouldOverride, + replacements: [ + 'DummyTableName' => $tableName, + ], + ); + + return $targetPath; + } + + /** + * Generates a class migration file. + * + * @param string $fileName The name of the file. + * @param StubFile $stubFile The stub file to use. + * + * @return string The path to the generated file. + */ + protected function generateClassFile( + string $fileName, + StubFile $stubFile, + ): string { + $suggestedPath = $this->getSuggestedPath($fileName); + $targetPath = $this->promptTargetPath($suggestedPath); + $shouldOverride = $this->askForOverride($targetPath); + + $tableName = str($fileName)->snake()->toString(); + $this->stubFileGenerator->generateClassFile( + stubFile: $stubFile, + targetPath: $targetPath, + shouldOverride: $shouldOverride, + replacements: [ + 'dummy-date' => date('Y-m-d'), + 'dummy-table-name' => $tableName, + ], + ); + + return $targetPath; + } + + private function getStubFileFromMigrationType(MigrationType $migrationType): StubFile + { + try { + return match ($migrationType) { + MigrationType::RAW => StubFile::from(dirname(__DIR__) . '/Stubs/migration.stub.sql'), + MigrationType::MODEL => StubFile::from(MigrationModelStub::class), + MigrationType::OBJECT => StubFile::from(MigrationStub::class), // @phpstan-ignore match.alwaysTrue (Because this is a guardrail for the future implementations) + default => throw new InvalidArgumentException(sprintf('The "%s" migration type has no supported stub file.', $migrationType->value)), + }; + } catch (InvalidArgumentException $invalidArgumentException) { + throw new FileGenerationFailedException(sprintf('Cannot retrieve stub file: %s', $invalidArgumentException->getMessage())); + } + } +} diff --git a/src/Tempest/Database/src/Enums/MigrationType.php b/src/Tempest/Database/src/Enums/MigrationType.php new file mode 100644 index 000000000..3c3852410 --- /dev/null +++ b/src/Tempest/Database/src/Enums/MigrationType.php @@ -0,0 +1,16 @@ +primary() + ->text('name') + ->datetime('created_at') + ->datetime('updated_at'); + } + + public function down(): ?QueryStatement { + return DropTableStatement::forModel('DummyModel'); + } +} diff --git a/src/Tempest/Database/src/Stubs/MigrationStub.php b/src/Tempest/Database/src/Stubs/MigrationStub.php new file mode 100644 index 000000000..f5e53c71d --- /dev/null +++ b/src/Tempest/Database/src/Stubs/MigrationStub.php @@ -0,0 +1,33 @@ +primary() + ->text('name') + ->datetime('created_at') + ->datetime('updated_at'); + } + + public function down(): ?QueryStatement { + return new DropTableStatement( + tableName: 'dummy-table-name' + ); + } +} diff --git a/src/Tempest/Database/src/Stubs/migration.stub.sql b/src/Tempest/Database/src/Stubs/migration.stub.sql new file mode 100644 index 000000000..68bd31d2b --- /dev/null +++ b/src/Tempest/Database/src/Stubs/migration.stub.sql @@ -0,0 +1,5 @@ +CREATE TABLE DummyTableName +( + `id` INTEGER PRIMARY KEY AUTOINCREMENT, + `name` TEXT NOT NULL +); \ No newline at end of file From 10e32430128f5c5ea596b12b2c5860d96ec0923c Mon Sep 17 00:00:00 2001 From: Guillaume Turpin Date: Wed, 18 Dec 2024 16:25:04 +0100 Subject: [PATCH 2/9] :recycle: Update class stubs --- src/Tempest/Database/src/Stubs/MigrationModelStub.php | 8 ++++---- src/Tempest/Database/src/Stubs/MigrationStub.php | 7 ++++--- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/Tempest/Database/src/Stubs/MigrationModelStub.php b/src/Tempest/Database/src/Stubs/MigrationModelStub.php index 5661405cf..41c8c1b6c 100644 --- a/src/Tempest/Database/src/Stubs/MigrationModelStub.php +++ b/src/Tempest/Database/src/Stubs/MigrationModelStub.php @@ -4,15 +4,15 @@ namespace Tempest\Database\Stubs; -use Tempest\Database\Migrations\Migration; +use Tempest\Database\DatabaseMigration; use Tempest\Database\QueryStatement; use Tempest\Database\QueryStatements\CreateTableStatement; use Tempest\Database\QueryStatements\DropTableStatement; -final class MigrationModelStub +final class MigrationModelStub implements DatabaseMigration { - public function getName(): string { - return 'dummy-date_dummy-name'; + public string $name { + get => 'dummy-date_dummy-table-name'; } public function up(): ?QueryStatement { diff --git a/src/Tempest/Database/src/Stubs/MigrationStub.php b/src/Tempest/Database/src/Stubs/MigrationStub.php index f5e53c71d..7822400ab 100644 --- a/src/Tempest/Database/src/Stubs/MigrationStub.php +++ b/src/Tempest/Database/src/Stubs/MigrationStub.php @@ -4,15 +4,16 @@ namespace Tempest\Database\Stubs; +use Tempest\Database\DatabaseMigration; use Tempest\Database\Migrations\Migration; use Tempest\Database\QueryStatement; use Tempest\Database\QueryStatements\CreateTableStatement; use Tempest\Database\QueryStatements\DropTableStatement; -final readonly class MigrationStub +final readonly class MigrationStub implements DatabaseMigration { - public function getName(): string { - return 'dummy-date_dummy-table-name'; + public string $name { + get => 'dummy-date_dummy-table-name'; } public function up(): ?QueryStatement { From 5abf7a9157473b5aec61ad24b8209d90f5e3f4e3 Mon Sep 17 00:00:00 2001 From: Guillaume Turpin Date: Wed, 18 Dec 2024 17:43:31 +0100 Subject: [PATCH 3/9] :construction: WIP add model migration support --- .../src/Commands/MakeMigrationCommand.php | 29 +++++++++++++++---- .../Database/src/Stubs/MigrationStub.php | 2 +- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/src/Tempest/Database/src/Commands/MakeMigrationCommand.php b/src/Tempest/Database/src/Commands/MakeMigrationCommand.php index 7d024377e..5d32b8e15 100644 --- a/src/Tempest/Database/src/Commands/MakeMigrationCommand.php +++ b/src/Tempest/Database/src/Commands/MakeMigrationCommand.php @@ -18,6 +18,8 @@ use Tempest\Validation\Rules\EndsWith; use Tempest\Validation\Rules\NotEmpty; +use function Tempest\get; + final class MakeMigrationCommand { use PublishesFiles; @@ -42,7 +44,7 @@ public function __invoke( $stubFile = $this->getStubFileFromMigrationType($migrationType); $targetPath = match ($migrationType) { MigrationType::RAW => $this->generateRawFile( $fileName, $stubFile ), - default => $this->generateClassFile( $fileName, $stubFile ), + default => $this->generateClassFile( $fileName, $stubFile, $migrationType ), }; $this->success(sprintf('Migration file successfully created at "%s".', $targetPath)); @@ -94,26 +96,41 @@ protected function generateRawFile( * * @param string $fileName The name of the file. * @param StubFile $stubFile The stub file to use. + * @param MigrationType $migrationType The type of the migration. * * @return string The path to the generated file. */ protected function generateClassFile( string $fileName, StubFile $stubFile, + MigrationType $migrationType, ): string { $suggestedPath = $this->getSuggestedPath($fileName); $targetPath = $this->promptTargetPath($suggestedPath); $shouldOverride = $this->askForOverride($targetPath); - $tableName = str($fileName)->snake()->toString(); + + $replacements = [ + 'dummy-date' => date('Y-m-d'), + 'dummy-table-name' => $tableName, + ]; + if ( $migrationType === MigrationType::MODEL ) { + $migrationModel = $this->search('Model related to the migration', function( string $search ) { + // @TODO : Implement the search logic to find all models in app + return [ + 'BookModel', + 'AuthorModel', + ]; + }); + + $replacements['DummyModel'] = $migrationModel; + } + $this->stubFileGenerator->generateClassFile( stubFile: $stubFile, targetPath: $targetPath, shouldOverride: $shouldOverride, - replacements: [ - 'dummy-date' => date('Y-m-d'), - 'dummy-table-name' => $tableName, - ], + replacements: $replacements, ); return $targetPath; diff --git a/src/Tempest/Database/src/Stubs/MigrationStub.php b/src/Tempest/Database/src/Stubs/MigrationStub.php index 7822400ab..7fbc110a3 100644 --- a/src/Tempest/Database/src/Stubs/MigrationStub.php +++ b/src/Tempest/Database/src/Stubs/MigrationStub.php @@ -10,7 +10,7 @@ use Tempest\Database\QueryStatements\CreateTableStatement; use Tempest\Database\QueryStatements\DropTableStatement; -final readonly class MigrationStub implements DatabaseMigration +final class MigrationStub implements DatabaseMigration { public string $name { get => 'dummy-date_dummy-table-name'; From 7597004e34a717c3d4922db8b7959e812305ea30 Mon Sep 17 00:00:00 2001 From: Guillaume Turpin Date: Thu, 19 Dec 2024 16:43:18 +0100 Subject: [PATCH 4/9] :sparkles: Search through models in main namespace to link for --- .../src/Commands/MakeMigrationCommand.php | 101 +++++++++++++++--- 1 file changed, 86 insertions(+), 15 deletions(-) diff --git a/src/Tempest/Database/src/Commands/MakeMigrationCommand.php b/src/Tempest/Database/src/Commands/MakeMigrationCommand.php index 5d32b8e15..d46297a52 100644 --- a/src/Tempest/Database/src/Commands/MakeMigrationCommand.php +++ b/src/Tempest/Database/src/Commands/MakeMigrationCommand.php @@ -4,21 +4,32 @@ namespace Tempest\Database\Commands; +use function Tempest\get; +use function Tempest\Support\arr; + +use Throwable; +use Tempest\Validation\Rules\NotEmpty; +use Tempest\Validation\Rules\EndsWith; +use Tempest\Reflection\ClassReflector; use Tempest\Generation\Exceptions\FileGenerationFailedException; use Tempest\Generation\Exceptions\FileGenerationAbortedException; use Tempest\Generation\Enums\StubFileType; use Tempest\Generation\DataObjects\StubFile; use Tempest\Database\Stubs\MigrationStub; +use Tempest\Database\Stubs\MigrationModelStub; use Tempest\Database\Enums\MigrationType; +use Tempest\Database\DatabaseModel; use Tempest\Core\PublishesFiles; + +use Tempest\Core\DoNotDiscover; +use Tempest\Core\Composer; use Tempest\Console\ConsoleCommand; use Tempest\Console\ConsoleArgument; +use SplFileInfo; +use RecursiveIteratorIterator; +use RecursiveDirectoryIterator; use InvalidArgumentException; -use Tempest\Database\Stubs\MigrationModelStub; -use Tempest\Validation\Rules\EndsWith; -use Tempest\Validation\Rules\NotEmpty; - -use function Tempest\get; +use FilesystemIterator; final class MakeMigrationCommand { @@ -109,21 +120,17 @@ protected function generateClassFile( $targetPath = $this->promptTargetPath($suggestedPath); $shouldOverride = $this->askForOverride($targetPath); $tableName = str($fileName)->snake()->toString(); - $replacements = [ 'dummy-date' => date('Y-m-d'), 'dummy-table-name' => $tableName, ]; + if ( $migrationType === MigrationType::MODEL ) { - $migrationModel = $this->search('Model related to the migration', function( string $search ) { - // @TODO : Implement the search logic to find all models in app - return [ - 'BookModel', - 'AuthorModel', - ]; - }); - - $replacements['DummyModel'] = $migrationModel; + $appModels = $this->getAppDatabaseModels(); + $migrationModel = $this->ask('Model related to the migration', array_keys($appModels)); + $migrationModel = $appModels[$migrationModel] ?? null; + + $replacements["'DummyModel'"] = sprintf('%s::class', $migrationModel?->getName()); } $this->stubFileGenerator->generateClassFile( @@ -149,4 +156,68 @@ private function getStubFileFromMigrationType(MigrationType $migrationType): Stu throw new FileGenerationFailedException(sprintf('Cannot retrieve stub file: %s', $invalidArgumentException->getMessage())); } } + + /** + * Get database models defined in the application. + * + * @return array The list of models. + */ + protected function getAppDatabaseModels(): array + { + $composer = get(Composer::class); + $directories = new RecursiveDirectoryIterator( $composer->mainNamespace->path, flags: FilesystemIterator::UNIX_PATHS | FilesystemIterator::SKIP_DOTS ); + $files = new RecursiveIteratorIterator($directories); + $databaseModels = []; + + foreach ($files as $file) { + // We assume that any PHP file that starts with an uppercase letter will be a class + if ( $file->getExtension() !== 'php' || ucfirst( $file->getFilename() ) !== $file->getFilename() ) { + continue; + } + + // Try to create a PSR-compliant class name from the path + $fqcn = str_replace( + [ + rtrim($composer->mainNamespace->path, '\\/'), + '/', + '\\\\', + '.php', + ], + [ + $composer->mainNamespace->namespace, + '\\', + '\\', + '', + ], + $file->getPathname(), + ); + + // Bail if not a class + if ( ! class_exists( $fqcn ) ) { + continue; + } + + try { + $class = new ClassReflector($fqcn); + } catch (Throwable) { + continue; + } + + // Bail if not a database model + if ( ! $class->implements(DatabaseModel::class) ) { + continue; + } + + // Bail if the class should not be discovered + if ( $class->hasAttribute(DoNotDiscover::class) ) { + continue; + } + + $databaseModels[] = $class; + } + + return arr($databaseModels) + ->mapWithKeys(fn( ClassReflector $model ) => yield $model->getName() => $model) + ->toArray(); + } } From 51f464873515c720eb20be2728f6ea87db77d3cd Mon Sep 17 00:00:00 2001 From: Guillaume Turpin Date: Mon, 23 Dec 2024 09:37:34 +0100 Subject: [PATCH 5/9] :bug: Allow namespaces to be "use" by the ClassManipulator --- src/Tempest/Database/src/Commands/MakeMigrationCommand.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Tempest/Database/src/Commands/MakeMigrationCommand.php b/src/Tempest/Database/src/Commands/MakeMigrationCommand.php index d46297a52..aed4aa9b0 100644 --- a/src/Tempest/Database/src/Commands/MakeMigrationCommand.php +++ b/src/Tempest/Database/src/Commands/MakeMigrationCommand.php @@ -6,6 +6,7 @@ use function Tempest\get; use function Tempest\Support\arr; +use function Tempest\Support\str; use Throwable; use Tempest\Validation\Rules\NotEmpty; @@ -129,10 +130,11 @@ protected function generateClassFile( $appModels = $this->getAppDatabaseModels(); $migrationModel = $this->ask('Model related to the migration', array_keys($appModels)); $migrationModel = $appModels[$migrationModel] ?? null; + $migrationModelName = str($migrationModel?->getName() ?? '')->start('\\')->toString(); - $replacements["'DummyModel'"] = sprintf('%s::class', $migrationModel?->getName()); + $replacements["'DummyModel'"] = sprintf('%s::class', $migrationModelName); } - + $this->stubFileGenerator->generateClassFile( stubFile: $stubFile, targetPath: $targetPath, From 458d5b13b51d01a0223381207beac72cb23f944e Mon Sep 17 00:00:00 2001 From: Guillaume Turpin Date: Mon, 23 Dec 2024 09:39:41 +0100 Subject: [PATCH 6/9] :rotating_light: Run rector --- .../Database/src/Commands/MakeMigrationCommand.php | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/Tempest/Database/src/Commands/MakeMigrationCommand.php b/src/Tempest/Database/src/Commands/MakeMigrationCommand.php index aed4aa9b0..484d58536 100644 --- a/src/Tempest/Database/src/Commands/MakeMigrationCommand.php +++ b/src/Tempest/Database/src/Commands/MakeMigrationCommand.php @@ -72,7 +72,7 @@ public function __invoke( * * @return string The path to the generated file. */ - protected function generateRawFile( + private function generateRawFile( string $fileName, StubFile $stubFile, ): string { @@ -112,7 +112,7 @@ protected function generateRawFile( * * @return string The path to the generated file. */ - protected function generateClassFile( + private function generateClassFile( string $fileName, StubFile $stubFile, MigrationType $migrationType, @@ -164,7 +164,7 @@ private function getStubFileFromMigrationType(MigrationType $migrationType): Stu * * @return array The list of models. */ - protected function getAppDatabaseModels(): array + private function getAppDatabaseModels(): array { $composer = get(Composer::class); $directories = new RecursiveDirectoryIterator( $composer->mainNamespace->path, flags: FilesystemIterator::UNIX_PATHS | FilesystemIterator::SKIP_DOTS ); @@ -173,10 +173,12 @@ protected function getAppDatabaseModels(): array foreach ($files as $file) { // We assume that any PHP file that starts with an uppercase letter will be a class - if ( $file->getExtension() !== 'php' || ucfirst( $file->getFilename() ) !== $file->getFilename() ) { + if ($file->getExtension() !== 'php') { + continue; + } + if (ucfirst( $file->getFilename() ) !== $file->getFilename()) { continue; } - // Try to create a PSR-compliant class name from the path $fqcn = str_replace( [ From f0013044b46775ea9937c7a42f19e0218f9a9746 Mon Sep 17 00:00:00 2001 From: Guillaume Turpin Date: Mon, 23 Dec 2024 09:40:12 +0100 Subject: [PATCH 7/9] :art: Coding styles --- src/Tempest/Core/src/PublishesFiles.php | 32 ++++---- .../src/Commands/MakeMigrationCommand.php | 74 +++++++++---------- 2 files changed, 51 insertions(+), 55 deletions(-) diff --git a/src/Tempest/Core/src/PublishesFiles.php b/src/Tempest/Core/src/PublishesFiles.php index 017aba990..0ec5f635d 100644 --- a/src/Tempest/Core/src/PublishesFiles.php +++ b/src/Tempest/Core/src/PublishesFiles.php @@ -4,23 +4,23 @@ namespace Tempest\Core; +use Closure; +use Tempest\Console\Exceptions\ConsoleException; +use Tempest\Console\HasConsole; +use Tempest\Container\Inject; +use Tempest\Generation\ClassManipulator; +use Tempest\Generation\DataObjects\StubFile; +use Tempest\Generation\Enums\StubFileType; +use Tempest\Generation\Exceptions\FileGenerationAbortedException; +use Tempest\Generation\Exceptions\FileGenerationFailedException; +use Tempest\Generation\StubFileGenerator; +use Tempest\Support\NamespaceHelper; +use Tempest\Validation\Rule; +use Tempest\Validation\Rules\EndsWith; +use Tempest\Validation\Rules\NotEmpty; +use Throwable; use function Tempest\path; use function Tempest\Support\str; -use Throwable; -use Tempest\Validation\Rules\NotEmpty; -use Tempest\Validation\Rules\EndsWith; -use Tempest\Validation\Rule; -use Tempest\Support\NamespaceHelper; -use Tempest\Generation\StubFileGenerator; -use Tempest\Generation\Exceptions\FileGenerationFailedException; -use Tempest\Generation\Exceptions\FileGenerationAbortedException; -use Tempest\Generation\Enums\StubFileType; -use Tempest\Generation\DataObjects\StubFile; -use Tempest\Generation\ClassManipulator; -use Tempest\Container\Inject; -use Tempest\Console\HasConsole; -use Tempest\Console\Exceptions\ConsoleException; -use Closure; /** * Provides a bunch of methods to publish and generate files and work with common user input. @@ -162,7 +162,7 @@ public function getSuggestedPath(string $className, ?string $pathPrefix = null, * Prompt the user for the target path to save the generated file. * @param string $suggestedPath The suggested path to show to the user. * @param ?array Rules to use instead of the default ones. - * + * * @return string The target path that the user has chosen. */ public function promptTargetPath(string $suggestedPath, ?array $rules = null): string diff --git a/src/Tempest/Database/src/Commands/MakeMigrationCommand.php b/src/Tempest/Database/src/Commands/MakeMigrationCommand.php index 484d58536..193e21343 100644 --- a/src/Tempest/Database/src/Commands/MakeMigrationCommand.php +++ b/src/Tempest/Database/src/Commands/MakeMigrationCommand.php @@ -4,34 +4,30 @@ namespace Tempest\Database\Commands; +use FilesystemIterator; +use InvalidArgumentException; +use RecursiveDirectoryIterator; +use RecursiveIteratorIterator; +use Tempest\Console\ConsoleArgument; +use Tempest\Console\ConsoleCommand; +use Tempest\Core\Composer; +use Tempest\Core\DoNotDiscover; +use Tempest\Core\PublishesFiles; +use Tempest\Database\DatabaseModel; +use Tempest\Database\Enums\MigrationType; +use Tempest\Database\Stubs\MigrationModelStub; +use Tempest\Database\Stubs\MigrationStub; +use Tempest\Generation\DataObjects\StubFile; +use Tempest\Generation\Exceptions\FileGenerationAbortedException; +use Tempest\Generation\Exceptions\FileGenerationFailedException; +use Tempest\Reflection\ClassReflector; +use Tempest\Validation\Rules\EndsWith; +use Tempest\Validation\Rules\NotEmpty; +use Throwable; use function Tempest\get; use function Tempest\Support\arr; use function Tempest\Support\str; -use Throwable; -use Tempest\Validation\Rules\NotEmpty; -use Tempest\Validation\Rules\EndsWith; -use Tempest\Reflection\ClassReflector; -use Tempest\Generation\Exceptions\FileGenerationFailedException; -use Tempest\Generation\Exceptions\FileGenerationAbortedException; -use Tempest\Generation\Enums\StubFileType; -use Tempest\Generation\DataObjects\StubFile; -use Tempest\Database\Stubs\MigrationStub; -use Tempest\Database\Stubs\MigrationModelStub; -use Tempest\Database\Enums\MigrationType; -use Tempest\Database\DatabaseModel; -use Tempest\Core\PublishesFiles; - -use Tempest\Core\DoNotDiscover; -use Tempest\Core\Composer; -use Tempest\Console\ConsoleCommand; -use Tempest\Console\ConsoleArgument; -use SplFileInfo; -use RecursiveIteratorIterator; -use RecursiveDirectoryIterator; -use InvalidArgumentException; -use FilesystemIterator; - final class MakeMigrationCommand { use PublishesFiles; @@ -55,8 +51,8 @@ public function __invoke( try { $stubFile = $this->getStubFileFromMigrationType($migrationType); $targetPath = match ($migrationType) { - MigrationType::RAW => $this->generateRawFile( $fileName, $stubFile ), - default => $this->generateClassFile( $fileName, $stubFile, $migrationType ), + MigrationType::RAW => $this->generateRawFile($fileName, $stubFile), + default => $this->generateClassFile($fileName, $stubFile, $migrationType), }; $this->success(sprintf('Migration file successfully created at "%s".', $targetPath)); @@ -69,7 +65,7 @@ public function __invoke( * Generates a raw migration file. * @param string $fileName The name of the file. * @param StubFile $stubFile The stub file to use. - * + * * @return string The path to the generated file. */ private function generateRawFile( @@ -81,7 +77,7 @@ private function generateRawFile( $suggestedPath = str($this->getSuggestedPath('Dummy')) ->replace( [ 'Dummy', '.php' ], - [ $now . '_' . $tableName, '.sql' ] + [ $now . '_' . $tableName, '.sql' ], ) ->toString(); @@ -105,11 +101,11 @@ private function generateRawFile( /** * Generates a class migration file. - * + * * @param string $fileName The name of the file. * @param StubFile $stubFile The stub file to use. * @param MigrationType $migrationType The type of the migration. - * + * * @return string The path to the generated file. */ private function generateClassFile( @@ -126,7 +122,7 @@ private function generateClassFile( 'dummy-table-name' => $tableName, ]; - if ( $migrationType === MigrationType::MODEL ) { + if ($migrationType === MigrationType::MODEL) { $appModels = $this->getAppDatabaseModels(); $migrationModel = $this->ask('Model related to the migration', array_keys($appModels)); $migrationModel = $appModels[$migrationModel] ?? null; @@ -161,22 +157,22 @@ private function getStubFileFromMigrationType(MigrationType $migrationType): Stu /** * Get database models defined in the application. - * + * * @return array The list of models. */ private function getAppDatabaseModels(): array { $composer = get(Composer::class); - $directories = new RecursiveDirectoryIterator( $composer->mainNamespace->path, flags: FilesystemIterator::UNIX_PATHS | FilesystemIterator::SKIP_DOTS ); + $directories = new RecursiveDirectoryIterator($composer->mainNamespace->path, flags: FilesystemIterator::UNIX_PATHS | FilesystemIterator::SKIP_DOTS); $files = new RecursiveIteratorIterator($directories); $databaseModels = []; - + foreach ($files as $file) { // We assume that any PHP file that starts with an uppercase letter will be a class if ($file->getExtension() !== 'php') { continue; } - if (ucfirst( $file->getFilename() ) !== $file->getFilename()) { + if (ucfirst($file->getFilename()) !== $file->getFilename()) { continue; } // Try to create a PSR-compliant class name from the path @@ -197,7 +193,7 @@ private function getAppDatabaseModels(): array ); // Bail if not a class - if ( ! class_exists( $fqcn ) ) { + if (! class_exists($fqcn)) { continue; } @@ -208,12 +204,12 @@ private function getAppDatabaseModels(): array } // Bail if not a database model - if ( ! $class->implements(DatabaseModel::class) ) { + if (! $class->implements(DatabaseModel::class)) { continue; } // Bail if the class should not be discovered - if ( $class->hasAttribute(DoNotDiscover::class) ) { + if ($class->hasAttribute(DoNotDiscover::class)) { continue; } @@ -221,7 +217,7 @@ private function getAppDatabaseModels(): array } return arr($databaseModels) - ->mapWithKeys(fn( ClassReflector $model ) => yield $model->getName() => $model) + ->mapWithKeys(fn (ClassReflector $model) => yield $model->getName() => $model) ->toArray(); } } From 4db814746b0eba7b5210c2ef53526701151ed0d7 Mon Sep 17 00:00:00 2001 From: Guillaume Turpin Date: Mon, 23 Dec 2024 16:33:04 +0100 Subject: [PATCH 8/9] :rotating_light: Fix phpstan --- src/Tempest/Database/src/Stubs/MigrationModelStub.php | 8 ++++---- src/Tempest/Database/src/Stubs/MigrationStub.php | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Tempest/Database/src/Stubs/MigrationModelStub.php b/src/Tempest/Database/src/Stubs/MigrationModelStub.php index 41c8c1b6c..2ffc7f2a1 100644 --- a/src/Tempest/Database/src/Stubs/MigrationModelStub.php +++ b/src/Tempest/Database/src/Stubs/MigrationModelStub.php @@ -15,15 +15,15 @@ final class MigrationModelStub implements DatabaseMigration get => 'dummy-date_dummy-table-name'; } - public function up(): ?QueryStatement { - return CreateTableStatement::forModel('DummyModel') + public function up(): QueryStatement { + return CreateTableStatement::forModel('DummyModel') // @phpstan-ignore-line argument.type (Because this is stub file and this param will be replaced by actual model name) ->primary() ->text('name') ->datetime('created_at') ->datetime('updated_at'); } - public function down(): ?QueryStatement { - return DropTableStatement::forModel('DummyModel'); + public function down(): QueryStatement { + return DropTableStatement::forModel('DummyModel'); // @phpstan-ignore-line argument.type (Because this is stub file and this param will be replaced by actual model name) } } diff --git a/src/Tempest/Database/src/Stubs/MigrationStub.php b/src/Tempest/Database/src/Stubs/MigrationStub.php index 7fbc110a3..2f1488dc9 100644 --- a/src/Tempest/Database/src/Stubs/MigrationStub.php +++ b/src/Tempest/Database/src/Stubs/MigrationStub.php @@ -16,7 +16,7 @@ final class MigrationStub implements DatabaseMigration get => 'dummy-date_dummy-table-name'; } - public function up(): ?QueryStatement { + public function up(): QueryStatement { return new CreateTableStatement( tableName: 'dummy-table-name' ) @@ -26,7 +26,7 @@ public function up(): ?QueryStatement { ->datetime('updated_at'); } - public function down(): ?QueryStatement { + public function down(): QueryStatement { return new DropTableStatement( tableName: 'dummy-table-name' ); From a605067319ae6cdab148993ae2ec364aca6d6b08 Mon Sep 17 00:00:00 2001 From: Guillaume Turpin Date: Mon, 23 Dec 2024 16:40:45 +0100 Subject: [PATCH 9/9] :recycle: Replace help param by description --- src/Tempest/Database/src/Commands/MakeMigrationCommand.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Tempest/Database/src/Commands/MakeMigrationCommand.php b/src/Tempest/Database/src/Commands/MakeMigrationCommand.php index 193e21343..061013ffe 100644 --- a/src/Tempest/Database/src/Commands/MakeMigrationCommand.php +++ b/src/Tempest/Database/src/Commands/MakeMigrationCommand.php @@ -39,12 +39,12 @@ final class MakeMigrationCommand )] public function __invoke( #[ConsoleArgument( - help: 'The file name of the migration', + description: 'The file name of the migration', )] string $fileName, #[ConsoleArgument( name: 'type', - help: 'The type of the migration to create', + description: 'The type of the migration to create', )] MigrationType $migrationType = MigrationType::OBJECT, ): void {