2017-12-19 23:14:51 +01:00
# Rector - Upgrade your Legacy App to Modern Codebase
2017-07-15 19:20:20 +02:00
2018-09-11 20:46:11 +02:00
Rector is a **rec**onstruc**tor** tool - it does **instant upgrades** and **instant refactoring** of your code.
2019-02-06 18:24:48 +01:00
Why doing it manually if 80% Rector can handle for you?
2018-02-02 17:51:41 +01:00
2017-11-13 02:58:21 +01:00
[![Build Status ](https://img.shields.io/travis/rectorphp/rector/master.svg?style=flat-square )](https://travis-ci.org/rectorphp/rector)
2018-11-09 14:45:14 +01:00
[![Coverage Status ](https://img.shields.io/coveralls/rectorphp/rector/master.svg?style=flat-square )](https://coveralls.io/github/rectorphp/rector?branch=master)
2018-07-02 15:02:27 +02:00
[![Downloads ](https://img.shields.io/packagist/dt/rector/rector.svg?style=flat-square )](https://packagist.org/packages/rector/rector)
2017-07-15 19:20:20 +02:00
2018-10-28 18:02:30 +01:00
2018-01-13 16:01:31 +01:00
![Rector-showcase ](docs/images/rector-showcase.gif )
2018-12-31 12:58:21 +01:00
Rector **instantly upgrades and instantly refactors PHP code of your application** . It covers many open-source projects and PHP changes itself:
2017-07-15 19:20:20 +02:00
2018-10-21 11:00:39 +02:00
< br >
2017-10-30 16:00:28 +01:00
< p align = "center" >
2018-10-21 11:00:07 +02:00
< a href = "/config/level/php" > < img src = "/docs/images/php.png" > < / a >
< img src = "/docs/images/space.png" width = 20 >
< a href = "/config/level/cakephp" > < img src = "/docs/images/cakephp.png" > < / a >
< img src = "/docs/images/space.png" width = 20 >
2018-03-18 18:40:13 -03:00
< a href = "/config/level/symfony" > < img src = "/docs/images/symfony.png" > < / a >
2019-03-09 22:47:22 +00:00
< img src = "/docs/images/space.png" width = 20 >
< a href = "/config/level/symfony" > < img src = "/docs/images/easy-admin.png" > < / a >
2017-12-10 02:52:28 +01:00
< img src = "/docs/images/space.png" width = 20 >
2018-05-26 15:39:01 -03:00
< a href = "/config/level/sylius" > < img src = "/docs/images/sylius.png" > < / a >
2018-05-22 17:43:36 +02:00
< img src = "/docs/images/space.png" width = 20 >
2018-03-18 18:40:13 -03:00
< a href = "/config/level/phpunit" > < img src = "/docs/images/phpunit.jpg" > < / a >
2017-12-10 02:52:28 +01:00
< img src = "/docs/images/space.png" width = 20 >
2018-03-18 18:40:13 -03:00
< a href = "/config/level/twig" > < img src = "/docs/images/twig.png" > < / a >
2018-09-26 21:26:04 +08:00
< img src = "/docs/images/space.png" width = 20 >
2019-03-04 09:34:42 +01:00
< a href = "/config/level/laravel" > < img src = "/docs/images/laravel.png" > < / a >
< img src = "/docs/images/space.png" width = 20 >
2018-09-27 01:15:10 +08:00
< a href = "/config/level/silverstripe" > < img src = "/docs/images/silverstripe.jpg" > < / a >
2017-10-30 16:00:28 +01:00
< / p >
2017-08-20 17:40:19 +02:00
2018-10-21 11:00:39 +02:00
< br >
2018-08-01 22:29:01 +02:00
**Rector can**:
2019-03-09 13:23:11 +00:00
- Rename classes, methods, properties, namespaces, constants... anything :)
2018-08-01 22:29:01 +02:00
- Add, replace or remove arguments
2019-03-09 14:29:44 +00:00
- Add [parameter or return type declarations ](https://www.tomasvotruba.cz/blog/2019/01/03/how-to-complete-type-declarations-without-docblocks-with-rector/ ) without docblocks - just with static analysis
2019-03-09 13:23:11 +00:00
- Upgrade from PHP 5.3 to PHP 7.4
2019-04-02 15:35:35 +02:00
- [Migrate from one PHP framework to another ](https://www.tomasvotruba.cz/blog/2019/02/21/how-we-migrated-from-nette-to-symfony-in-3-weeks-part-1/ )
2019-03-09 13:23:11 +00:00
- [Complete PHP 7.4 property type declarations ](https://www.tomasvotruba.cz/blog/2018/11/15/how-to-get-php-74-typed-properties-to-your-code-in-few-seconds/ )
2019-04-02 15:35:35 +02:00
- [Turn Laravel static to Dependency Injection ](https://www.tomasvotruba.cz/blog/2019/03/04/how-to-turn-laravel-from-static-to-dependency-injection-in-one-day/ )
2017-12-28 17:58:35 -02:00
- And much more...
2017-07-15 19:20:20 +02:00
2018-11-09 14:58:49 +01:00
...**look at overview of [all available Rectors ](/docs/AllRectorsOverview.md )** with before/after diffs and configuration examples. You can use them to build your own sets.
2018-04-29 11:03:47 +02:00
2017-07-15 19:20:20 +02:00
## Install
```bash
2018-10-07 01:28:57 +08:00
composer require rector/rector --dev
2017-07-15 19:20:20 +02:00
```
2018-12-31 20:27:38 +01:00
**Do you have conflicts on `composer require` or on run?**
2018-01-06 16:50:22 +01:00
2018-12-31 20:27:38 +01:00
- use [Docker image ](#run-rector-in-docker ) or
- install [prefixed version ](https://github.com/rectorphp/rector-prefixed ) with isolated dependencies (currently [looking for maintainer ](https://github.com/rectorphp/prefixer/issues/1 ))
2018-01-06 16:50:22 +01:00
2018-02-08 15:25:45 +01:00
### Extra Autoloading
2018-02-09 01:16:54 +01:00
Rector relies on project and autoloading of its classes. To specify own autoload file, use `--autoload-file` option:
2018-02-08 15:25:45 +01:00
```bash
2018-02-08 15:27:14 +01:00
vendor/bin/rector process ../project --autoload-file ../project/vendor/autoload.php
2018-02-08 15:25:45 +01:00
```
2019-02-03 18:46:45 +01:00
Or make use of `rector.yaml` config:
2018-04-13 21:14:07 +02:00
```yaml
2019-02-03 18:46:45 +01:00
# rector.yaml
2018-04-13 21:14:07 +02:00
parameters:
2018-09-26 15:03:04 +08:00
autoload_paths:
2018-11-09 14:58:49 +01:00
- 'vendor/squizlabs/php_codesniffer/autoload.php'
- 'vendor/project-without-composer'
2018-04-13 21:14:07 +02:00
```
2019-01-18 12:41:07 +01:00
## Exclude Paths and Rectors
2018-11-09 14:58:49 +01:00
You can also **exclude files or directories** (with regex or [fnmatch ](http://php.net/manual/en/function.fnmatch.php )):
2018-08-29 22:45:09 +02:00
```yaml
2019-02-03 18:46:45 +01:00
# rector.yaml
2018-08-29 22:45:09 +02:00
parameters:
exclude_paths:
- '*/src/*/Tests/*'
```
2019-01-18 12:41:07 +01:00
Do you want to use whole set, except that one rule? Exclude it:
```yaml
2019-02-03 18:46:45 +01:00
# rector.yaml
2019-01-18 12:41:07 +01:00
parameters:
exclude_rectors:
- 'Rector\CodeQuality\Rector\If_\SimplifyIfReturnBoolRector'
```
2019-02-23 14:03:07 +01:00
By default Rector uses language features of your PHP version. If you you want to use different PHP version than your system, put it in config:
```yaml
parameters:
php_version_features: '7.2' # your version 7.3
```
2018-11-09 14:58:49 +01:00
## Running Rector
2017-10-30 14:33:09 +01:00
### A. Prepared Sets
2018-11-09 14:58:49 +01:00
Featured open-source projects have **prepared sets** . You'll find them in [`/config/level` ](/config/level ) or by calling:
2017-10-30 14:33:09 +01:00
2018-11-09 14:58:49 +01:00
```bash
vendor/bin/rector levels
```
2017-12-28 17:58:35 -02:00
2018-11-09 14:58:49 +01:00
Let's say you pick `symfony40` level and you want to upgrade your `/src` directory:
2017-09-23 23:51:04 +02:00
2018-11-09 14:58:49 +01:00
```bash
2018-11-11 14:09:23 +01:00
# show known changes in Symfony 4.0
2018-11-09 14:58:49 +01:00
vendor/bin/rector process src --level symfony40 --dry-run
```
2018-08-30 10:50:03 +02:00
2018-11-09 14:58:49 +01:00
```bash
2018-11-11 14:09:23 +01:00
# apply
2018-11-09 14:58:49 +01:00
vendor/bin/rector process src --level symfony40
```
2018-08-30 10:50:03 +02:00
2017-10-30 14:33:09 +01:00
### B. Custom Sets
2017-09-27 23:58:14 +02:00
2019-02-03 18:46:45 +01:00
1. Create `rector.yaml` with desired Rectors:
2017-09-27 23:58:14 +02:00
2018-11-09 14:58:49 +01:00
```yaml
2018-03-03 21:08:25 +01:00
services:
2018-11-09 14:58:49 +01:00
Rector\Rector\Architecture\DependencyInjection\AnnotatedPropertyInjectToConstructorInjectionRector:
$annotation: "inject"
2017-12-20 02:39:06 +01:00
```
2017-09-27 23:58:14 +02:00
2018-11-09 14:58:49 +01:00
2. Run on your `/src` directory:
2017-07-15 19:20:20 +02:00
2017-12-20 02:39:06 +01:00
```bash
vendor/bin/rector process src --dry-run
2018-11-09 14:58:49 +01:00
# apply
2017-12-20 02:39:06 +01:00
vendor/bin/rector process src
```
2017-07-15 19:20:20 +02:00
2018-07-01 18:37:04 +02:00
## How to Apply Coding Standards?
2017-11-02 18:31:57 +01:00
2018-11-09 14:58:49 +01:00
AST that Rector uses doesn't deal with coding standards very well, so it's better to let coding standard tools do that. Your project doesn't have one? Rector ships with [EasyCodingStandard ](https://github.com/Symplify/EasyCodingStandard ) set that covers namespaces import, 1 empty line between class elements etc.
2017-11-02 18:31:57 +01:00
2018-11-09 14:58:49 +01:00
Just use `--with-style` option to handle these basic cases:
2017-11-18 16:19:47 +01:00
2018-07-01 18:37:04 +02:00
```bash
vendor/bin/rector process src --with-style
2017-11-02 18:31:57 +01:00
```
2019-02-07 13:52:15 +01:00
## 4 Steps to Create Own Rector
First, make sure it's not covered by [any existing Rectors yet ](/docs/AllRectorsOverview.md ).
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 New Rector
Create class that extends [`Rector\Rector\AbstractRector` ](/src/Rector/AbstractRector.php ). It has useful methods like checking node type and name. Just run `$this->` and let PHPStorm show you all possible methods.
```php
< ?php declare(strict_types=1);
namespace App\Rector;
use PhpParser\Node;
use Rector\Rector\AbstractRector;
use Rector\RectorDefinition\RectorDefinition;
final class MyFirstRector extends AbstractRector
{
public function getDefinition(): RectorDefinition
{
// what does this do?
// minimalistic before/after sample - to explain in code
}
/**
* @return string[]
*/
public function getNodeTypes(): array
{
// what node types we look for?
// String_? FuncCall? ...
// pick any node from https://github.com/nikic/PHP-Parser/tree/master/lib/PhpParser/Node
return [];
}
public function refactor(Node $node): ?Node
{
// what will happen with the node?
// common work flow:
// - should skip? → return null;
// - modify it? → do it, then return $node;
// - remove/add nodes elsewhere? → do it, then return null;
}
}
```
### 2. Implement Methods
```php
< ?php declare(strict_types=1);
namespace App\Rector;
use Nette\Utils\Strings;
use PhpParser\Node;
use PhpParser\Node\Identifier;
use PhpParser\Node\Expr\MethodCall;
use Rector\Rector\AbstractRector;
use Rector\RectorDefinition\CodeSample;
use Rector\RectorDefinition\RectorDefinition;
final class MyFirstRector extends AbstractRector
{
public function getDefinition(): RectorDefinition
{
2019-03-29 10:27:11 +01:00
return new RectorDefinition('Change method calls from set* to change*.', [
new CodeSample('$user->setPassword('123456');', '$user->changePassword('123456');')
2019-02-07 13:52:15 +01:00
]);
}
/**
* @return string[]
*/
public function getNodeTypes(): array
{
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
{
2019-03-29 10:27:11 +01:00
// we only care about "set*" method names
2019-02-07 13:52:15 +01:00
$methodCallName = $this->getName($node);
if (! Strings::startsWith($methodCallName, 'set')) {
return null;
}
$newMethodCallName = Strings::replace($methodCallName, '#^set#', 'change');
$node->name = new Identifier($newMethodCallName);
return $node;
}
}
```
### 3. Register it
```yaml
# rector.yaml
services:
App\Rector\MyFirstRector: ~
```
### 4. Let Rector Refactor Your Code
```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!
2017-12-28 17:58:35 -02:00
## More Detailed Documentation
2017-10-15 11:07:53 +02:00
2018-11-09 14:58:49 +01:00
- **[All Rectors Overview ](/docs/AllRectorsOverview.md )**
2018-01-06 16:05:19 +01:00
- [How Rector Works? ](/docs/HowItWorks.md )
2019-02-23 00:49:04 +01:00
- [Nodes Overview ](/docs/NodesOverview.md )
2017-10-15 11:07:53 +02:00
2017-12-28 17:58:35 -02:00
## How to Contribute
2017-07-15 19:20:20 +02:00
Just follow 3 rules:
- **1 feature per pull-request**
2017-08-21 12:12:51 +02:00
- **New feature needs tests**
2017-12-28 18:37:43 -02:00
- Tests, coding standards and PHPStan **checks must pass** :
2017-07-15 19:20:20 +02:00
```bash
2017-12-28 18:27:16 -02:00
composer complete-check
2017-07-15 19:20:20 +02:00
```
2017-08-21 12:12:51 +02:00
Don you need to fix coding standards? Run:
2017-07-15 19:20:20 +02:00
```bash
2017-08-21 12:12:51 +02:00
composer fix-cs
2017-07-15 19:20:20 +02:00
```
We would be happy to merge your feature then.
2018-12-12 10:02:10 +01:00
2018-12-31 20:27:38 +01:00
## Run Rector in Docker
2018-12-12 10:02:10 +01:00
With this command, you can process your project with rector from docker:
2018-12-31 20:27:38 +01:00
2018-12-12 10:02:10 +01:00
```bash
2019-03-11 16:44:39 +02:00
docker run -v $(pwd):/project rector/rector:latest process /project/src --level symfony40 --dry-run
2019-03-11 16:12:27 +02:00
# Note that a volume is mounted from `pwd` into `/project` which can be accessed later.
2018-12-11 18:22:54 +01:00
```
2019-03-11 16:27:13 +02:00
Using `rector.yaml` :
```bash
2019-03-11 16:44:39 +02:00
docker run -v $(pwd):/project rector/rector:latest process /project/app --config /project/rector.yaml --autoload-file /project/vendor/autoload.php --dry-run
2019-03-11 16:27:13 +02:00
```