Skip to content

Add AddIndexToClassExtendingTypeRector - #66

Merged
Wojdylak merged 3 commits into
Sylius:mainfrom
Wojdylak:feature/add-index-to-class-extending-type-rector
Sep 3, 2026
Merged

Wojdylak merged 3 commits into
Sylius:mainfrom
Wojdylak:feature/add-index-to-class-extending-type-rector

Conversation

@Wojdylak

@Wojdylak Wojdylak commented Sep 3, 2026

Copy link
Copy Markdown
Member

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:

#[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.

$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:

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

b2b-kit 4.0 asks for a Doctrine index on the Payment entity next to the
trade credit interface and trait (README step 11, entity 7):

    #[ORM\Index(name: 'idx_payment_credit_approval_state', columns: ['credit_approval_state'])]

There was no rule for adding index mapping, so that part of the entity
decoration could not be automated. The rule mirrors
AddAttributeOverridesToClassExtendingTypeRector: it matches classes derived
from a configured parent and appends the attribute at class level.

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

Existing indexes are matched by name, so a class that already declares the
index is left alone while other indexes on the same class are preserved.
Recognises the attribute written as Index, ORM\Index or the fully qualified
Doctrine\ORM\Mapping\Index.
Doctrine\ORM\Mapping\Index takes $name as its first constructor parameter, so
#[ORM\Index('idx_name', ['column'])] is as valid as the named form. The name
lookup only read a "name:" argument, so a positionally spelled index went
unrecognised and a duplicate was appended.

The lookup now falls back to the first positional argument, with a fixture
covering that spelling.
Now that Sylius#65 is merged there is a single b2b-kit.php to register the rule in,
next to the trade credit interface and trait it belongs with:

    $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 itself is generic, so its documentation and fixtures no longer use
the B2B Kit case that motivated it. The code sample and the tests work on
plain Sylius entities - an index on Order::number and two indexes on
ProductVariant - which also covers registering several indexes for one class,
something the single b2b-kit configuration did not exercise.

Fixtures:

- order_entity: adds the configured index
- product_variant_with_two_indexes: adds both configured indexes
- order_already_has_index: the index is already there, no change
- order_has_index_with_positional_name: the same, spelled positionally
- order_with_another_index: an unrelated index is kept, the configured one appended
- unrelated_class: a class not derived from a configured parent is untouched

The Payment stub goes with them - nothing references it now, and the b2b-kit
configuration lives in a set file rather than in a test.
@Wojdylak
Wojdylak force-pushed the feature/add-index-to-class-extending-type-rector branch from b5e9364 to 36753b0 Compare September 3, 2026 11:31
@Wojdylak
Wojdylak merged commit 6ea42e3 into Sylius:main Sep 3, 2026
2 checks passed
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