mirror of
https://github.com/rectorphp/rector.git
synced 2024-05-31 16:30:51 +00:00
cleanup
This commit is contained in:
parent
0fa88d8f2a
commit
1c52f96f29
|
@ -1,70 +0,0 @@
|
|||
# Beyond PHP - FileProcessors
|
||||
|
||||
You think Rector is all about PHP? You might be wrong.
|
||||
Sure, the vast majority of the rules included in Rector is for PHP-Code. That´s true.
|
||||
|
||||
But since version 0.11.x Rector introduced the concept of so called FileProcessors.
|
||||
When you are running Rector with the process command all collected files from your configured paths
|
||||
are iterated through all registered FileProcessors.
|
||||
|
||||
Each FileProcessor must implement the [FileProcessorInterface](https://github.com/rectorphp/rector-src/blob/main/src/Contract/Processor/FileProcessorInterface.php) and must decide if it is able to handle a given file by
|
||||
the [supports](https://github.com/rectorphp/rector-src/blob/main/src/Contract/Processor/FileProcessorInterface.php#L11) method or not.
|
||||
|
||||
Rector itself already ships with three FileProcessors. Whereas the most important one, you guessed it, is the PhpFileProcessor.
|
||||
|
||||
But another nice one is the ComposerFileProcessor. The ComposerFileProcessor lets you manipulate composer.json files in your project.
|
||||
Let´s say you want to define a custom configuration where you want to update the version constraint of some packages.
|
||||
All you have to do is using the ChangePackageVersionComposerRector:
|
||||
|
||||
```php
|
||||
use Rector\Composer\Rector\ChangePackageVersionComposerRector;
|
||||
use Rector\Composer\ValueObject\PackageAndVersion;
|
||||
use Rector\Config\RectorConfig;
|
||||
|
||||
return static function (RectorConfig $rectorConfig): void {
|
||||
$rectorConfig->ruleWithConfiguration(ChangePackageVersionComposerRector::class, [
|
||||
new PackageAndVersion('symfony/yaml', '^5.0'),
|
||||
]);
|
||||
};
|
||||
```
|
||||
|
||||
There are some more rules related to manipulate your composer.json files. Let´s see them in action:
|
||||
|
||||
```php
|
||||
use Rector\Composer\Rector\AddPackageToRequireComposerRector;
|
||||
use Rector\Composer\Rector\AddPackageToRequireDevComposerRector;
|
||||
use Rector\Composer\Rector\RemovePackageComposerRector;
|
||||
use Rector\Composer\Rector\ReplacePackageAndVersionComposerRector;
|
||||
use Rector\Composer\ValueObject\PackageAndVersion;
|
||||
use Rector\Composer\ValueObject\ReplacePackageAndVersion;
|
||||
use Rector\Config\RectorConfig;
|
||||
|
||||
return static function (RectorConfig $rectorConfig): void {
|
||||
// Add a package to the require section of your composer.json
|
||||
$rectorConfig->ruleWithConfiguration(AddPackageToRequireComposerRector::class, [
|
||||
new PackageAndVersion('symfony/yaml', '^5.0'),
|
||||
]);
|
||||
|
||||
// Add a package to the require dev section of your composer.json
|
||||
$rectorConfig->ruleWithConfiguration(AddPackageToRequireDevComposerRector::class, [
|
||||
new PackageAndVersion('phpunit/phpunit', '^9.0'),
|
||||
]);
|
||||
|
||||
// Remove a package from composer.json
|
||||
$rectorConfig->ruleWithConfiguration(RemovePackageComposerRector::class, [
|
||||
'symfony/console'
|
||||
]);
|
||||
|
||||
// Replace a package in the composer.json
|
||||
$rectorConfig->ruleWithConfiguration(ReplacePackageAndVersionComposerRector::class, [
|
||||
new ReplacePackageAndVersion('vendor1/package2', 'vendor2/package1', '^3.0'),
|
||||
]);
|
||||
};
|
||||
```
|
||||
|
||||
Behind every FileProcessor are one or multiple rules which are in turn implementing a dedicated Interface extending the [RectorInterface](https://github.com/rectorphp/rector-src/blob/main/src/Contract/Rector/RectorInterface.php).
|
||||
In the case of the ComposerFileProcessor all rules are implementing the [ComposerRectorInterface](https://github.com/rectorphp/rector-src/blob/main/rules/Composer/Contract/Rector/ComposerRectorInterface.php)
|
||||
|
||||
Are you eager to create your own one? Dive in and have a look at [How to create a custom FileProcessor](how_to_create_custom_fileprocessor.md)
|
||||
|
||||
|
|
@ -1,202 +0,0 @@
|
|||
# Create your own custom FileProcessor
|
||||
|
||||
This section is all about creating your custom specific FileProcessor.
|
||||
If you don´t know the concept of FileProcessors in the context of Rector, have a look at [Beyond PHP - Entering the realm of FileProcessors](beyond_php_file_processors.md)
|
||||
|
||||
Most of the examples starting with a rather contrived example, let´s do it the same.
|
||||
|
||||
Imagine you would like to replace the sentence "Make america great again" to "Make the whole world a better place to be" in every file named bold_statement.txt.
|
||||
|
||||
In order to do so, we create the BoldStatementFileProcessor like that:
|
||||
|
||||
```php
|
||||
<?php
|
||||
namespace MyVendor\MyPackage\FileProcessor;
|
||||
|
||||
use Rector\Core\Contract\Processor\FileProcessorInterface;
|
||||
use Rector\Core\ValueObject\Application\File;
|
||||
|
||||
final class BoldStatementFileProcessor implements FileProcessorInterface
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private const OLD_STATEMENT = 'Make america great again';
|
||||
|
||||
public function supports(File $file): bool
|
||||
{
|
||||
$smartFileInfo = $file->getSmartFileInfo();
|
||||
return 'bold_statement.txt' === $smartFileInfo->getBasename();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param File[] $files
|
||||
*/
|
||||
public function process(array $files): void
|
||||
{
|
||||
foreach ($files as $file) {
|
||||
$this->processFile($file);
|
||||
}
|
||||
}
|
||||
|
||||
private function processFile(File $file): void
|
||||
{
|
||||
$oldContent = $file->getFileContent();
|
||||
|
||||
if(false === strpos($oldContent, self::OLD_STATEMENT)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$newFileContent = str_replace(self::OLD_STATEMENT, 'Make the whole world a better place to be', $oldContent);
|
||||
$file->changeFileContent($newFileContent);
|
||||
}
|
||||
|
||||
public function getSupportedFileExtensions(): array
|
||||
{
|
||||
return ['txt'];
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Now register your FileProcessor in your configuration (actually in the container):
|
||||
|
||||
```php
|
||||
use MyVendor\MyPackage\FileProcessor\BoldStatementFileProcessor;
|
||||
use Rector\Config\RectorConfig
|
||||
|
||||
return static function (RectorConfig $rectorConfig): void {
|
||||
// [...]
|
||||
$services = $rectorConfig->services();
|
||||
$services->set(BoldStatementFileProcessor::class);
|
||||
};
|
||||
```
|
||||
|
||||
Run rector again and see what happens. Yes, we made the world better.
|
||||
|
||||
The astute reader has noticed, that the BoldStatementFileProcessor is not really reusable and easily extendable.
|
||||
So it would be much better to separate the processing from the actual rule(s).
|
||||
This is also the best practice in all Rector internal FileProcessors. So, let´s just do that.
|
||||
|
||||
Create a new dedicated Interface for our rules used by the BoldStatementFileProcessor. Just call it BoldStatementRectorInterface.
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
namespace MyVendor\MyPackage\FileProcessor\Rector;
|
||||
|
||||
use Rector\Core\Contract\Rector\RectorInterface;
|
||||
|
||||
interface BoldStatementRectorInterface extends RectorInterface
|
||||
{
|
||||
public function transform(string $content): string;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Now, separate the modification from the processing:
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
namespace MyVendor\MyPackage\FileProcessor\Rector;
|
||||
use Rector\Core\ValueObject\Application\File;
|
||||
|
||||
final class BoldStatementMakeAmericaGreatAgainRector implements BoldStatementRectorInterface
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private const OLD_STATEMENT = 'Make america great again';
|
||||
|
||||
public function transform(string $content): string
|
||||
{
|
||||
if(false === strpos($content, self::OLD_STATEMENT)) {
|
||||
return;
|
||||
}
|
||||
|
||||
return str_replace(self::OLD_STATEMENT, 'Make the whole world a better place to be', $content);
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
And change our BoldStatementFileProcessor so it is using one or multiple classes implementing the BoldStatementRectorInterface:
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
namespace MyVendor\MyPackage\FileProcessor;
|
||||
|
||||
use Rector\Core\Contract\Processor\FileProcessorInterface;
|
||||
use Rector\Core\ValueObject\Application\File;
|
||||
use MyVendor\MyPackage\FileProcessor\Rector\BoldStatementRectorInterface;
|
||||
|
||||
final class BoldStatementFileProcessor implements FileProcessorInterface
|
||||
{
|
||||
/**
|
||||
* @var BoldStatementRectorInterface[]
|
||||
*/
|
||||
private $boldStatementRectors;
|
||||
|
||||
/**
|
||||
* @param BoldStatementRectorInterface[] $boldStatementRectors
|
||||
*/
|
||||
public function __construct(array $boldStatementRectors)
|
||||
{
|
||||
$this->boldStatementRectors = $boldStatementRectors;
|
||||
}
|
||||
|
||||
public function supports(File $file): bool
|
||||
{
|
||||
$smartFileInfo = $file->getSmartFileInfo();
|
||||
return 'bold_statement.txt' === $smartFileInfo->getBasename();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param File[] $files
|
||||
*/
|
||||
public function process(array $files): void
|
||||
{
|
||||
foreach ($files as $file) {
|
||||
$this->processFile($file);
|
||||
}
|
||||
}
|
||||
|
||||
private function processFile(File $file): void
|
||||
{
|
||||
foreach ($this->boldStatementRectors as $boldStatementRector) {
|
||||
$changeFileContent = $boldStatementRector->transform($file->getFileContent());
|
||||
$file->changeFileContent($changeFileContent);
|
||||
}
|
||||
}
|
||||
|
||||
public function getSupportedFileExtensions(): array
|
||||
{
|
||||
return ['txt'];
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Notice the annotation BoldStatementRectorInterface[]. This is important to inject all active classes implementing the BoldStatementRectorInterface into the BoldStatementFileProcessor.
|
||||
Yes, we said active. So last but not least we must register our new rule in the container, so it is applied:
|
||||
|
||||
```php
|
||||
use MyVendor\MyPackage\FileProcessor\BoldStatementFileProcessor;
|
||||
use MyVendor\MyPackage\FileProcessor\Rector\BoldStatementMakeAmericaGreatAgainRector;
|
||||
use Rector\Config\RectorConfig;
|
||||
|
||||
return static function (RectorConfig $rectorConfig): void {
|
||||
// [...]
|
||||
$services = $rectorConfig->services();
|
||||
$services->set(BoldStatementFileProcessor::class);
|
||||
|
||||
$rectorConfig->rule(BoldStatementMakeAmericaGreatAgainRector::class);
|
||||
};
|
||||
```
|
||||
|
||||
Run rector again and yes, we made the world a better place again.
|
||||
|
||||
Puh. This was a long ride. But we are done and have our new shiny BoldStatementFileProcessor in place.
|
||||
Now, it´s up to you, to create something useful. But always keep in mind: Try to make the world a better place to be.
|
Loading…
Reference in New Issue
Block a user