Rector - instant upgrades and automated refactoring
The Rector project describes the tool as follows:
Rector instantly upgrades and refactors the PHP code of your application.
Every Drupal major release removes the APIs that the previous major release
deprecated. Rector rewrites your code to replace them and moves it onto
PHP 8.4 language features. It applies each refactoring across the whole
codebase at once. Because Rector runs in every ahoy lint-be run and every
CI build, the deprecations Drupal Rector covers are already fixed when a
major upgrade starts.
Vortex comes with a pre-configured Rector configuration for Drupal projects, based on the configuration provided by Drupal Rector.
This page is for developers who keep custom code current with Drupal and PHP. It shows how to run Rector and clear its cache, which rule sets Vortex enables and how to skip a rule or a file.
Vortex runs Rector as a regular code quality check:
ahoy lint-bereports the code Rector would change.ahoy lint-be-fixapplies the changes.- The
lintjob in CI fails while any change is pending.
Run ahoy lint-be-fix before a Drupal major upgrade to clear the remaining
deprecations, and when you modernize legacy code in bulk.
Usage
Check for violations
Both commands run Rector as a dry run. The Ahoy command runs it last, after PHPCS and PHPStan. The Docker Compose command runs Rector alone. To check for code that Rector would change, run 1 of the following commands:
- Ahoy
- Docker Compose
ahoy lint-be
docker compose exec cli vendor/bin/rector --dry-run
Confirm that Rector found nothing to change: the output ends with
[OK] Rector is done!. When Rector would change files, it prints a diff
for each file and exits with code 2, which fails the check.
Fix violations
To apply the changes, run 1 of the following commands:
- Ahoy
- Docker Compose
# Fix all back-end lint issues (Rector, then PHPCBF).
ahoy lint-be-fix
docker compose exec cli vendor/bin/rector process
Cache management
Rector caches parsed files and analysis results in the system temp
directory, /tmp/rector_cached_files inside the CLI container, so later
runs reuse the results for files that haven't changed.
Clear the cache in any of the following cases:
- After you change the
rector.phpconfiguration, such as its rules, skip list or paths - After you update the
rector/rectororpalantirnet/drupal-rectorpackages - After you switch to a Git branch with a different Rector configuration
- Whenever the results look stale
To clear the cache and check for violations, run 1 of the following commands:
- Ahoy
- Docker Compose
ahoy cli vendor/bin/rector process --clear-cache --dry-run
docker compose exec cli vendor/bin/rector process \
--clear-cache --dry-run
To clear the cache and apply changes, run 1 of the following commands:
- Ahoy
- Docker Compose
ahoy cli vendor/bin/rector process --clear-cache
docker compose exec cli vendor/bin/rector process --clear-cache
Configuration
See the Rector documentation.
All global configuration lives in the
rector.php file.
Rector processes the following paths, which withPaths() in rector.php
lists:
web/modules/customweb/themes/customweb/sites/default/settings.phpweb/sites/default/includestests
withPaths() leaves out scripts, which PHPCS and PHPStan check.
Config sets
Rector provides config sets that each turn on a group of related rules. Vortex enables the following sets:
- The PHP sets up to the lowest PHP version that the
require.phpconstraint incomposer.jsonallows, throughwithPhpSets(), which reads that constraint when called without an argument. The shipped constraint,>=8.4, resolves to PHP 8.4. The sets followcomposer.json, so a PHP version change needs no edit torector.php. - The Drupal sets from Drupal
Rector, turned on by
withSetProviders()andwithComposerBased()and resolved from the installeddrupal/coreversion, so the rules track core upgrades. - The
codeQuality,codingStyle,deadCode,naming,privatizationandtypeDeclarationsprepared sets. - The Behat attribute sets, which convert Behat annotations to PHP 8 attributes. They ship only when Behat is selected during installation.
On top of the sets, rector.php adds the DeclareStrictTypesRector rule
and, when PHPUnit is selected, YieldDataProviderRector, which turns
array-returning data providers into generators. withImportNames() is
called with importNames: FALSE, so Rector adds no use statements to the
files it changes.
To adjust the sets, edit the withPhpSets(), withAttributesSets() and
withPreparedSets() calls in rector.php. The Set
Lists page describes the
available sets, and the Find a Rector
rule page lists the
individual rules.
Ignore violations
For every way to skip a rule or a path, see the Rector configuration documentation.
To skip a rule across the project, add it to withSkip() in the
rector.php file:
->withSkip([
SimplifyIfReturnBoolRector::class,
])
The shipped withSkip() list already skips the following 20 rules
everywhere, based on the project's coding standards:
AddOverrideAttributeToOverriddenMethodsRectorArrayToFirstClassCallableRectorCatchExceptionNameMatchingTypeRectorChangeSwitchToMatchRectorCompleteDynamicPropertiesRectorDisallowedEmptyRuleFixerRectorInlineArrayReturnAssignRectorNewlineAfterStatementRectorNewlineBeforeNewAssignSetRectorNewlineBetweenClassLikeStmtsRectorPrivatizeFinalClassMethodRectorPrivatizeFinalClassPropertyRectorPrivatizeLocalGetterToPropertyRectorRemoveAlwaysTrueIfConditionRectorRenameForeachValueVariableToMatchExprVariableRectorRenameForeachValueVariableToMatchMethodCallReturnTypeRectorRenameParamToMatchTypeRectorRenameVariableToMatchMethodCallReturnTypeRectorRenameVariableToMatchNewTypeRectorSimplifyEmptyCheckOnEmptyArrayRector
The list skips RemoveUnusedPublicMethodParameterRector for the src/Hook
classes of custom modules and themes, and
StringClassNameToClassConstantRector for the settings includes. The list
also skips the vendor and node_modules directories.
To skip all Rector rules for a file, add its path to withSkip():
->withSkip([
'file.php',
'*/other_file.php',
])
To skip a specific rule for a file, map the rule to the file's path in
withSkip():
->withSkip([
SimplifyIfReturnBoolRector::class => ['file.php'],
])
Rector doesn't support ignoring code blocks.
Continuous integration
Rector runs in the lint job of the continuous integration
pipeline and fails the build on
violations.
Ignore failures
To let the build pass anyway, set the VORTEX_CI_RECTOR_IGNORE_FAILURE CI
variable to 1. Rector still runs and prints the changes it would make in
the job log, so you can see what you're letting through.