Skip to content

Instantly share code, notes, and snippets.

@MrPunyapal
Last active May 20, 2024 15:47
Show Gist options
  • Save MrPunyapal/d9399f1262b542b358a9aa7731228e92 to your computer and use it in GitHub Desktop.
Save MrPunyapal/d9399f1262b542b358a9aa7731228e92 to your computer and use it in GitHub Desktop.
Refactor enums ffrom snake_case to PascalCase.

Task Completed: Replaced All Enums with Pascal Case from SNAKE_CASE

Steps

  1. Copy both files to the appropriate namespace.
  2. Register the Rector rule:
    ->withRules([
        RenameEnumCasesToPascalCaseRector::class,
    ])
  3. Run Rector:
    vendor/bin/rector process
  4. Run the command to apply the same changes to Blade files:
    php artisan refactor:blade-enums

All set!

Limitations

  • This approach does not work if you use self::YOUR_CASE in the enum class.
  • It also fails if you use the following pattern in Blade templates:
    @use('App\Enums\SomeBigNameEnum', 'YourEnum')
  • Avoid running the process twice to prevent conflicts.
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\File;
class RefactorBladeEnums extends Command
{
protected $signature = 'refactor:blade-enums';
protected $description = 'Refactor enum cases in Blade templates from snake_case to PascalCase';
public function handle()
{
$this->info('Refactoring Blade templates...');
$enumClasses = $this->getEnumClasses();
if ($enumClasses === []) {
$this->info('No enum classes found.');
return;
}
$bladeFiles = File::allFiles(resource_path('views'));
foreach ($bladeFiles as $bladeFile) {
$filePath = $bladeFile->getRealPath();
$fileContents = File::get($filePath);
foreach ($enumClasses as $enumClass) {
$fileContents = $this->refactorEnumCases($fileContents, $enumClass);
}
File::put($filePath, $fileContents);
$this->info("Refactored: {$filePath}");
}
$this->info('Refactoring completed!');
}
private function getEnumClasses(): array
{
$enumClasses = [];
$phpFiles = File::allFiles(app_path());
foreach ($phpFiles as $phpFile) {
$filePath = $phpFile->getRealPath();
$fileContents = File::get($filePath);
if (preg_match_all('/enum\s+(\w+)/', $fileContents, $matches)) {
foreach ($matches[1] as $enumClass) {
$namespace = $this->getNamespace($fileContents);
$enumClasses[] = $namespace.'\\'.$enumClass;
}
}
}
return $enumClasses;
}
private function getNamespace(string $fileContents): string
{
if (preg_match('/namespace\s+(.+?);/', $fileContents, $matches)) {
return $matches[1];
}
return '';
}
private function refactorEnumCases(string $content, string $enumClass): string
{
$enumClassName = basename(str_replace('\\', '/', $enumClass));
return preg_replace_callback("/$enumClassName::([A-Z_]+)/", function ($matches) use ($enumClassName) {
$enumCase = $matches[1];
$pascalCase = $this->convertSnakeToPascalCase($enumCase);
return "{$enumClassName}::{$pascalCase}";
}, $content);
}
private function convertSnakeToPascalCase(string $name): string
{
return str_replace(' ', '', ucwords(str_replace('_', ' ', strtolower($name))));
}
}
<?php
declare(strict_types=1);
namespace App\Rector;
use PhpParser\Node;
use PhpParser\Node\Expr\ClassConstFetch;
use PhpParser\Node\Identifier;
use PhpParser\Node\Stmt\EnumCase;
use Rector\Rector\AbstractRector;
use ReflectionClass;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
final class RenameEnumCasesToPascalCaseRector extends AbstractRector
{
public function getRuleDefinition(): RuleDefinition
{
return new RuleDefinition(
'Convert snake_case enum cases to PascalCase',
[
new CodeSample(<<<'CODE_SAMPLE'
enum SomeEnum
{
case SNAKE_CASE_CONSTANT;
}
function example() {
$value = SomeEnum::SNAKE_CASE_CONSTANT;
}
CODE_SAMPLE
,
<<<'CODE_SAMPLE'
enum SomeEnum
{
case SnakeCaseConstant;
}
function example() {
$value = SomeEnum::SnakeCaseConstant;
}
CODE_SAMPLE),
]
);
}
/**
* @return string[]
*/
public function getNodeTypes(): array
{
return [EnumCase::class, ClassConstFetch::class];
}
public function refactor(Node $node): ?Node
{
if ($node instanceof EnumCase) {
return $this->refactorEnumCase($node);
}
if ($node instanceof ClassConstFetch) {
return $this->refactorEnumCaseFetch($node);
}
return null;
}
private function refactorEnumCase(EnumCase $node): ?Node
{
$oldName = $this->getName($node->name);
$newName = $this->convertSnakeToPascalCase($oldName);
if ($oldName !== $newName) {
$node->name = new Identifier($newName);
}
return $node;
}
private function refactorEnumCaseFetch(ClassConstFetch $node): ?Node
{
if ($this->isEnumCaseFetch($node)) {
$oldName = $this->getName($node->name);
if($oldName === 'class'){
return null;
}
$newName = $this->convertSnakeToPascalCase($oldName);
if ($oldName !== $newName) {
$node->name = new Identifier($newName);
}
}
return $node;
}
private function isEnumCaseFetch(ClassConstFetch $node): bool
{
$class = $this->getName($node->class);
if ($class === null) {
return false;
}
// Using ReflectionClass to check if the class is an enum
try {
$reflectionClass = new ReflectionClass($class);
return $reflectionClass->isEnum();
} catch (\ReflectionException $e) {
return false;
}
}
private function convertSnakeToPascalCase(string $name): string
{
return str_replace(' ', '', ucwords(str_replace('_', ' ', strtolower($name))));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment