Skip to content

Commit ca2b69a

Browse files
committed
refactor: migrate make:migration to AbstractGeneratorCommand
1 parent 4f9d165 commit ca2b69a

6 files changed

Lines changed: 148 additions & 115 deletions

File tree

‎system/Commands/Generators/MigrationGenerator.php‎

Lines changed: 59 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -13,116 +13,83 @@
1313

1414
namespace CodeIgniter\Commands\Generators;
1515

16-
use CodeIgniter\CLI\BaseCommand;
17-
use CodeIgniter\CLI\CLI;
18-
use CodeIgniter\CLI\GeneratorTrait;
16+
use CodeIgniter\CLI\AbstractGeneratorCommand;
17+
use CodeIgniter\CLI\Attributes\Command;
18+
use CodeIgniter\CLI\Attributes\GeneratorCommand;
19+
use CodeIgniter\CLI\Input\Option;
1920
use Config\Database;
2021
use Config\Migrations;
2122
use Config\Session as SessionConfig;
2223

23-
/**
24-
* Generates a skeleton migration file.
25-
*/
26-
class MigrationGenerator extends BaseCommand
24+
#[Command(name: 'make:migration', description: 'Generates a new migration file.', group: 'Generators')]
25+
#[GeneratorCommand(
26+
component: 'Migration',
27+
template: 'migration.tpl.php',
28+
directory: 'Database\Migrations',
29+
classNameLang: 'CLI.generator.className.migration',
30+
)]
31+
class MigrationGenerator extends AbstractGeneratorCommand
2732
{
28-
use GeneratorTrait;
29-
30-
/**
31-
* The Command's Group
32-
*
33-
* @var string
34-
*/
35-
protected $group = 'Generators';
36-
37-
/**
38-
* The Command's Name
39-
*
40-
* @var string
41-
*/
42-
protected $name = 'make:migration';
43-
44-
/**
45-
* The Command's Description
46-
*
47-
* @var string
48-
*/
49-
protected $description = 'Generates a new migration file.';
50-
51-
/**
52-
* The Command's Usage
53-
*
54-
* @var string
55-
*/
56-
protected $usage = 'make:migration <name> [options]';
57-
58-
/**
59-
* The Command's Arguments
60-
*
61-
* @var array<string, string>
62-
*/
63-
protected $arguments = [
64-
'name' => 'The migration class name.',
65-
];
66-
67-
/**
68-
* The Command's Options
69-
*
70-
* @var array<string, string>
71-
*/
72-
protected $options = [
73-
'--session' => 'Generates the migration file for database sessions.',
74-
'--table' => 'Table name to use for database sessions. Default: "ci_sessions".',
75-
'--dbgroup' => 'Database group to use for database sessions. Default: "default".',
76-
'--namespace' => 'Set root namespace. Default: "APP_NAMESPACE".',
77-
'--suffix' => 'Append the component title to the class name (e.g. User => UserMigration).',
78-
];
33+
protected function configure(): void
34+
{
35+
parent::configure();
36+
37+
$this
38+
->addOption(new Option(
39+
name: 'session',
40+
description: 'Generate the migration file for database sessions.',
41+
))
42+
->addOption(new Option(
43+
name: 'table',
44+
shortcut: 't',
45+
description: 'Table name to use for database sessions.',
46+
requiresValue: true,
47+
default: 'ci_sessions',
48+
))
49+
->addOption(new Option(
50+
name: 'dbgroup',
51+
shortcut: 'g',
52+
description: 'Database group to use for database sessions.',
53+
requiresValue: true,
54+
valueLabel: 'group',
55+
default: 'default',
56+
));
57+
}
7958

80-
/**
81-
* Actually execute a command.
82-
*/
83-
public function run(array $params)
59+
protected function provideGeneratorOptions(): void
8460
{
85-
$this->component = 'Migration';
86-
$this->directory = 'Database\Migrations';
87-
$this->template = 'migration.tpl.php';
61+
$this->addNamespaceOption()->addSuffixOption();
62+
}
8863

89-
if (array_key_exists('session', $params) || CLI::getOption('session')) {
90-
$table = $params['table'] ?? CLI::getOption('table') ?? 'ci_sessions';
91-
$params[0] = "_create_{$table}_table";
64+
protected function initialize(array &$arguments, array &$options): void
65+
{
66+
if (! $this->hasUnboundOption('session', $options)) {
67+
return;
9268
}
9369

94-
$this->classNameLang = 'CLI.generator.className.migration';
95-
$this->generateClass($params);
70+
$table = $this->getUnboundOption('table', $options);
9671

97-
return EXIT_SUCCESS;
72+
$arguments[0] = sprintf('_create_%s_table', is_string($table) ? $table : 'ci_sessions');
9873
}
9974

100-
/**
101-
* Prepare options and do the necessary replacements.
102-
*/
103-
protected function prepare(string $class): string
75+
protected function getTemplateData(string $class): array
10476
{
105-
$data = [];
106-
$data['session'] = false;
107-
108-
if ($this->getOption('session')) {
109-
$table = $this->getOption('table');
110-
$DBGroup = $this->getOption('dbgroup');
111-
112-
$data['session'] = true;
113-
$data['table'] = is_string($table) ? $table : 'ci_sessions';
114-
$data['DBGroup'] = is_string($DBGroup) ? $DBGroup : 'default';
115-
$data['DBDriver'] = config(Database::class)->{$data['DBGroup']}['DBDriver'];
116-
117-
$data['matchIP'] = config(SessionConfig::class)->matchIP;
77+
if ($this->getValidatedOption('session') !== true) {
78+
return ['session' => false];
11879
}
11980

120-
return $this->parseTemplate($class, [], [], $data);
81+
$group = $this->getValidatedOption('dbgroup');
82+
assert(is_string($group));
83+
84+
return [
85+
'session' => true,
86+
'table' => $this->getValidatedOption('table'),
87+
'DBGroup' => $group,
88+
'DBDriver' => config(Database::class)->{$group}['DBDriver'],
89+
'matchIP' => config(SessionConfig::class)->matchIP,
90+
];
12191
}
12292

123-
/**
124-
* Change file basename before saving.
125-
*/
12693
protected function basename(string $filename): string
12794
{
12895
return gmdate(config(Migrations::class)->timestampFormat) . basename($filename);

‎system/Commands/Generators/ScaffoldGenerator.php‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ public function run(array $params)
119119
// Call those commands!
120120
$exit1 = $this->call('make:controller', array_merge([$class], $controllerOpts, $options));
121121
$exit2 = $this->call('make:model', array_merge([$class], $modelOpts, $options));
122-
$exit3 = $this->call('make:migration', array_merge([$class], $options));
122+
$exit3 = $this->call('make:migration', array_merge([$class], array_diff_key($options, ['force' => null])));
123123
$exit4 = $this->call('make:seeder', array_merge([$class], $options));
124124

125125
assert(is_int($exit1) && is_int($exit2) && is_int($exit3) && is_int($exit4));

‎tests/system/Commands/Generators/MigrationGeneratorTest.php‎

Lines changed: 73 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
namespace CodeIgniter\Commands\Generators;
1515

16+
use CodeIgniter\CLI\CLI;
1617
use CodeIgniter\Test\CIUnitTestCase;
1718
use CodeIgniter\Test\StreamFilterTrait;
1819
use PHPUnit\Framework\Attributes\Group;
@@ -25,36 +26,97 @@ final class MigrationGeneratorTest extends CIUnitTestCase
2526
{
2627
use StreamFilterTrait;
2728

29+
protected function setUp(): void
30+
{
31+
parent::setUp();
32+
33+
CLI::reset();
34+
}
35+
2836
protected function tearDown(): void
2937
{
30-
$result = str_replace(["\033[0;32m", "\033[0m", "\n"], '', $this->getStreamFilterBuffer());
31-
$file = str_replace('APPPATH' . DIRECTORY_SEPARATOR, APPPATH, trim(substr($result, 14)));
32-
if (is_file($file)) {
38+
parent::tearDown();
39+
40+
CLI::reset();
41+
42+
foreach (glob(APPPATH . 'Database/Migrations/*_*.php') as $file) {
3343
unlink($file);
3444
}
3545
}
3646

47+
private function getUndecoratedBuffer(): string
48+
{
49+
return preg_replace('/\e\[[^m]+m/', '', $this->getStreamFilterBuffer()) ?? '';
50+
}
51+
52+
private function getContents(string $basename): string
53+
{
54+
$files = glob(APPPATH . 'Database/Migrations/*_' . $basename . '.php');
55+
$this->assertCount(1, $files);
56+
57+
$contents = file_get_contents($files[0]);
58+
$this->assertIsString($contents);
59+
60+
return $contents;
61+
}
62+
3763
public function testGenerateMigration(): void
3864
{
3965
command('make:migration database');
40-
$this->assertStringContainsString('_Database.php', $this->getStreamFilterBuffer());
66+
67+
$this->assertMatchesRegularExpression(
68+
'#^' . PHP_EOL . 'File created: APPPATH/Database/Migrations/\d{4}-\d{2}-\d{2}-\d{6}_Database\.php' . PHP_EOL . '$#',
69+
$this->getUndecoratedBuffer(),
70+
);
71+
72+
$contents = $this->getContents('Database');
73+
$this->assertStringContainsString('namespace App\Database\Migrations;', $contents);
74+
$this->assertStringContainsString('class Database extends Migration', $contents);
75+
$this->assertStringNotContainsString('$DBGroup', $contents);
4176
}
4277

4378
public function testGenerateMigrationWithOptionSession(): void
4479
{
45-
command('make:migration -session');
46-
$this->assertStringContainsString('_CreateCiSessionsTable.php', $this->getStreamFilterBuffer());
80+
command('make:migration --session');
81+
82+
$contents = $this->getContents('CreateCiSessionsTable');
83+
$this->assertStringContainsString('class CreateCiSessionsTable extends Migration', $contents);
84+
$this->assertStringContainsString("protected \$DBGroup = 'default';", $contents);
85+
$this->assertStringContainsString("\$this->forge->addKey('id', true);", $contents);
86+
$this->assertStringContainsString("\$this->forge->createTable('ci_sessions', true);", $contents);
4787
}
4888

49-
public function testGenerateMigrationWithOptionTable(): void
89+
public function testSessionIgnoresNameArgument(): void
5090
{
51-
command('make:migration -session -table logger');
52-
$this->assertStringContainsString('_CreateLoggerTable.php', $this->getStreamFilterBuffer());
91+
command('make:migration database --session');
92+
93+
$this->assertStringContainsString('_CreateCiSessionsTable.php', $this->getUndecoratedBuffer());
94+
$this->assertFileDoesNotExist(APPPATH . 'Database/Migrations/Database.php');
95+
}
96+
97+
public function testGenerateMigrationWithOptionTableAndDbGroup(): void
98+
{
99+
command('make:migration --session --table logger --dbgroup tests');
100+
101+
$contents = $this->getContents('CreateLoggerTable');
102+
$this->assertStringContainsString("protected \$DBGroup = 'tests';", $contents);
103+
$this->assertStringContainsString("\$this->forge->createTable('logger', true);", $contents);
104+
$this->assertStringContainsString("\$this->forge->dropTable('logger', true);", $contents);
105+
}
106+
107+
public function testGenerateMigrationWithShortcuts(): void
108+
{
109+
command('make:migration --session -t logger -g tests');
110+
111+
$contents = $this->getContents('CreateLoggerTable');
112+
$this->assertStringContainsString("protected \$DBGroup = 'tests';", $contents);
113+
$this->assertStringContainsString("\$this->forge->createTable('logger', true);", $contents);
53114
}
54115

55116
public function testGenerateMigrationWithOptionSuffix(): void
56117
{
57-
command('make:migration database -suffix');
58-
$this->assertStringContainsString('_DatabaseMigration.php', $this->getStreamFilterBuffer());
118+
command('make:migration database --suffix');
119+
120+
$this->assertStringContainsString('class DatabaseMigration extends Migration', $this->getContents('DatabaseMigration'));
59121
}
60122
}

‎user_guide_src/source/changelogs/v4.8.0.rst‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ Behavior Changes
3333
- **Commands:** Generator commands migrated to ``AbstractGeneratorCommand`` now return ``EXIT_ERROR`` (previously ``EXIT_SUCCESS``) when the target file exists
3434
without ``--force``, when the namespace is not defined, or when the name does not form a valid class name. The ``CodeIgniter`` namespace confirmation is no
3535
longer prompted on non-interactive runs.
36+
- **Commands:** The ``make:migration`` command now rejects ``--force`` as an unknown option. It was previously accepted but ignored, since the
37+
timestamped file name never collides with an existing file.
3638
- **Commands:** The success and error messages from ``debugbar:clear``, ``cache:clear``, and ``cache:info`` now include the affected path or cache driver/handler so the user can see which resource was acted on (or rejected). Scripts asserting on the prior literal text will need to be updated.
3739
- **Commands:** Declining the ``key:generate`` overwrite prompt interactively now returns ``EXIT_SUCCESS`` instead of ``EXIT_ERROR``. Output messages were also reworded; CI/automation that branches on the exit code or greps the previous wording will need updating.
3840
- **Commands:** The ``migrate:rollback`` command no longer accepts the undocumented ``-g`` (database group) option. It never had any effect, since ``MigrationRunner::regress()`` ignores the group, and the modern command pipeline now rejects unknown options. Remove ``-g`` from any ``migrate:rollback`` invocation.
@@ -238,6 +240,7 @@ Commands
238240
options, which the target command validates like any other input.
239241
- The ``make:controller`` command now accepts ``-b`` and ``-r`` as shortcuts for ``--bare`` and ``--restful``, and rejects an invalid
240242
``--restful`` value on non-interactive runs instead of prompting.
243+
- The ``make:migration`` command now accepts ``-t`` and ``-g`` as shortcuts for ``--table`` and ``--dbgroup``.
241244
- Modern commands can now opt in to prompting for missing required arguments on interactive runs by implementing the new
242245
``PromptsForMissingInputInterface`` marker interface. Prompt labels can be customized via ``getArgumentPromptLabels()``, and an
243246
``afterPrompting()`` hook runs when prompting occurred. Non-interactive runs keep failing fast with the missing-arguments error.

‎user_guide_src/source/cli/cli_generators.rst‎

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -313,12 +313,13 @@ Argument:
313313

314314
Options:
315315
========
316-
* ``--session``: Generate a migration file for database sessions.
317-
* ``--table``: Set the table name to use for database sessions. Defaults to ``ci_sessions``.
318-
* ``--dbgroup``: Set the database group for database sessions. Defaults to ``default`` group.
319-
* ``--namespace``: Set the root namespace. Defaults to value of ``APP_NAMESPACE``.
320-
* ``--suffix``: Append the component suffix to the generated class name.
321-
* ``--force``: Set this flag to overwrite existing files on destination.
316+
* ``--session``: Generate a migration file for database sessions. The ``name`` argument is ignored.
317+
* ``--table`` (``-t``): Set the table name to use for database sessions. Defaults to ``ci_sessions``.
318+
* ``--dbgroup`` (``-g``): Set the database group for database sessions. Defaults to ``default`` group.
319+
* ``--namespace`` (``-n``): Set the root namespace. Defaults to value of ``APP_NAMESPACE``.
320+
* ``--suffix`` (``-s``): Append the component suffix to the generated class name.
321+
322+
.. note:: ``make:migration`` has no ``--force`` option, since the timestamped file name never collides with an existing file.
322323

323324
make:validation
324325
---------------

‎user_guide_src/source/dbmgmt/migration.rst‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -220,15 +220,15 @@ creates is the Pascal case version of the filename.
220220
221221
You can use ``make:migration`` with the following options:
222222

223-
- ``--namespace`` - Set root namespace. Default: ``APP_NAMESPACE``.
224-
- ``--suffix`` - Append the component title to the class name.
223+
- ``--namespace`` (``-n``) - Set root namespace. Default: ``APP_NAMESPACE``.
224+
- ``--suffix`` (``-s``) - Append the component title to the class name.
225225

226226
The following options are also available to generate the migration file for
227227
database sessions:
228228

229-
- ``--session`` - Generates the migration file for database sessions.
230-
- ``--table`` - Table name to use for database sessions. Default: ``ci_sessions``.
231-
- ``--dbgroup`` - Database group to use for database sessions. Default: ``default``.
229+
- ``--session`` - Generates the migration file for database sessions.
230+
- ``--table`` (``-t``) - Table name to use for database sessions. Default: ``ci_sessions``.
231+
- ``--dbgroup`` (``-g``) - Database group to use for database sessions. Default: ``default``.
232232

233233
*********************
234234
Migration Preferences

0 commit comments

Comments
 (0)