Skip to content

Commit 8903b1d

Browse files
committed
refactor: migrate make:command to AbstractGeneratorCommand
1 parent 4f9d165 commit 8903b1d

7 files changed

Lines changed: 209 additions & 247 deletions

File tree

‎system/Commands/Generators/CommandGenerator.php‎

Lines changed: 68 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -13,111 +13,86 @@
1313

1414
namespace CodeIgniter\Commands\Generators;
1515

16-
use CodeIgniter\CLI\BaseCommand;
16+
use CodeIgniter\CLI\AbstractGeneratorCommand;
17+
use CodeIgniter\CLI\Attributes\Command;
18+
use CodeIgniter\CLI\Attributes\GeneratorCommand;
1719
use CodeIgniter\CLI\CLI;
18-
use CodeIgniter\CLI\GeneratorTrait;
19-
20-
/**
21-
* Generates a skeleton command file.
22-
*/
23-
class CommandGenerator extends BaseCommand
20+
use CodeIgniter\CLI\Input\Option;
21+
22+
#[Command(name: 'make:command', description: 'Generates a new spark command.', group: 'Generators')]
23+
#[GeneratorCommand(
24+
component: 'Command',
25+
template: 'command.tpl.php',
26+
directory: 'Commands',
27+
classNameLang: 'CLI.generator.className.command',
28+
)]
29+
class CommandGenerator extends AbstractGeneratorCommand
2430
{
25-
use GeneratorTrait;
26-
27-
/**
28-
* The Command's Group
29-
*
30-
* @var string
31-
*/
32-
protected $group = 'Generators';
33-
34-
/**
35-
* The Command's Name
36-
*
37-
* @var string
38-
*/
39-
protected $name = 'make:command';
40-
41-
/**
42-
* The Command's Description
43-
*
44-
* @var string
45-
*/
46-
protected $description = 'Generates a new spark command.';
47-
48-
/**
49-
* The Command's Usage
50-
*
51-
* @var string
52-
*/
53-
protected $usage = 'make:command <name> [options]';
54-
55-
/**
56-
* The Command's Arguments
57-
*
58-
* @var array<string, string>
59-
*/
60-
protected $arguments = [
61-
'name' => 'The command class name.',
62-
];
63-
64-
/**
65-
* The Command's Options
66-
*
67-
* @var array<string, string>
68-
*/
69-
protected $options = [
70-
'--command' => 'The command name. Default: "command:name"',
71-
'--type' => 'The command type. Options [basic, generator]. Default: "basic".',
72-
'--group' => 'The command group. Default: [basic -> "App", generator -> "Generators"].',
73-
'--namespace' => 'Set root namespace. Default: "APP_NAMESPACE".',
74-
'--suffix' => 'Append the component title to the class name (e.g. User => UserCommand).',
75-
'--force' => 'Force overwrite existing file.',
76-
];
77-
78-
/**
79-
* Actually execute a command.
80-
*/
81-
public function run(array $params)
31+
protected function configure(): void
32+
{
33+
parent::configure();
34+
35+
$this
36+
->addOption(new Option(
37+
name: 'command',
38+
shortcut: 'c',
39+
description: 'The command name.',
40+
requiresValue: true,
41+
valueLabel: 'name',
42+
default: 'command:name',
43+
))
44+
->addOption(new Option(
45+
name: 'type',
46+
shortcut: 't',
47+
description: 'The command type: "basic" or "generator".',
48+
requiresValue: true,
49+
default: 'basic',
50+
))
51+
->addOption(new Option(
52+
name: 'group',
53+
shortcut: 'g',
54+
description: 'The command group. Defaults to "App" for basic and "Generators" for generator commands.',
55+
acceptsValue: true,
56+
));
57+
}
58+
59+
protected function interact(array &$arguments, array &$options): void
8260
{
83-
$this->component = 'Command';
84-
$this->directory = 'Commands';
85-
$this->template = 'command.tpl.php';
61+
$type = $this->getUnboundOption('type', $options);
8662

87-
$this->classNameLang = 'CLI.generator.className.command';
88-
$this->generateClass($params);
63+
if (! is_string($type) || $type === 'basic' || $type === 'generator') {
64+
return;
65+
}
8966

90-
return EXIT_SUCCESS;
67+
$options['type'] = CLI::prompt(lang('CLI.generator.commandType'), ['basic', 'generator'], 'required');
9168
}
9269

93-
/**
94-
* Prepare options and do the necessary replacements.
95-
*/
96-
protected function prepare(string $class): string
70+
protected function execute(array $arguments, array $options): int
9771
{
98-
$command = $this->getOption('command');
99-
$group = $this->getOption('group');
100-
$type = $this->getOption('type');
101-
102-
$command = is_string($command) ? $command : 'command:name';
103-
$type = is_string($type) ? $type : 'basic';
104-
105-
if (! in_array($type, ['basic', 'generator'], true)) {
106-
// @codeCoverageIgnoreStart
107-
$type = CLI::prompt(lang('CLI.generator.commandType'), ['basic', 'generator'], 'required');
108-
CLI::newLine();
109-
// @codeCoverageIgnoreEnd
72+
$type = $this->getValidatedOption('type');
73+
74+
if ($type !== 'basic' && $type !== 'generator') {
75+
CLI::error(lang('CLI.generator.invalidCommandType', [$type]));
76+
77+
return EXIT_ERROR;
11078
}
11179

80+
return $this->generateClass();
81+
}
82+
83+
protected function getReplacements(string $class): array
84+
{
85+
$group = $this->getValidatedOption('group');
86+
11287
if (! is_string($group)) {
113-
$group = $type === 'generator' ? 'Generators' : 'App';
88+
$group = $this->getValidatedOption('type') === 'generator' ? 'Generators' : 'App';
11489
}
11590

116-
return $this->parseTemplate(
117-
$class,
118-
['{group}', '{command}'],
119-
[$group, $command],
120-
['type' => $type],
121-
);
91+
return ['{command}' => $this->getValidatedOption('command'), '{group}' => $group];
92+
}
93+
94+
protected function getTemplateData(string $class): array
95+
{
96+
return ['type' => $this->getValidatedOption('type')];
12297
}
12398
}

‎system/Commands/Generators/Views/command.tpl.php‎

Lines changed: 16 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -2,77 +2,28 @@
22

33
namespace {namespace};
44

5-
use CodeIgniter\CLI\BaseCommand;
6-
use CodeIgniter\CLI\CLI;
75
<?php if ($type === 'generator'): ?>
8-
use CodeIgniter\CLI\GeneratorTrait;
9-
<?php endif ?>
6+
use CodeIgniter\CLI\AbstractGeneratorCommand;
7+
use CodeIgniter\CLI\Attributes\Command;
8+
use CodeIgniter\CLI\Attributes\GeneratorCommand;
109

11-
class {class} extends BaseCommand
10+
#[Command(name: '{command}', description: '', group: '{group}')]
11+
#[GeneratorCommand(component: 'Command', template: 'command.tpl.php', directory: 'Commands')]
12+
class {class} extends AbstractGeneratorCommand
1213
{
13-
<?php if ($type === 'generator'): ?>
14-
use GeneratorTrait;
15-
16-
<?php endif ?>
17-
/**
18-
* The Command's Group
19-
*
20-
* @var string
21-
*/
22-
protected $group = '{group}';
23-
24-
/**
25-
* The Command's Name
26-
*
27-
* @var string
28-
*/
29-
protected $name = '{command}';
30-
31-
/**
32-
* The Command's Description
33-
*
34-
* @var string
35-
*/
36-
protected $description = '';
37-
38-
/**
39-
* The Command's Usage
40-
*
41-
* @var string
42-
*/
43-
protected $usage = '{command} [arguments] [options]';
44-
45-
/**
46-
* The Command's Arguments
47-
*
48-
* @var array
49-
*/
50-
protected $arguments = [];
51-
52-
/**
53-
* The Command's Options
54-
*
55-
* @var array
56-
*/
57-
protected $options = [];
14+
}
15+
<?php else: ?>
16+
use CodeIgniter\CLI\AbstractCommand;
17+
use CodeIgniter\CLI\Attributes\Command;
5818

59-
/**
60-
* Actually execute a command.
61-
*
62-
* @param array $params
63-
*/
64-
public function run(array $params)
19+
#[Command(name: '{command}', description: '', group: '{group}')]
20+
class {class} extends AbstractCommand
21+
{
22+
protected function execute(array $arguments, array $options): int
6523
{
66-
<?php if ($type === 'generator'): ?>
67-
$this->component = 'Command';
68-
$this->directory = 'Commands';
69-
$this->template = 'command.tpl.php';
70-
71-
$this->generateClass($params);
72-
<?php else: ?>
73-
// your command logic here
74-
<?php endif ?>
24+
//
7525

7626
return EXIT_SUCCESS;
7727
}
7828
}
29+
<?php endif ?>

‎system/Language/en/CLI.php‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
'fileExist' => 'File exists: "{0}"',
4545
'fileOverwrite' => 'File overwritten: "{0}"',
4646
'invalidClassName' => 'Class name "{0}" is not valid.',
47+
'invalidCommandType' => 'Command type "{0}" is not valid.',
4748
'invalidParentClass' => 'Parent class "{0}" is not valid.',
4849
'parentClass' => 'Parent class',
4950
'returnType' => 'Return type',

‎tests/system/CLI/AbstractGeneratorCommandTest.php‎

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,40 @@ public function testInteriorRootNamespaceSegmentIsPreserved(): void
163163
$this->assertStringContainsString('namespace App\Widgets\Sub\App;', $content);
164164
}
165165

