Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Shopware Rector Laravel Package

frosh/shopware-rector

Frosh Shopware Rector provides Rector rules to automate upgrading Shopware 6 extensions and themes to newer versions. It helps modernize plugin code, apply API changes, and reduce manual migration work so your Shopware projects stay compatible with less effort.

View on GitHub
Deep Wiki
Context7

Getting Started

Add it as a dev dependency next to Rector itself — it is a ruleset, not a standalone tool, so nothing happens until Rector runs it:

composer require --dev rector/rector frosh/shopware-rector

Since 0.6.0 the package requires PHP 8.2+ (and is validated against Rector 2.6.2). Your runtime PHP can still be 8.1 — Shopware 6.4/6.5 projects do this — but the machine that runs Rector (local dev, CI job) needs 8.2. If composer require resolves an ancient 0.5.x, that's the reason; upgrade the toolchain or run Rector in a dedicated 8.2 CI job (see Gotchas about PHP_82 sets in that case).

Then look at two things in the repo before writing any config:

  1. config/ (or sets/) in vendor/frosh/shopware-rector — the per-Shopware-version set files. These are the actual product; the PHP classes under src/Rector/ are just their implementation. ls vendor/frosh/shopware-rector/config is your first command.
  2. The README table that maps a set to a Shopware minor (6.4 → 6.5 → 6.6 …). Rules are version-scoped, so the set you pick is your upgrade target.

A minimal rector.php at project root:

<?php
use Rector\Config\RectorConfig;
use Rector\Set\ValueObject\SetList;

return RectorConfig::configure()
    ->withPaths([
        __DIR__ . '/custom/plugins/Acme/src',
        __DIR__ . '/custom/static-plugins/AcmeErp/src',
    ])
    ->withSkip([
        __DIR__ . '/custom/plugins/*/vendor',
        __DIR__ . '/custom/plugins/*/tests/Fixtures',
    ])
    ->withSets([
        SetList::PHP_82,
        SetList::TYPE_DECLARATION,
        // Shopware rules: point at the set file for your target version
        __DIR__ . '/vendor/frosh/shopware-rector/config/shopware-66.php',
    ]);

First use case: pick one plugin, run vendor/bin/rector process --dry-run and read the diff. Do not start with process on the whole custom/ tree — you want to learn what the rules actually rewrite before committing to a 300-file changeset.

Implementation Patterns

Version-ladder upgrades. Run the sets in sequence, one Shopware minor per commit: 6.4 → 6.5, test, commit, then 6.5 → 6.6. Squashing them into one run hides which rule caused a break, and a broken intermediate state is much easier to bisect than a 2 000-line diff.

Run Rector before bumping composer.json. The rewritten code is (usually) still valid against the old platform for the APIs the rules touch, so you get an isolated, reviewable refactor commit and a separate dependency-upgrade commit. If instead you bump first, composer update failures and Rector diffs get tangled.

Scope by directory, not by rule. Shopware codebases split cleanly into Domain/, Storefront/, Administration/, Migration/. vendor/bin/rector process custom/plugins/Acme/src/Domain gives reviewable PRs and keeps the cache warm for the rest.

