Skip to content

Commit 91b3fba

Browse files
committed
Fix issue with special characters in constant/enum-case names
1 parent 31508b8 commit 91b3fba

File tree

7 files changed

+96
-3
lines changed

7 files changed

+96
-3
lines changed

src/PhpConstant.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ public function getName(): string
4141
$currentName = $this->identifier;
4242
$sanitizedName = (string)preg_replace('/^(\d)/', '_$0', $currentName);
4343
$sanitizedName = str_replace('-', '_', $sanitizedName);
44+
$sanitizedName = (string)preg_replace('/[^A-Za-z0-9_]/', '_s_', $sanitizedName);
4445

4546
if ($this->case === self::CASE_NONE) {
4647
return $sanitizedName;

src/Renderer/Php7Renderer.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,8 +129,9 @@ public function renderEnum(PhpEnum $enum): array
129129

130130
foreach ($enum->getCases() as $case) {
131131
$value = $case instanceof EnumBackedCase ? $case->getValue() : null;
132-
$enum->addConstant(PhpConstant::public($case->getName(), $value)->setCase(PhpConstant::CASE_NONE));
133-
$tryFromCtorSource[] = 'if ($value === self::' . $case->getName() . ') {';
132+
$const = PhpConstant::public($case->getName(), $value)->setCase(PhpConstant::CASE_NONE);
133+
$enum->addConstant($const);
134+
$tryFromCtorSource[] = 'if ($value === self::' . $const->getName() . ') {';
134135
$tryFromCtorSource[] = ['return new self($value);'];
135136
$tryFromCtorSource[] = '}';
136137
}

src/ValueObject/EnumCase.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,12 @@ public function __construct(
1010

1111
public function getName(): string
1212
{
13-
return $this->name;
13+
$currentName = $this->name;
14+
$sanitizedName = str_replace('-', '_', $currentName);
15+
$sanitizedName = str_replace(' ', '', ucwords(str_replace('_', ' ', $sanitizedName)));
16+
$sanitizedName = (string)preg_replace('/[^A-Za-z0-9_]/', '_s_', $sanitizedName);
17+
$sanitizedName = (string)preg_replace('/^(\d)/', '_$0', $sanitizedName);
18+
19+
return $sanitizedName;
1420
}
1521
}

tests/Renderer/PhpConstantTest.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,4 +100,12 @@ public function testUpperCaseWithLeadingDigit(): void
100100

101101
$this->assertSame(['public const _3DS = \'3DS\';'], $render->renderConstant($const));
102102
}
103+
104+
public function testSanitizeConstNameFromSpecialCharacters(): void
105+
{
106+
$const = PhpConstant::public(identifier: '>2m');
107+
$render = new Php7Renderer();
108+
109+
$this->assertSame(['public const _S_2M = \'>2m\';'], $render->renderConstant($const));
110+
}
103111
}

tests/Renderer/PhpEnumTest.php

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use Stefna\PhpCodeBuilder\PhpFile;
99
use Stefna\PhpCodeBuilder\Renderer\Php74Renderer;
1010
use Stefna\PhpCodeBuilder\Renderer\Php81Renderer;
11+
use Stefna\PhpCodeBuilder\Renderer\Php8Renderer;
1112
use Stefna\PhpCodeBuilder\ValueObject\EnumBackedCase;
1213
use Stefna\PhpCodeBuilder\ValueObject\EnumCase;
1314
use Stefna\PhpCodeBuilder\ValueObject\Type;
@@ -76,4 +77,36 @@ public function testRenderEnumInFile(): void
7677

7778
$this->assertSourceResult($renderer->render($file), 'PhpEnumTest.' . __FUNCTION__);
7879
}
80+
81+
public function testCaseWithSpecialCharacters(): void
82+
{
83+
$renderer = new Php8Renderer();
84+
$enum = new PhpEnum(
85+
'Test',
86+
Type::fromString('string'),
87+
cases: [
88+
new EnumBackedCase('2m', '2m'),
89+
new EnumBackedCase('>2m', '>2m'),
90+
],
91+
);
92+
$file = PhpFile::createFromClass($enum);
93+
94+
$this->assertSourceResult($renderer->render($file), 'PhpEnumTest.' . __FUNCTION__);
95+
}
96+
97+
public function testCaseWithSpecialCharactersNative(): void
98+
{
99+
$renderer = new Php81Renderer();
100+
$enum = new PhpEnum(
101+
'Test',
102+
Type::fromString('string'),
103+
cases: [
104+
new EnumBackedCase('2m', '2m'),
105+
new EnumBackedCase('>2m', '>2m'),
106+
],
107+
);
108+
$file = PhpFile::createFromClass($enum);
109+
110+
$this->assertSourceResult($renderer->render($file), 'PhpEnumTest.' . __FUNCTION__);
111+
}
79112
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?php declare(strict_types=1);
2+
3+
final class Test
4+
{
5+
public const _2m = '2m';
6+
public const _s_2m = '>2m';
7+
8+
9+
private function __construct(
10+
public string $value,
11+
) {}
12+
13+
public static function from(string $value): self
14+
{
15+
$self = self::tryFrom($value);
16+
if ($self) {
17+
return $self;
18+
}
19+
throw new \ValueError('Enum not found: ' . $value);
20+
}
21+
22+
public static function tryFrom(string $value): ?self
23+
{
24+
if ($value === self::_2m) {
25+
return new self($value);
26+
}
27+
if ($value === self::_s_2m) {
28+
return new self($value);
29+
}
30+
return null;
31+
}
32+
33+
public function __toString(): string
34+
{
35+
return (string)$this->value;
36+
}
37+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<?php declare(strict_types=1);
2+
3+
enum Test: string
4+
{
5+
case _2m = '2m';
6+
case _s_2m = '>2m';
7+
}

0 commit comments

Comments
 (0)