Skip to main content
Version: v2

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 one deprecated. Rector rewrites your code to replace them, moves it onto PHP 8.4 language features, and applies the same refactorings across the whole codebase at once. Keep it running, and a major upgrade starts with the deprecations that Drupal Rector covers already fixed.

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.

Many projects run Rector ad hoc, for a single round of bulk refactoring. Vortex runs it as a regular code quality check instead: ahoy lint-be reports the code Rector would change, ahoy lint-be-fix applies the changes, and the lint job in CI fails while any change is pending. Run it by hand before a Drupal major upgrade to clear the remaining deprecations, and when you refactor legacy code to modernize it in bulk.

Usage​

Check for violations​

ahoy lint-be runs Rector last, after PHPCS and PHPStan, while the Docker Compose command runs Rector alone. To check for code that Rector would change, run 1 of the following commands:

ahoy lint-be

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:

# Fix all back-end lint issues (Rector, then PHPCBF).
ahoy lint-be-fix

Cache management​

Rector caches parsed file information 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.php configuration, such as its rules, skip list, or paths
  • After you update the rector/rector or palantirnet/drupal-rector packages
  • 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 cli vendor/bin/rector process --clear-cache --dry-run

To clear the cache and apply changes, run 1 of the following commands:

ahoy 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/custom
  • web/themes/custom
  • web/sites/default/settings.php
  • web/sites/default/includes
  • tests

Unlike PHPCS and PHPStan, Rector leaves the scripts directory alone.

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.php constraint in composer.json allows, through withPhpSets() called without an argument. The shipped constraint, >=8.4, resolves to PHP 8.4. The sets follow composer.json, so rector.php needs no change when you move to a new PHP version.
  • The Drupal sets from Drupal Rector, resolved from the installed drupal/core version, so the rules track core upgrades without changes to rector.php.
  • The codeQuality, codingStyle, deadCode, naming, privatization, and typeDeclarations prepared 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, it adds the DeclareStrictTypesRector rule and, when PHPUnit is selected, YieldDataProviderRector, which turns array-returning data providers into generators. It also leaves class names unimported, so Rector doesn't add 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.

Ignoring​

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 22 rules everywhere, based on the project's coding standards:

  • AddOverrideAttributeToOverriddenMethodsRector
  • ArrayToFirstClassCallableRector
  • CatchExceptionNameMatchingTypeRector
  • ChangeSwitchToMatchRector
  • CompleteDynamicPropertiesRector
  • DisallowedEmptyRuleFixerRector
  • InlineArrayReturnAssignRector
  • NewlineAfterStatementRector
  • NewlineBeforeNewAssignSetRector
  • NewlineBetweenClassLikeStmtsRector
  • PrivatizeFinalClassConstantRector
  • PrivatizeFinalClassMethodRector
  • PrivatizeFinalClassPropertyRector
  • PrivatizeLocalGetterToPropertyRector
  • RemoveAlwaysTrueIfConditionRector
  • RenameForeachValueVariableToMatchExprVariableRector
  • RenameForeachValueVariableToMatchMethodCallReturnTypeRector
  • RenameParamToMatchTypeRector
  • RenamePropertyToMatchTypeRector
  • RenameVariableToMatchMethodCallReturnTypeRector
  • RenameVariableToMatchNewTypeRector
  • SimplifyEmptyCheckOnEmptyArrayRector

It also skips StringClassNameToClassConstantRector for the settings includes, and 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.

Ignoring 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.

➡️ See Continuous integration > Ignore tool failures