Skip to content

Conflict with rector/rector >=2.6.5, where set providers stopped being applied - #64

Merged
TheMilek merged 2 commits into
Sylius:mainfrom
Wojdylak:fix/conflict-rector-set-providers-removed
Sep 3, 2026
Merged

Conflict with rector/rector >=2.6.5, where set providers stopped being applied#64
TheMilek merged 2 commits into
Sylius:mainfrom
Wojdylak:fix/conflict-rector-set-providers-removed

Conversation

@Wojdylak

@Wojdylak Wojdylak commented Sep 3, 2026

Copy link
Copy Markdown
Member

What

Adds a Composer conflict so this package cannot be installed next to rector/rector >= 2.6.5:

"conflict": {
    "rector/rector": "<0.11 || >=2.6.5"
}

Why

sylius/sylius-rector v3.8.0 stopped doing anything at all on current Rector. Not a partial regression — zero rules are applied, with no error.

Rector 2.6.5 removed the machinery SyliusSetProvider depends on:

rector/rector withSetProviders() Rector\Set\SetManager Our sets
<= 2.6.4 registers the providers present applied
>= 2.6.5 trigger_error() + return $this deleted never loaded

In 2.6.5 the method became a no-op, and its signature lost the string ...$setProviders parameter, so ->withSetProviders(SyliusSetProvider::class) in config/config.php passes an argument that is silently discarded. Nothing else in Rector consumes SetProviderCollector::provideComposerTriggeredSets() any more, so every ComposerTriggeredSet we declare is dead code.

This is the upstream deprecation from rectorphp/rector-src#8296 landing as an actual removal.

Reproduction

Sylius-Standard 2.2.9, sylius/b2b-kit v3.1.2, sylius/sylius-rector v3.8.0, rector/rector 2.6.6, project rector.php with just ->withPaths([__DIR__ . '/src']):

$ vendor/bin/rector process --dry-run

Deprecated: The withSetProviders() method is deprecated and no longer applied.
Set providers are now loaded internally - use "withComposerBased()" instead.
in vendor/rector/rector/src/Configuration/RectorConfigBuilder.php on line 806

 [OK] Rector is done!

[OK] Rector is done! without a file count means no rule was ever registered.

The rules and the set files themselves are fine. Importing the same set by hand on the very same project applies it correctly:

return RectorConfig::configure()
    ->withPaths([__DIR__ . '/src'])
    ->withSets([__DIR__ . '/vendor/sylius/sylius-rector/config/sets/sylius/b2b-kit/b2b-kit-3.0.php']);
 [OK] 7 files would have been changed (dry-run) by Rector

Only the automatic set loading is broken.

Why a conflict rather than a fix here

rector/rector is not required directly by Sylius-Standard — this package is the only thing pulling it in — so Composer is free to resolve a working pair. Verified on the reproduction project:

- Downgrading rector/rector (2.6.6 => 2.6.4)

That gets users off a combination that quietly does nothing, without touching any set file.

It is a stopgap, not the destination. The proper fix is to drop SyliusSetProvider and move version gating into the set files with RectorConfig::ruleWithConfigurationComposerVersionBound(), which is the replacement Rector now uses itself — rector-symfony ships a single config/sets/symfony/composer-based.php built entirely that way. That method exists since rector/rector 2.6.0, so 2.6.0–2.6.4 is a window where both the old and the new approach work, and a follow-up release can require ^2.6 and migrate cleanly. That migration narrows our rector/rector constraint, so it does not belong in a patch release.

Boundary

Boundary established by reading src/Configuration/RectorConfigBuilder.php and src/Config/RectorConfig.php at tags 2.5.0, 2.6.0, 2.6.1, 2.6.2, 2.6.3, 2.6.4, 2.6.5 and 2.6.6:

  • withSetProviders() still functional through 2.6.4, no-op from 2.6.5
  • SetManager present through 2.6.4, absent from 2.6.5
  • ruleWithConfigurationComposerVersionBound() available from 2.6.0

Hence >=2.6.5 and not >2.6.2 — 2.6.3 and 2.6.4 are unaffected and there is no reason to exclude them.

…g applied

