Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RenameClassRector with callback support #3023

Conversation

dorrogeray
Copy link
Contributor

@dorrogeray dorrogeray commented Oct 28, 2022

Hi, sorry for the delayed response. I put this together in order to try to answer question in discussion: Make RenameClassRector more flexible by supporting callbacks?:

Callback enforcing Exception suffix on classes which extend Exception:

<?php

declare(strict_types = 1);

namespace Rector\Tests\Renaming\Rector\Name\RenameClassRector\Source;

use Exception;
use PhpParser\Node\Stmt\ClassLike;
use PHPStan\Reflection\ReflectionProvider;
use Rector\NodeNameResolver\NodeNameResolver;

class EnforceExceptionSuffixCallback
{
    public function __invoke(
        ClassLike $class,
        NodeNameResolver $nodeNameResolver,
        ReflectionProvider $reflectionProvider
    ): ?string {
        $fullyQualifiedClassName = (string) $nodeNameResolver->getName($class);
        $classReflection = $reflectionProvider->getClass($fullyQualifiedClassName);
        if (! $classReflection->isSubclassOf(Exception::class)) {
            return null;
        }

        if (!str_ends_with($fullyQualifiedClassName, 'Exception')) {
            return $fullyQualifiedClassName . 'Exception';
        }

        return null;
    }
}

Callback enforcing Interface suffix on classes which are interfaces:

<?php

declare(strict_types = 1);

namespace Rector\Tests\Renaming\Rector\Name\RenameClassRector\Source;

use PhpParser\Node\Stmt\ClassLike;
use PhpParser\Node\Stmt\Interface_;
use Rector\NodeNameResolver\NodeNameResolver;

class EnforceInterfaceSuffixCallback
{
    public function __invoke(ClassLike $class, NodeNameResolver $nodeNameResolver): ?string {
        $fullyQualifiedClassName = (string) $nodeNameResolver->getName($class);
        if (
            $class instanceof Interface_ &&
            !str_ends_with($fullyQualifiedClassName, 'Interface')
        ) {
            return $fullyQualifiedClassName . 'Interface';
        }

        return null;
    }
}

In final solution the NodeNameResolver and ReflectionProvider could be injected via DI, but it did not work in the unit test out of the box so I have passed it via argument for simplicity.

I don't like the magical callbacks configuration key, but I am not sure what is the best approach here, to keep configuration BC while adding this new feature..

@dorrogeray dorrogeray force-pushed the add-callback-support-to-rename-class-rector branch from 2930e41 to b6c1c4b Compare October 29, 2022 11:29
@dorrogeray dorrogeray marked this pull request as ready for review October 29, 2022 11:36
@dorrogeray dorrogeray force-pushed the add-callback-support-to-rename-class-rector branch 2 times, most recently from 9311624 to e9e3550 Compare November 24, 2022 15:35
@dorrogeray dorrogeray changed the title [draft] RenameClassRector with callback support RenameClassRector with callback support Nov 26, 2022
@dorrogeray dorrogeray force-pushed the add-callback-support-to-rename-class-rector branch from e9e3550 to 808c226 Compare November 26, 2022 16:09
@dorrogeray dorrogeray force-pushed the add-callback-support-to-rename-class-rector branch from 808c226 to 9b56cb1 Compare December 5, 2022 06:34
@dorrogeray
Copy link
Contributor Author

Hi, please let me know if I need to make any additional changes or if the current implementation is acceptable. Thanks! 🙏

Copy link
Member

@samsonasik samsonasik left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you add fixture and with existing configured rule test an verify rename class named __callbacks__, eg:

'__callbacks__' => 'NewSomeOtherClass'

will be renamed working ok?

it seems class named __callbacks__ is valid https://3v4l.org/TJlNv

@dorrogeray dorrogeray force-pushed the add-callback-support-to-rename-class-rector branch from f17c6e8 to 4dc1bd5 Compare December 17, 2022 14:27
@dorrogeray
Copy link
Contributor Author

Could you add fixture and with existing configured rule test an verify rename class named __callbacks__, eg:

'__callbacks__' => 'NewSomeOtherClass'

will be renamed working ok?

it seems class named __callbacks__ is valid https://3v4l.org/TJlNv

Hi, good point. 👍

I have changed the value of RenameClassRector::CALLBACKS from __callbacks__ to #callbacks#, which is not a valid classname: https://3v4l.org/ZuC21

@@ -33,7 +33,7 @@ final class RenameClassRector extends AbstractRector implements ConfigurableRect
/**
* @var string
*/
public const CALLBACKS = '__callbacks__';
public const CALLBACKS = '#callbacks#';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good 👍

@TomasVotruba TomasVotruba merged commit dfad0c3 into rectorphp:main Dec 17, 2022
@TomasVotruba
Copy link
Member

Thank you 👏

@TomasVotruba
Copy link
Member

TomasVotruba commented Aug 9, 2023

Hi @dorrogeray

I'm thinking about this rule in retrospect and it seems it's crossing border with PHPStan and IDE fetaures.
While it might be benefitical for automated fixes of architecture standard, it's leaking feature of dynamic coding to the tool.

It doesn't seem useful to public nor standard sets. Instead these should be handled in a custom Rector rule or better required by PHPStan, as probably is already :)

I wan to keep IDE features and dynamic code sepeate, as we focus mainly on strict and clear no-brainer refactorings. Morover with upcoming GPT coding that goes the opposite way.
Saying that I'll withdraw this feature to keep Rector robuts and focuses.

Despite that, I want to thank you for your input and work 🙏

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
3 participants