driftingly/rector-laravel
Rector rules for Laravel and first-party packages like Cashier and Livewire. Automate Laravel upgrades with version-aware rule sets that detect your installed version from composer.json, plus dozens of individual rules for modernizing legacy code.
Architecture fit
driftingly/rector-laravel is a rule pack that extends Rector, a PHP AST-based refactoring engine. It is not a runtime library — it installs as a require-dev dependency and operates over source files at build/upgrade time. Architecturally this is a very clean fit for any Laravel estate:
rector.php config object that teams already use for Rector, so it composes with other Rector extensions and rules rather than introducing a parallel tool.RectorConfig::configure()->withComposerBased(laravel: true) reads composer.json and applies only the rule sets up to the installed Laravel (plus Faker, Livewire, Cashier) version. This turns "upgrade Laravel" from a bespoke migration project into a deterministic, repeatable transformation — the single strongest architectural argument for adoption.LaravelLevelSetList, LaravelSetList::LARAVEL_130, etc.) that encode the Laravel upgrade guide as executable rules. (2) Codebase modernisation — opt-in sets for code quality, collections, DI conversion, type declarations, testing. These are separable and can be sequenced, which matters for risk management.composer make:rule scaffolding plus a documented directory/namespace convention means an internal platform team can encode house rules (e.g., banned helpers, mandated JsonResponse) into the same pipeline.The main architectural caveat is that the package inherits Rector's model: it is a source-to-source rewriter with no semantic guarantee. Fit is high; trust is not implicit and must be earned through test coverage and diff review.
Integration feasibility
Feasibility is high and the effort is measured in hours, not sprints:
composer require --dev driftingly/rector-laravel (pulls in rector/rector as a peer).rector.php returning RectorConfig::configure()->withComposerBased(laravel: true) — this single line replaces the deprecated LaravelLevelSetList::UP_TO_LARAVEL_* constants and auto-selects rules.vendor/bin/rector process --dry-run first, review the diff, then vendor/bin/rector process.Constraints to validate before committing:
RectorConfig::configure()) is Rector 2.x-era. Confirm the installed Rector version matches what the package's current release targets, and pin both.app(), string container bindings, or call_user_func are the known blind spots — several rules exist precisely because those patterns are hard to reason about statically.Technical risk
Risk is concentrated in semantic drift from automated edits, not in the dependency itself. Key exposures:
| Risk | Severity | Notes |
|---|---|---|
| Behaviour-changing rules applied silently | High | e.g., MinutesToSecondsInCacheRector changes runtime cache TTL semantics; WhereToWhereLikeRector needs an explicit USING_POSTGRES_DRIVER decision; LARAVEL_STATIC_TO_INJECTION rewrites Facades to constructor injection, which can cascade through call sites. |
| Dynamic / magic code misread | Medium–High | Eloquent magic methods, container string bindings, macro-registered methods. Rules like LARAVEL_ELOQUENT_MAGIC_METHOD_TO_QUERY_BUILDER and LARAVEL_CONTAINER_STRING_TO_FULLY_QUALIFIED_NAME exist to fix this, but can also misfire on unusual code. |
| Rule interaction / ordering | Medium | Sets are layered (higher version includes lower), so the applied surface grows with target version. Conflicts surface as failed refactors or non-idempotent output. |
| Opinionated rules leaking into the default path | Medium | ResponseHelperCallToJsonResponseRector, RemoveModelPropertyFromFactoriesRector, EmptyToBlankAndFilledFuncRector are deliberately not in sets. Governance must keep them out unless a team explicitly wants the convention. |
| Maintenance/continuity of the rule pack | Medium | MIT, single prominent maintainer lineage, ~1.3k stars, and a low Packagist "dependents" signal — the ruleset's future is coupled to volunteer effort and to Laravel's own release cadence. |
| Toolchain lockstep | Low–Medium | A Rector major bump can invalidate config or rule behaviour. Pin and upgrade deliberately. |
Key questions
withComposerBased reliable in monorepos / multi-composer.json workspaces, or does each package need its own config?Stack fit
Excellent for a standard Composer-based Laravel monolith or a set of Laravel services. The package is a dev-only Composer dependency with no runtime coupling, so it slots into the existing composer.json, CI pipeline, and code review process without touching application architecture. The only prerequisite is that the repo already has (or can adopt) a test suite adequate to catch semantic drift — this tool amplifies test coverage; it does not substitute for it.
Migration path
Phased, with escalating blast radius:
rector.php with only the version set for the current Laravel version, and run --dry-run. The resulting diff tells you what the tool thinks your codebase is doing wrong. This is the cheapest possible signal.rector process --dry-run in report-only mode. No gate yet — just visibility and a stable config.laravel/framework, run Rector, review diff, ship. This is the highest-ROI use and the one with the clearest acceptance criteria (tests pass + upgrade guide items covered).LARAVEL_CODE_QUALITY, LARAVEL_COLLECTION, LARAVEL_TESTING, LARAVEL_TYPE_DECLARATIONS) scoped by directory via Rector paths. One PR per set, one reviewer, full test run.composer make:rule to encode internal conventions so the same pipeline enforces them.Compatibility
driftingly/rector-laravel and rector/rector together in composer.json; treat them as a paired version set.withComposerBased(laravel: true) over the deprecated LaravelLevelSetList::UP_TO_LARAVEL_* constants — the manual sets are slated for removal in a future major.composer.json.Sequencing
Version/upgrade sets → framework-adjacent correctness (LARAVEL_TESTING, LARAVEL_TYPE_DECLARATIONS) → ergonomics (LARAVEL_COLLECTION, LARAVEL_IF_HELPERS) → architectural rewrites (LARAVEL_STATIC_TO_INJECTION, LARAVEL_ELOQUENT_MAGIC_METHOD_TO_QUERY_BUILDER) → opinionated/configured rules on explicit request only. Never enable an architectural set in the same PR as a framework upgrade; you lose the ability to attribute a failure.
Maintenance
Low steady-state cost: bump the dev dependency on the same cadence as Rector and Laravel; verify the version sets cover the target Laravel release before starting an upgrade. The real maintenance obligation is config hygiene — a rector.php that grows without review becomes an unreviewable source of diffs. Assign a named owner (platform/DevEx) and treat the config as code.
Support
MIT-licensed, community-maintained, no commercial SLA. Support is GitHub issues plus the Rector rule-finder site. Escalation path for a broken rule is to disable it, file an issue, or write a local equivalent. Budget for the possibility of self-support on edge cases; this is not a vendor you can escalate to.
Scaling
Runtime scales with codebase size and rule count; Rector is CPU-bound and parallelisable across paths. For large codebases, shard by directory in CI and keep the dry-run job on a schedule rather than every PR if wall-clock becomes painful. Organisationally, scaling means a shared base rector.php published internally so teams don't diverge, plus a per-team opt-in for opinionated rules.
Failure modes
Ramp-up
Very fast for consumers: two commands to install and configure, one config line for version-aware operation, and the docs are good enough that a mid-level engineer can run their first upgrade pass unaided. Ramp-up is materially higher only for rule authoring (understanding Rector's node types and fixture testing) — plan a short internal enablement session if a team intends to encode house rules. Overall: adopt with confidence as a dev-only upgrade accelerator, gate it behind tests and review, and keep the opinionated rules off by default.
How can I help you explore Laravel packages today?