driftingly/rector-laravel
Rector extension for Laravel that applies automated refactors and upgrade rules based on your composer.json or selected Laravel version sets. Includes rules for core Laravel and first‑party packages like Cashier and Livewire.
Installation:
composer require --dev driftingly/rector-laravel
Add the package as a dev dependency to avoid bloating production builds.
Basic Configuration:
Create or update rector.php in your project root with:
<?php declare(strict_types=1);
use Rector\Config\RectorConfig;
use RectorLaravel\Set\LaravelSetProvider;
return RectorConfig::configure()
->withSetProviders(LaravelSetProvider::class)
->withComposerBased(laravel: true);
This auto-detects your Laravel version from composer.json and applies version-specific rules.
First Run:
vendor/bin/rector process src
Process your src directory (adjust paths as needed). Use --dry-run first to preview changes.
Upgrade from Laravel 11 to 12:
composer require --dev driftingly/rector-laravel
Configure rector.php as above, then run:
vendor/bin/rector process src --level=UP_TO_LARAVEL_120
This applies all rules needed for the upgrade, including:
Cache:: → Cache::class).Version-Specific Upgrades:
Use LaravelLevelSetList constants for targeted upgrades:
->withSets([
LaravelLevelSetList::LARAVEL_130, // Rules for 12→13
LaravelLevelSetList::LARAVEL_140, // Rules for 13→14
])
Higher versions include lower-version rules automatically.
Code Quality Improvements: Combine sets for incremental refactoring:
->withSets([
LaravelSetList::LARAVEL_CODE_QUALITY, // Replaces `$this->app['...']`
LaravelSetList::LARAVEL_COLLECTION, // Modernizes collection methods
LaravelSetList::LARAVEL_TYPE_DECLARATIONS, // Adds type hints
])
Testing Integration:
Use LaravelSetList::LARAVEL_TESTING to modernize tests:
->withSets([
LaravelSetList::LARAVEL_TESTING,
])
Example transformations:
assertViewHas() → assertViewHasAll().assertDatabaseHas() → modern assertions.CI/CD Pipeline: Add a GitHub Action or GitLab CI step:
# .github/workflows/rector.yml
- name: Run Rector
run: vendor/bin/rector process src --dry-run
Use --dry-run to fail builds on changes without committing them.
->withPaths([
__DIR__ . '/src',
])
->withExcludedPaths([
__DIR__ . '/tests/Feature/OldCode.php',
]);
vendor/bin/rector process src --parallel
->withSets([
Rector\Set\PHP80,
LaravelSetList::LARAVEL_STATIC_TO_INJECTION,
]);
False Positives in UP_TO_LARAVEL_X Sets:
UP_TO_LARAVEL_130 may not apply if your codebase already uses Laravel 13 patterns.--dry-run to preview changes and manually review.Facade-to-DI Conflicts:
LARAVEL_STATIC_TO_INJECTION may break code relying on facades in constructors.->withSets([
LaravelSetList::LARAVEL_STATIC_TO_INJECTION,
])
->withExcludedNodes([
new PhpDocNode('*@inject*'),
]);
Collection Method Ambiguity:
LARAVEL_COLLECTION rules may conflict with custom collection macros.--dry-run and exclude ambiguous methods:
->withExcludedNodes([
new MethodCallNode('Illuminate\Support\Collection', 'customMacro'),
]);
Database Schema Changes:
WhereToWhereLikeRector may alter query logic if not tested.Legacy Factory Conflicts:
LARAVEL_LEGACY_FACTORIES_TO_CLASSES may fail if factories use dynamic properties.->withExcludedPaths([
__DIR__ . '/database/factories/OldFactory.php',
]);
Verbose Output:
vendor/bin/rector process src --verbose
Shows detailed rule application logs.
Rule-Specific Debugging:
Use --only to test individual rules:
vendor/bin/rector process src --only LaravelSetList::LARAVEL_ELOQUENT_MAGIC_METHOD_TO_QUERY_BUILDER
Git Diff Analysis: After a dry run, inspect changes with:
git diff --name-only
Revert unwanted changes with:
git checkout -- .
Composer-Based Detection:
composer.json accurately reflects your Laravel version.->withComposerBased(laravel: '12.*')
Rule Order Matters:
LARAVEL_ARRAYACCESS_TO_METHOD_CALL before LARAVEL_CONTAINER_STRING_TO_FULLY_QUALIFIED_NAME).->withRules([
\RectorLaravel\Rector\MethodCall\ArrayAccessToMethodCallRector::class,
\RectorLaravel\Rector\MethodCall\ContainerStringToFqnRector::class,
]);
IDE Support:
vendor/bin/phpstan generate-baseline
Custom Rules: Generate a new rule with:
composer make:rule -- MyCustomRule
Example: Convert Str::of($var)->upper() to Str::upper($var):
// src/Rector/StaticCall/MyCustomRuleRector.php
public function refactor(StaticCall $staticCall): ?StaticCall
{
if ($staticCall->getName() === 'of' && $staticCall->getParent() instanceof StaticCall) {
$parent = $staticCall->getParent();
if ($parent->getName() === 'upper' && $parent->getClass() instanceof StaticNode) {
$parent->setArguments([$staticCall->getArguments()[0]]);
return $parent;
}
}
return null;
}
Conditional Rule Application:
Use Rector\Contract\Rector\ConfigurableRectorInterface for dynamic rules:
public function getConfiguration(): array
{
return [
'only_if' => fn(Node $node) => $node instanceof ClassMethod && str_contains($node->getName(), 'test'),
];
}
Pre/Post-Processing:
Hook into Rector’s lifecycle with Rector\Contract\Rector\RectorInterface:
public function refactor(Node $node): ?Node
{
if ($node instanceof Class_) {
$this->logger->info('Processing class: ' . $node->getName());
}
return null;
}
Testing Rules: Use Rector’s testing utilities:
// tests/Rector/MyCustomRuleRectorTest.php
public function provideTestCases(): iterable
{
yield 'converts Str::of()->upper()' => [
<<<'PHP'
use Illuminate\Support\Str;
Str::of('test')->upper();
PHP,
<<<'PHP'
use Illuminate\Support\Str;
Str
How can I help you explore Laravel packages today?