diff --git a/src/Command/EnumCommand.php b/src/Command/EnumCommand.php index 42ad11f1..c5ff42bc 100644 --- a/src/Command/EnumCommand.php +++ b/src/Command/EnumCommand.php @@ -16,6 +16,7 @@ */ namespace Bake\Command; +use Bake\Utility\Model\EnumParser; use Cake\Console\Arguments; use Cake\Console\ConsoleIo; use Cake\Console\ConsoleOptionParser; @@ -67,7 +68,7 @@ public function template(): string */ public function templateData(Arguments $arguments): array { - $cases = $this->parseCases($arguments->getArgument('cases'), (bool)$arguments->getOption('int')); + $cases = EnumParser::parseCases($arguments->getArgument('cases'), (bool)$arguments->getOption('int')); $isOfTypeInt = $this->isOfTypeInt($cases); $backingType = $isOfTypeInt ? 'int' : 'string'; if ($arguments->getOption('int')) { @@ -101,7 +102,7 @@ public function buildOptionParser(ConsoleOptionParser $parser): ConsoleOptionPar 'help' => 'Name of the enum to bake. You can use Plugin.name to bake plugin enums.', 'required' => true, ])->addArgument('cases', [ - 'help' => 'List of either `one,two` for string or `0:foo,1:bar` for int type.', + 'help' => 'List of either `one,two` for string or `foo:0,bar:1` for int type.', ])->addOption('int', [ 'help' => 'Using backed enums with int instead of string as return type.', 'boolean' => true, @@ -112,35 +113,7 @@ public function buildOptionParser(ConsoleOptionParser $parser): ConsoleOptionPar } /** - * @param string|null $casesString - * @return array - */ - protected function parseCases(?string $casesString, bool $int): array - { - if ($casesString === null) { - return []; - } - - $enumCases = explode(',', $casesString); - - $definition = []; - foreach ($enumCases as $k => $enumCase) { - $key = $value = trim($enumCase); - if (str_contains($key, ':')) { - $value = trim(mb_substr($key, strpos($key, ':') + 1)); - $key = mb_substr($key, 0, strpos($key, ':')); - } elseif ($int) { - $key = $k; - } - - $definition[$key] = $value; - } - - return $definition; - } - - /** - * @param array $definition + * @param array $definition * @return bool */ protected function isOfTypeInt(array $definition): bool @@ -149,8 +122,8 @@ protected function isOfTypeInt(array $definition): bool return false; } - foreach ($definition as $key => $value) { - if (!is_int($key)) { + foreach ($definition as $value) { + if (!is_int($value)) { return false; } } @@ -159,18 +132,18 @@ protected function isOfTypeInt(array $definition): bool } /** - * @param array $cases + * @param array $cases * @return array */ protected function formatCases(array $cases): array { $formatted = []; - foreach ($cases as $case => $alias) { - $alias = mb_strtoupper(Inflector::underscore($alias)); - if (is_string($case)) { - $case = '\'' . $case . '\''; + foreach ($cases as $case => $value) { + $case = Inflector::camelize(Inflector::underscore($case)); + if (is_string($value)) { + $value = '\'' . $value . '\''; } - $formatted[] = 'case ' . $alias . ' = ' . $case . ';'; + $formatted[] = 'case ' . $case . ' = ' . $value . ';'; } return $formatted; diff --git a/src/Command/ModelCommand.php b/src/Command/ModelCommand.php index d495cfc0..e378c808 100644 --- a/src/Command/ModelCommand.php +++ b/src/Command/ModelCommand.php @@ -17,6 +17,7 @@ namespace Bake\Command; use Bake\CodeGen\FileBuilder; +use Bake\Utility\Model\EnumParser; use Bake\Utility\TableScanner; use Cake\Console\Arguments; use Cake\Console\ConsoleIo; @@ -1473,8 +1474,9 @@ protected function getEnumDefinitions(TableSchemaInterface $schema): array continue; } - $enumsDefinitionString = mb_substr($columnSchema['comment'], strpos($columnSchema['comment'], '[enum]') + 6); - $enumsDefinition = $this->parseEnumsDefinition($enumsDefinitionString); + $enumsDefinitionString = trim(mb_substr($columnSchema['comment'], strpos($columnSchema['comment'], '[enum]') + 6)); + $isInt = in_array($columnSchema['type'], ['integer', 'tinyinteger', 'smallinteger', true]); + $enumsDefinition = EnumParser::parseCases($enumsDefinitionString, $isInt); if (!$enumsDefinition) { continue; } diff --git a/src/Utility/Model/EnumParser.php b/src/Utility/Model/EnumParser.php new file mode 100644 index 00000000..92f10080 --- /dev/null +++ b/src/Utility/Model/EnumParser.php @@ -0,0 +1,36 @@ + + */ + public static function parseCases(?string $casesString, bool $int): array + { + if ($casesString === null || $casesString === '') { + return []; + } + + $enumCases = explode(',', $casesString); + + $definition = []; + foreach ($enumCases as $k => $enumCase) { + $case = $value = trim($enumCase); + if (str_contains($case, ':')) { + $value = trim(mb_substr($case, strpos($case, ':') + 1)); + $case = mb_substr($case, 0, strpos($case, ':')); + } elseif ($int) { + $value = $k; + } + + $definition[$case] = $int ? (int)$value : $value; + } + + return $definition; + } +} diff --git a/templates/bake/Model/enum.twig b/templates/bake/Model/enum.twig index 315ed2f6..83f48243 100644 --- a/templates/bake/Model/enum.twig +++ b/templates/bake/Model/enum.twig @@ -33,6 +33,6 @@ enum {{ name }}: {{ backingType }} implements EnumLabelInterface */ public function label(): string { - return Inflector::humanize(mb_strtolower($this->name)); + return Inflector::humanize(Inflector::underscore($this->name)); } } diff --git a/tests/TestCase/Command/EnumCommandTest.php b/tests/TestCase/Command/EnumCommandTest.php index 678aaf40..bc34dcb1 100644 --- a/tests/TestCase/Command/EnumCommandTest.php +++ b/tests/TestCase/Command/EnumCommandTest.php @@ -68,4 +68,36 @@ public function testBakeEnumBackedInt() $result = file_get_contents($this->generatedFile); $this->assertSameAsFile(__FUNCTION__ . '.php', $result); } + + /** + * test baking an enum with string return type and cases + * + * @return void + */ + public function testBakeEnumBackedWithCases() + { + $this->generatedFile = APP . 'Model/Enum/FooBar.php'; + $this->exec('bake enum FooBar foo,bar:b,bar_baz', ['y']); + + $this->assertExitCode(CommandInterface::CODE_SUCCESS); + $this->assertFileExists($this->generatedFile); + $result = file_get_contents($this->generatedFile); + $this->assertSameAsFile(__FUNCTION__ . '.php', $result); + } + + /** + * test baking an enum with string return type and cases + * + * @return void + */ + public function testBakeEnumBackedIntWithCases() + { + $this->generatedFile = APP . 'Model/Enum/FooBar.php'; + $this->exec('bake enum FooBar foo,bar,bar_baz:9 -i', ['y']); + + $this->assertExitCode(CommandInterface::CODE_SUCCESS); + $this->assertFileExists($this->generatedFile); + $result = file_get_contents($this->generatedFile); + $this->assertSameAsFile(__FUNCTION__ . '.php', $result); + } } diff --git a/tests/TestCase/Utility/Model/EnumParserTest.php b/tests/TestCase/Utility/Model/EnumParserTest.php new file mode 100644 index 00000000..bff2c71c --- /dev/null +++ b/tests/TestCase/Utility/Model/EnumParserTest.php @@ -0,0 +1,47 @@ +assertSame([], $cases); + + $cases = EnumParser::parseCases('foo, bar', false); + $this->assertSame(['foo' => 'foo', 'bar' => 'bar'], $cases); + + $cases = EnumParser::parseCases('foo:f, bar:b', false); + $this->assertSame(['foo' => 'f', 'bar' => 'b'], $cases); + + $cases = EnumParser::parseCases('foo:0, bar:1', true); + $this->assertSame(['foo' => 0, 'bar' => 1], $cases); + + $cases = EnumParser::parseCases('foo, bar', true); + $this->assertSame(['foo' => 0, 'bar' => 1], $cases); + } +} diff --git a/tests/comparisons/Model/testBakeEnum.php b/tests/comparisons/Model/testBakeEnum.php index 4b29bbc9..41c6faea 100644 --- a/tests/comparisons/Model/testBakeEnum.php +++ b/tests/comparisons/Model/testBakeEnum.php @@ -16,6 +16,6 @@ enum FooBar: string implements EnumLabelInterface */ public function label(): string { - return Inflector::humanize(mb_strtolower($this->name)); + return Inflector::humanize(Inflector::underscore($this->name)); } } diff --git a/tests/comparisons/Model/testBakeEnumBackedInt.php b/tests/comparisons/Model/testBakeEnumBackedInt.php index 41a5514b..c0c0648c 100644 --- a/tests/comparisons/Model/testBakeEnumBackedInt.php +++ b/tests/comparisons/Model/testBakeEnumBackedInt.php @@ -16,6 +16,6 @@ enum FooBar: int implements EnumLabelInterface */ public function label(): string { - return Inflector::humanize(mb_strtolower($this->name)); + return Inflector::humanize(Inflector::underscore($this->name)); } } diff --git a/tests/comparisons/Model/testBakeEnumBackedIntWithCases.php b/tests/comparisons/Model/testBakeEnumBackedIntWithCases.php new file mode 100644 index 00000000..fcd88e07 --- /dev/null +++ b/tests/comparisons/Model/testBakeEnumBackedIntWithCases.php @@ -0,0 +1,25 @@ +name)); + } +} diff --git a/tests/comparisons/Model/testBakeEnumBackedWithCases.php b/tests/comparisons/Model/testBakeEnumBackedWithCases.php new file mode 100644 index 00000000..403e8fda --- /dev/null +++ b/tests/comparisons/Model/testBakeEnumBackedWithCases.php @@ -0,0 +1,25 @@ +name)); + } +} diff --git a/tests/test_app/App/Model/Enum/BakeUserStatus.php b/tests/test_app/App/Model/Enum/BakeUserStatus.php index be156019..5dcf0ec7 100644 --- a/tests/test_app/App/Model/Enum/BakeUserStatus.php +++ b/tests/test_app/App/Model/Enum/BakeUserStatus.php @@ -19,14 +19,14 @@ enum BakeUserStatus: int implements EnumLabelInterface { - case INACTIVE = 0; - case ACTIVE = 1; + case Inactive = 0; + case Active = 1; /** * @return string */ public function label(): string { - return Inflector::humanize(mb_strtolower($this->name)); + return Inflector::humanize(Inflector::underscore($this->name)); } }