mirror of
https://github.com/rectorphp/rector.git
synced 2025-01-18 05:48:21 +01:00
a7705ed0a5
* [composer] bump to Symplify 9 * [Symplify 9] Update phpstan rules * bump to Symplify 9 BETA2 * update AbstractKernel from Tests to Testing namespace * decoupling removing node trait * remove fluent calls * removing variadic * [CodingStyle] Improve AnnotateThrowablesRector * bump deps * Make use of RuleDocGenerator * first short * [DocumentationGenerator] Drop deprecated package, RuleSetGenerator now handles it * import namespace * update docs
3.7 KiB
3.7 KiB
3 Steps to Create Your Own Rector
First, make sure it's not covered by any existing Rectors.
Let's say we want to change method calls from set*
to change*
.
$user = new User();
-$user->setPassword('123456');
+$user->changePassword('123456');
1. Create a New Rector and Implement Methods
Create a class that extends Rector\Core\Rector\AbstractRector
. It will inherit useful methods e.g. to check node type and name. See the source (or type $this->
in an IDE) for a list of available methods.
<?php
declare(strict_types=1);
namespace Utils\Rector;
use Nette\Utils\Strings;
use PhpParser\Node;
use PhpParser\Node\Identifier;
use PhpParser\Node\Expr\MethodCall;
use Rector\Core\Rector\AbstractRector;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Rector\Core\RectorDefinition\RectorDefinition;
final class MyFirstRector extends AbstractRector
{
/**
* @return string[]
*/
public function getNodeTypes(): array
{
// what node types are we looking for?
// pick any node from https://github.com/rectorphp/rector/blob/master/docs/nodes_overview.md
return [MethodCall::class];
}
/**
* @param MethodCall $node - we can add "MethodCall" type here, because
* only this node is in "getNodeTypes()"
*/
public function refactor(Node $node): ?Node
{
// we only care about "set*" method names
if (! $this->isName($node->name, 'set*')) {
// return null to skip it
return null;
}
$methodCallName = $this->getName($node->name);
$newMethodCallName = Strings::replace($methodCallName, '#^set#', 'change');
$node->name = new Identifier($newMethodCallName);
// return $node if you modified it
return $node;
}
/**
* From this method documentation is generated.
*/
public function getRuleDefinition(): \Symplify\RuleDocGenerator\ValueObject\RuleDefinition
{
return new \Symplify\RuleDocGenerator\ValueObject\RuleDefinition(
'Change method calls from set* to change*.', [
new \Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample(
// code before
'$user->setPassword("123456");',
// code after
'$user->changePassword("123456");'
),
]
);
}
}
This is how the file structure should look like:
/src/YourCode.php
/utils/Rector/MyFirstRector.php
rector.php
composer.json
We also need to load Rector rules in composer.json
:
{
"autoload": {
"psr-4": {
"App\\": "src"
}
},
"autoload-dev": {
"psr-4": {
"Utils\\": "utils"
}
}
}
After adding this to composer.json
, be sure to reload Composer's class map:
composer dump-autoload
2. Register It
<?php
// rector.php
declare(strict_types=1);
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
use Utils\Rector\MyFirstRector;
return static function (ContainerConfigurator $containerConfigurator): void {
$services = $containerConfigurator->services();
$services->set(MyFirstRector::class);
};
3. Let Rector Refactor Your Code
The rector.php
configuration is loaded by default, so we can skip it.
# see the diff first
vendor/bin/rector process src --dry-run
# if it's ok, apply
vendor/bin/rector process src
That's it!
Generating a Rector Rule
Do you want to save time with making rules and tests?
Use the create
command.