2020-05-03 14:19:09 +02:00
# 3 Steps to Create Your Own Rector
2020-05-03 14:22:23 +02:00
First, make sure it's not covered by [any existing Rectors ](/docs/rector_rules_overview.md ).
2020-05-03 14:19:09 +02:00
Let's say we want to **change method calls from `set*` to `change*`** .
```diff
$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` ](/src/Rector/AbstractRector.php ). 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
2021-06-09 13:08:07 +00:00
declare(strict_types=1);
namespace Utils\Rector\Rector;
2020-05-03 14:19:09 +02:00
use Nette\Utils\Strings;
use PhpParser\Node;
use PhpParser\Node\Identifier;
use PhpParser\Node\Expr\MethodCall;
use Rector\Core\Rector\AbstractRector;
2020-11-16 17:50:38 +00:00
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
2020-11-16 23:32:24 +00:00
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
2020-05-03 14:19:09 +02:00
final class MyFirstRector extends AbstractRector
{
/**
2021-06-09 15:02:10 +00:00
* @return array< class-string < Node > >
2020-05-03 14:19:09 +02:00
*/
public function getNodeTypes(): array
{
// what node types are we looking for?
2021-02-28 10:36:32 +01:00
// pick any node from https://github.com/rectorphp/php-parser-nodes-docs/
2020-05-03 14:19:09 +02:00
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;
}
2020-06-23 22:07:21 -04:00
$methodCallName = $this->getName($node->name);
2020-05-03 14:19:09 +02:00
$newMethodCallName = Strings::replace($methodCallName, '#^set#', 'change');
$node->name = new Identifier($newMethodCallName);
// return $node if you modified it
return $node;
}
/**
2021-06-09 15:02:10 +00:00
* This method helps other to understand the rule and to generate documentation.
2020-05-03 14:19:09 +02:00
*/
2020-11-16 23:32:24 +00:00
public function getRuleDefinition(): RuleDefinition
2020-05-03 14:19:09 +02:00
{
2020-11-16 23:32:24 +00:00
return new RuleDefinition(
2020-05-03 14:19:09 +02:00
'Change method calls from set* to change*.', [
2020-11-16 23:32:24 +00:00
new CodeSample(
2020-05-03 14:19:09 +02:00
// code before
'$user->setPassword("123456");',
// code after
'$user->changePassword("123456");'
),
]
);
}
}
```
2021-06-09 15:02:10 +00:00
## File Structure
This is how the file structure for custom rule in your own project will look like:
```bash
/src/
/YourCode.php
/utils
/rector
/src
/Rector
MyFirstRector.php
rector.php
composer.json
```
Writing test saves you lot of time in future debugging. Here is a file structure with tests:
2020-05-03 14:19:09 +02:00
```bash
2021-06-09 13:08:07 +00:00
/src/
/YourCode.php
/utils
/rector
/src
/Rector
MyFirstRector.php
/tests
/Rector
/MyFirstRector
2021-06-09 15:02:10 +00:00
/Fixture
test_fixture.php.inc
/config
config.php
2021-06-09 13:08:07 +00:00
MyFirstRectorTest.php
2020-07-29 18:28:19 +02:00
rector.php
2020-05-03 14:19:09 +02:00
composer.json
```
2021-06-09 15:02:10 +00:00
## Update `composer.json`
2020-05-03 14:19:09 +02:00
We also need to load Rector rules in `composer.json` :
```json
{
"autoload": {
"psr-4": {
"App\\": "src"
}
},
"autoload-dev": {
"psr-4": {
2021-06-09 13:08:07 +00:00
"Utils\\Rector\\": "utils/rector/src",
"Utils\\Rector\\Tests\\": "utils/rector/tests"
2020-05-03 14:19:09 +02:00
}
}
}
```
After adding this to `composer.json` , be sure to reload Composer's class map:
```bash
composer dump-autoload
```
## 2. Register It
2020-07-29 18:28:19 +02:00
```php
2021-06-09 13:08:07 +00:00
use Utils\Rector\Rector\MyFirstRector;
2022-04-12 11:52:08 +00:00
use Rector\Config\RectorConfig;
2020-07-29 18:28:19 +02:00
2022-04-12 11:52:08 +00:00
return static function (RectorConfig $rectorConfig): void {
$rectorConfig->rule(MyFirstRector::class);
2020-07-29 18:28:19 +02:00
};
2020-05-03 14:19:09 +02:00
```
## 3. Let Rector Refactor Your Code
2020-07-29 18:28:19 +02:00
The `rector.php` configuration is loaded by default, so we can skip it.
2020-05-03 14:19:09 +02:00
```bash
# see the diff first
vendor/bin/rector process src --dry-run
# if it's ok, apply
vendor/bin/rector process src
```
That's it!
< br >
## Generating a Rector Rule
Do you want to save time with making rules and tests?
2021-03-12 20:13:27 +01:00
Use [the `generate` command ](https://github.com/rectorphp/rector-generator ).