Rector 2.6.5 removed the set resolving machinery this package relies on:
RectorConfigBuilder::withSetProviders() became a no-op that only triggers a
deprecation, and Rector\Set\SetManager was deleted. SyliusSetProvider is
therefore never consumed, no set is loaded, and running Rector reports
"[OK] Rector is done!" without applying a single rule.

Conflicting with >=2.6.5 keeps Composer on a Rector version where the current
set provider still works, instead of installing a combination that silently
does nothing.
The package is abandoned, 11.3.2 is its last release, and its dist archive
returns 404, so "composer update" fails before anything else can run:

    Failed to download symplify/package-builder from dist: The
    ".../symplify/package-builder/zipball/4a29cf0b..." file could not be
    downloaded (HTTP/2 404)

Nothing in src, tests, ecs.php, rector.php or phpstan.neon references
Symplify\PackageBuilder, so the requirement can simply go.
@Wojdylak

Wojdylak commented Sep 3, 2026

Copy link
Copy Markdown
Member Author

CI failed on composer install, before any test could run — unrelated to this change:

Failed to download symplify/package-builder from dist: The
".../symplify/package-builder/zipball/4a29cf0b..." file could not be downloaded (HTTP/2 404)

symplify/package-builder is abandoned, 11.3.2 is its last release, its dist archive is gone, and nothing here references Symplify\PackageBuilder. Added a commit removing the requirement so the pipeline can start. The same commit is in #65, so whichever lands first the other drops it on rebase.

