Skip to content

Commit

Permalink
Add protected constants fix (#30)
Browse files Browse the repository at this point in the history
* tidy up

* add protected regex support as well

* misc
  • Loading branch information
TomasVotruba committed May 30, 2024
1 parent 8050337 commit 11d35ea
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 32 deletions.
73 changes: 47 additions & 26 deletions src/Command/PrivatizeConstantsCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,20 +22,42 @@ final class PrivatizeConstantsCommand extends Command
* @var string
* @see https://regex101.com/r/VR8VUD/1
*/
private const CONSTANT_MESSAGE_REGEX = '#constant (?<constant_name>.*?) of class (?<class_name>[\w\\\\]+)#';
private const PRIVATE_CONSTANT_MESSAGE_REGEX = '#constant (?<constant_name>.*?) of class (?<class_name>[\w\\\\]+)#';
/**
* @var string
* @see https://regex101.com/r/pRzdnw/1
*/
private const PROTECTED_CONSTANT_MESSAGE_REGEX = '#Access to undefined constant (?<class_name>[\w\\\\]+)::(?<constant_name>.*?)#';

/**
* @var string
* @see https://regex101.com/r/wkHZwX/1
*/
private const CONST_REGEX = '#( |\t| public )const #ms';
private const CONST_REGEX = '#( |\t)(public )?const #ms';

public function __construct(
private readonly SymfonyStyle $symfonyStyle
) {
parent::__construct();
}

public function resolveProtectedClassConstMatch(string $errorMessage): ?ClassConstMatch
{
if (! str_contains($errorMessage, 'Access to undefined constant')) {
return null;
}

$match = \Nette\Utils\Strings::match($errorMessage, self::PROTECTED_CONSTANT_MESSAGE_REGEX);
if (! isset($match['constant_name'], $match['class_name'])) {
return null;
}

/** @var class-string $className */
$className = (string) $match['class_name'];
return new ClassConstMatch($className, (string) $match['constant_name']);
}

protected function configure(): void
{
$this->setName('privatize-constants');
Expand All @@ -60,36 +82,36 @@ protected function execute(InputInterface $input, OutputInterface $output): int

$phpstanResult = $this->runPHPStanAnalyse($sources);

foreach ($phpstanResult['files'] as $detail) {
foreach ($phpstanResult['files'] as $filePath => $detail) {
foreach ($detail['messages'] as $messageError) {
// @todo check non-existing constants on child/parent access as well

// resolve errorMessage error details
$classConstMatch = $this->resolveClassConstMatch($messageError['message']);
if (! $classConstMatch instanceof ClassConstMatch) {
$publicClassConstMatch = $this->resolvePublicClassConstMatch($messageError['message']);
$protectedClassConstMatch = $this->resolveProtectedClassConstMatch($messageError['message']);
if (! $publicClassConstMatch instanceof ClassConstMatch && ! $protectedClassConstMatch instanceof ClassConstMatch) {
continue;
}

$classFileContents = FileSystem::read($classConstMatch->getClassFileName());

// replace "private const NAME" with "public const NAME"
$changedFileContent = str_replace(
'private const ' . $classConstMatch->getConstantName(),
'public const ' . $classConstMatch->getConstantName(),
$classFileContents
);
$classFileContents = FileSystem::read($filePath);

if ($changedFileContent === $classFileContents) {
continue;
if ($publicClassConstMatch instanceof ClassConstMatch) {
// replace "private const NAME" with "public const NAME"
$classFileContents = str_replace(
'private const ' . $publicClassConstMatch->getConstantName(),
'public const ' . $publicClassConstMatch->getConstantName(),
$classFileContents
);
}

FileSystem::write($classConstMatch->getClassFileName(), $changedFileContent);
if ($protectedClassConstMatch instanceof ClassConstMatch) {
// replace "private const NAME" with "protected const NAME"
$classFileContents = str_replace(
'private const ' . $protectedClassConstMatch->getConstantName(),
'protected const ' . $protectedClassConstMatch->getConstantName(),
$classFileContents
);
}

$this->symfonyStyle->note(sprintf(
'Updated "%s" constant in "%s" file to public as used outside',
$classConstMatch->getConstantName(),
$classConstMatch->getClassFileName()
));
FileSystem::write($filePath, $classFileContents);
}
}

Expand Down Expand Up @@ -147,14 +169,13 @@ private function runPHPStanAnalyse(array $paths): array
return json_decode($resultOutput, true);
}

private function resolveClassConstMatch(string $errorMessage): ?ClassConstMatch
private function resolvePublicClassConstMatch(string $errorMessage): ?ClassConstMatch
{
if (! str_contains($errorMessage, 'Access to private constant')) {
return null;
}

$match = Strings::match($errorMessage, self::CONSTANT_MESSAGE_REGEX);

$match = Strings::match($errorMessage, self::PRIVATE_CONSTANT_MESSAGE_REGEX);
if (! isset($match['constant_name'], $match['class_name'])) {
return null;
}
Expand Down
6 changes: 0 additions & 6 deletions src/ValueObject/ClassConstMatch.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,4 @@ public function getConstantName(): string
{
return $this->constantName;
}

public function getClassFileName(): string
{
$classReflection = new ReflectionClass($this->className);
return (string) $classReflection->getFileName();
}
}

0 comments on commit 11d35ea

Please sign in to comment.