166+
/**
167+
* @see https://github.com/codeigniter4/CodeIgniter4/issues/4495
168+
*/
169+
public function testInteriorCaseIsPreserved(): void
170+
{
171+
$command = new GeneratorFixtureCommand(new Commands());
172+
$command->setInteractive(false);
173+
174+
$exitCode = $command->run(['TestModule'], []);
175+
176+
$this->assertSame(EXIT_SUCCESS, $exitCode);
177+
$this->assertFileExists(APPPATH . 'Widgets' . DIRECTORY_SEPARATOR . 'TestModule.php');
178+
}
179+
180+
/**
181+
* @see https://github.com/codeigniter4/CodeIgniter4/issues/4857
182+
*/
183+
public function testNamespaceLikeNameIsNotTreatedAsNamespace(): void
184+
{
185+
$command = new GeneratorFixtureCommand(new Commands());
186+
$command->setInteractive(false);
187+
188+
$exitCode = $command->run(['App_Lesson'], []);
189+
190+
$this->assertSame(EXIT_SUCCESS, $exitCode);
191+
192+
$target = APPPATH . 'Widgets' . DIRECTORY_SEPARATOR . 'AppLesson.php';
193+
$this->assertFileExists($target);
194+
$content = file_get_contents($target);
195+
$this->assertIsString($content);
196+
$this->assertStringContainsString('namespace App\Widgets;', $content);
197+
$this->assertStringContainsString('class AppLesson extends BaseConfig', $content);
198+
}
199+
166200
public function testTrailingSeparatorInNameIsIgnored(): void
167201
{
168202
$command = new GeneratorFixtureCommand(new Commands());

0 commit comments

Comments
 (0)