# per-plugin loop, one PR each
for p in custom/plugins/*/; do
  vendor/bin/rector process "$p/src" --dry-run --output-format=json > "rector-$(basename $p).json"
done

CI as a ratchet, not a gate. Two jobs: a non-blocking --dry-run report on PRs (post the JSON as an artifact) and a blocking check only on changed files, so legacy files can't get worse while new code stays clean. Combine with PHPStan (frosh/phpstan-rules) and shopware-cli for build/validate — Rector fixes shape, PHPStan catches the semantics Rector can't see.

Custom rules on top. The real leverage for a big codebase is writing your own AbstractRector subclasses for in-house patterns (e.g. banning $container->get(...) in favour of constructor injection, or normalising your own event-subscriber signatures) and registering them in the same config. You inherit Rector's AST tooling and file handling for free. Note that 0.6.0 removed the rule scaffold/devenv helper script from the package — scaffold by copying an existing rule from src/Rector/ instead of expecting a generator.

Pair with a diff-only workflow. --dry-run plus git diff review is the whole quality gate. Treat Rector's output as a very fast junior developer: excellent at mechanical renames, unreliable on anything that depends on runtime container wiring.

Gotchas and Tips

  • It only reads PHP. Shopware's services.xml, config.xml, routes.xml, DI service ids, shopware.yaml, and Twig templates are invisible to Rector. Class renames that also appear as strings in XML or in getSubscribedEvents() arrays will be half-migrated. Grep for old FQCNs as strings after every run: grep -rn 'Old\\ClassName' --include='*.xml' --include='*.yaml'.
  • String class references are a blind spot. 'Acme\Subscriber\Foo' inside an event array, EntityRepository names in Migration code, and services.xml aliases survive untouched. Rector matches nodes, not stringly-typed config.
  • PHP 8.2 and Rector 2.6.2 are the supported floor as of 0.6.0. Bumping the package on a PHP 8.1 runner fails at install time, not at runtime — a confusing error if you only read the "Rector" part. Also, if you run Rector on a PHP 8.2 CI job against a PHP 8.1 production target, drop SetList::PHP_82 (or use PHP_81) so you don't introduce syntax your runtime can't parse.
  • Stay on Rector 2.x, and pin it. 0.6.0 explicitly restores Rector 2.6.2 compatibility; older 0.5.x releases were written against earlier 2.x internals. Pin rector/rector and frosh/shopware-rector in composer.json so a major bump of either doesn't break your rector.php mid-upgrade (RectorConfig::configure() vs the legacy ContainerConfigurator bootstrap remains the most common copy-paste failure).
  • Expect new rules to land in existing set files. 0.6.0 added a migration for deprecated CartBehavior recalculation checks ($cart->getBehavior()->isRecalculation(), etc.). Nothing in your config changes, but the output of a set you already validated does — after every package bump, re-run --dry-run on a plugin you've already migrated and check which set file the new rule lives in (git log -- vendor/frosh/shopware-rector/config). Silent behaviour changes in a set are the main reason to pin and re-read the changelog.
  • Silent no-ops are usually the cache. If a rule clearly should have fired and didn't, run --clear-cache (and check tmp/rector / your configured cache dir). Also confirm the set file path resolves — a wrong path in withSets() throws, but a missing rule inside a set is silently skipped.
  • Exclude vendor everywhere, including nested custom/plugins/*/vendor. Rector happily rewrites dependencies and you lose the ability to composer update cleanly.
  • Don't run Rector and ECS in the same pipeline step. Both rewrite files; ordering determines the diff. Convention: Rector first (structural), then ecs --fix (style), then commit. (The package itself moved to a newer php-cs-fixer in 0.6.0 — if you vendor its config patterns, expect style-only churn.)
  • Order-of-operations inside one run matters. Rule sets are applied in passes; a TYPE_DECLARATION set plus a Shopware set can interact badly (added return types on methods a later rule replaces). If output looks wrong, drop to --only on a single rule to isolate.
  • Memory and time on large plugins. Use --parallel and raise memory_limit; long runs on custom/ are much cheaper after excluding var/, vendor/, and tests fixtures.
  • Review every --dry-run diff that touches constructor signatures or service decoration. Those changes compile fine and fail at container build time, which is exactly where Rector's static view stops and Shopware's runtime starts. The CartBehavior rule is a good example: the API call rewrite is mechanical, but the surrounding recalculation logic is business logic — verify the cart still recalculates as expected in the storefront, not just in a unit test.
  • Escape hatch: withSkip() by rule class for a specific file when a rule is wrong for your case, rather than excluding the file entirely — you keep the other 20 rules working on it.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
cgv/localized-resource