@TheMilek
TheMilek merged commit 18f8f52 into Sylius:main Sep 3, 2026
1 check passed
Wojdylak added a commit that referenced this pull request Sep 3, 2026
…ons (#65)

Requires `rector/rector: ^2.6`. Supersedes #64, which is the stopgap for
the current line.

## Problem

`SyliusSetProvider` no longer works. Rector 2.6.5 removed the machinery
behind it:

| `rector/rector` | `withSetProviders()` | `Rector\Set\SetManager` |
|---|---|---|
| <= 2.6.4 | registers the providers | present |
| >= 2.6.5 | `trigger_error()` + `return $this` | **deleted** |

The method also lost its `string ...$setProviders` parameter, so
`->withSetProviders(SyliusSetProvider::class)` passes an argument that
is silently discarded, and nothing consumes
`SetProviderCollector::provideComposerTriggeredSets()` any more. Every
`ComposerTriggeredSet` we declared was dead code, and
`vendor/bin/rector` applied nothing while reporting `[OK] Rector is
done!`.

## Solution

Version gating moves out of the provider and into the set files, via
`RectorConfig::ruleWithConfigurationComposerVersionBound()` — the
replacement Rector now uses for its own extensions (`rector-symfony`
ships a single `config/sets/symfony/composer-based.php` built entirely
this way).

Each rule configuration states the package and constraint it belongs to
and is skipped when the analysed project does not satisfy it:

```php
$rectorConfig->ruleWithConfigurationComposerVersionBound(AddInterfaceToClassExtendingTypeRector::class, [
    'Sylius\Bundle\CoreBundle\Doctrine\ORM\AddressRepository' => [
        'Sylius\B2BKit\Organization\Repository\AddressRepositoryInterface',
    ],
    // ...
], 'sylius/b2b-kit', '>=3.0 <4.0');
```

so the sets can be registered unconditionally in `config/config.php`:

```php
return RectorConfig::configure()
    ->withSets([
        __DIR__ . '/sets/bitbag/elasticsearch-plugin/elasticsearch-plugin.php',
        __DIR__ . '/sets/sylius/b2b-kit/b2b-kit.php',
        __DIR__ . '/sets/sylius/product-configuration-plugin/product-configuration-plugin.php',
    ])
    ->withImportNames()
    ->withComposerBased(symfony: true)
;
```

Users still add nothing to their own `rector.php` —
`rector/extension-installer` includes this file, and `withSets()` from
it is applied. Verified on a project whose `rector.php` is only
`->withPaths([__DIR__ . '/src'])`.

## Changes

- `src/SetProvider/SyliusSetProvider.php` removed
- `b2b-kit-3.0.php` + `b2b-kit-4.0.php` merged into `b2b-kit.php`
- `elasticsearch-plugin-5.2.php` renamed to `elasticsearch-plugin.php`
- `rector/rector` requirement raised to `^2.6`
(`ruleWithConfigurationComposerVersionBound()` exists since 2.6.0), and
the redundant `"rector/rector": "<0.11"` conflict dropped
- separate commit: `symplify/package-builder` removed — it is abandoned,
unused here, and its dist 404s, which makes `composer update` fail
before anything else can run

The per-major files are merged because the version now lives next to
each rule configuration. Adding support for the next plugin major
becomes a constraint edit rather than a new file plus a new provider
entry.

`config/sets/sylius/b2b-kit/b2b-kit-3.0-with-new-namespaces.php` is
untouched — it is exposed as `SyliusPlus::B2B_SUITE_UP_TO_30` and
imported by hand, not triggered by package version.

## Constraints reproduce current behaviour exactly

No project gains or loses a rule. The former `ComposerTriggeredSet` bare
versions meant `^3.0` / `^4.0` / `^5.2` / `^0.1`, and those ranges are
preserved:

| Rules | Package | Constraint | Was |
|---|---|---|---|
| entity interfaces, traits, attribute overrides, constructor calls |
`sylius/b2b-kit` | `>=3.0 <5.0` | union of the `^3.0` and `^4.0` sets |
| repository interfaces and traits | `sylius/b2b-kit` | `>=3.0 <4.0` |
`^3.0` set only — 4.0 no longer decorates the repositories |
| `AliasTraitMethodRector` | `sylius/b2b-kit` | `>=3.0 <3.0.2` |
`InstalledVersions` + `version_compare` inside the set file |
| ProductVariant interface and trait | `bitbag/elasticsearch-plugin` |
`>=5.2 <6.0` | `^5.2` set |
| Product/OrderItem interface and traits |
`sylius/product-configurator-plugin` | `>=0.1 <0.2` | `^0.1` set |

Deliberately kept the upper bounds rather than opening them to `>=X`.
Widening the effective coverage is a separate decision from changing the
mechanism, and these ranges are what is actually tested today.

`->withComposerBased(symfony: true)` is kept as-is for the same reason —
it is no longer needed for our own sets, but removing it would silently
drop the Symfony rules from every user's run.

## Verification

Sylius-Standard 2.2.9, `sylius/b2b-kit` v3.1.2,
`bitbag/elasticsearch-plugin` 5.3.0,
`sylius/product-configurator-plugin` absent, `rector/rector` 2.6.6,
project `rector.php` with just `->withPaths([__DIR__ . '/src'])`.

`vendor/bin/rector composer-based` now shows the gating directly:

```
AddInterfaceToClassExtendingTypeRector   bitbag/elasticsearch-plugin          >=5.2 <6.0     5.3.0.0   yes
AddTraitToClassExtendingTypeRector       bitbag/elasticsearch-plugin          >=5.2 <6.0     5.3.0.0   yes
AddInterfaceToClassExtendingTypeRector   sylius/b2b-kit                       >=3.0 <5.0     3.1.2.0   yes
AddAttributeOverridesToClass...Rector    sylius/b2b-kit                       >=3.0 <5.0     3.1.2.0   yes
AddTraitToClassExtendingTypeRector       sylius/b2b-kit                       >=3.0 <5.0     3.1.2.0   yes
AddMethodCallToConstructor...Rector      sylius/b2b-kit                       >=3.0 <5.0     3.1.2.0   yes
AddInterfaceToClassExtendingTypeRector   sylius/b2b-kit                       >=3.0 <4.0     3.1.2.0   yes
AddTraitToClassExtendingTypeRector       sylius/b2b-kit                       >=3.0 <4.0     3.1.2.0   yes
AliasTraitMethodRector                   sylius/b2b-kit                       >=3.0 <3.0.2   3.1.2.0   no
AddInterfaceToClassExtendingTypeRector   sylius/product-configurator-plugin   >=0.1 <0.2     -         no
AddTraitToClassExtendingTypeRector       sylius/product-configurator-plugin   >=0.1 <0.2     -         no
```

`AliasTraitMethodRector` off because 3.1.2 is past 3.0.2, the product
configurator rules off because the plugin is absent, everything else on.
`vendor/bin/rector process --dry-run`:

```
1) src/Entity/Addressing/Address.php:4
2) src/Entity/Channel/Channel.php:4
3) src/Entity/Customer/Customer.php:4
4) src/Entity/Customer/CustomerGroup.php:4
5) src/Entity/Product/ProductVariant.php:4
6) src/Entity/User/ShopUser.php:4
7) src/Entity/Order/Order.php:4
8) src/Entity/Product/Product.php:4

 [OK] 8 files would have been changed (dry-run) by Rector
```

`ProductVariant` is the Elasticsearch set, the other seven are B2B Kit —
both sets resolved from installed versions with no configuration on the
project side. On `v3.8.0` the same project produced no changes at all.

Repository checks: PHPUnit 71 tests green, PHPStan no errors, ECS clean
on every touched file.

## Note on #64

#64 adds `"rector/rector": "<0.11 || >=2.6.5"` to keep the current line
off the broken combination; this PR removes that conflict and raises the
requirement instead. Whichever lands first, the other needs a rebase on
`composer.json`.
Wojdylak added a commit that referenced this pull request Sep 3, 2026
## Why

b2b-kit 4.0 asks for a Doctrine index on the `Payment` entity alongside
the trade credit interface and trait — README step 11, entity 7:

```php
#[ORM\Entity]
#[ORM\Table(name: 'sylius_payment')]
#[ORM\Index(name: 'idx_payment_credit_approval_state', columns: ['credit_approval_state'])]
class Payment extends BasePayment implements PaymentInterface
{
    use TradeCreditPaymentTrait;
}
```

The interface and the trait are covered by existing rules. The index was
not — there was no rule for adding index mapping, so it stayed a manual
step in an otherwise automated entity decoration.

## What

`AddIndexToClassExtendingTypeRector`, modelled on
`AddAttributeOverridesToClassExtendingTypeRector`: matches classes
derived from a configured parent and appends the attribute at class
level.

```php
$rectorConfig->ruleWithConfiguration(AddIndexToClassExtendingTypeRector::class, [
    'Sylius\Component\Core\Model\Payment' => [
        new Index('idx_payment_credit_approval_state', ['credit_approval_state']),
    ],
]);
```

Added:

- `src/Rector/Class_/AddIndexToClassExtendingTypeRector.php`
- `src/Rector/Dto/Index.php` — `name` plus `columns`
- `stubs/Sylius/Component/Core/Model/Payment.php` — the stub was missing
- tests with four fixtures
- one `phpstan-baseline.neon` entry, the same `refactor()`
contravariance notice every other rule here carries

## Behaviour

Existing indexes are matched **by name**, so:

- a class that already declares the index is left alone
(`payment_already_has_index`)
- an unrelated index on the same class is preserved and the configured
one is appended (`payment_with_another_index`)
- a class not derived from the configured parent is untouched
(`unrelated_class`)

The attribute is recognised written as `Index`, `ORM\Index` or fully
qualified `Doctrine\ORM\Mapping\Index`.

The index is emitted as a separate class-level attribute rather than
folded into `#[ORM\Table(indexes: ...)]`, which is the form the b2b-kit
README shows and which leaves an existing `#[ORM\Table]` untouched.

## Not included

No set file registers the rule yet. #65 merges `b2b-kit-3.0.php` and
`b2b-kit-4.0.php` into a single `b2b-kit.php`, so wiring it in here
would collide with that PR. It is a two-line addition once one of the
two lands:

```php
$rectorConfig->ruleWithConfigurationComposerVersionBound(AddIndexToClassExtendingTypeRector::class, [
    'Sylius\Component\Core\Model\Payment' => [
        new Index('idx_payment_credit_approval_state', ['credit_approval_state']),
    ],
], 'sylius/b2b-kit', '>=4.0 <5.0');
```

The rule is self-contained and testable on its own, so it does not need
to wait for #65.

## Checks

PHPUnit 75 tests green (4 new), PHPStan no errors, ECS clean on every
added file. Run against `rector/rector` 2.6.4, the version `main`
currently resolves to after #64.

`docs/rector_rules_overview.md` is not regenerated — it already predates
`AddAttributeOverridesToClassExtendingTypeRector`, and refreshing it
here would bury this change under an unrelated diff.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants