[Promotion] Add version locking to promotions and coupons by NoResponseMate · Pull Request #18921 · Sylius/Sylius
📝 Walkthrough
Walkthrough
Adds optimistic locking to Promotion and PromotionCoupon (version fields, ORM mappings, migrations), updates interfaces to be Versioned, and refactors AtomicOrderPromotionsUsageModifier to obtain entity locks via the EntityManager and delegate increment/decrement to a decorated modifier.
Changes
| Cohort / File(s) | Summary |
|---|---|
Core Entity Models src/Sylius/Component/Core/Model/Promotion.php, src/Sylius/Component/Core/Model/PromotionCoupon.php |
Added protected version property (default 1) with getVersion(): ?int and setVersion(?int): void accessors. |
Entity Interfaces src/Sylius/Component/Core/Model/PromotionInterface.php, src/Sylius/Component/Core/Model/PromotionCouponInterface.php |
Now extend VersionedInterface, adding versioning to the public contract. |
Doctrine ORM Configuration src/Sylius/Bundle/CoreBundle/Resources/config/doctrine/model/Promotion.orm.xml, src/Sylius/Bundle/CoreBundle/Resources/config/doctrine/model/PromotionCoupon.orm.xml |
Added integer version field mappings with version="true" to enable optimistic locking. |
Database Migrations src/Sylius/Bundle/CoreBundle/Migrations/Version20260216120000.php, src/Sylius/Bundle/CoreBundle/Migrations/Version20260216120001.php |
New migrations adding version INT NOT NULL DEFAULT 1 columns to sylius_promotion and sylius_promotion_coupon (standard and PostgreSQL variants). |
Modifier Refactor src/Sylius/Bundle/CoreBundle/Doctrine/ORM/Promotion/Modifier/AtomicOrderPromotionsUsageModifier.php |
Reworked to accept optional Connection, a decorated OrderPromotionsUsageModifierInterface, and EntityManagerInterface; removed direct SQL updates and now refreshes and locks relevant entities (optimistic locking) before delegating increment/decrement to the decorated modifier; constructor usage of Connection is deprecated. |
Service Configuration src/Sylius/Bundle/CoreBundle/Resources/config/services/promotion.php |
Updated service args for sylius.modifier.promotion.order_usage.atomic to pass null, the decorated service (.inner), and doctrine.orm.entity_manager; removed constructor arg from non-atomic modifier. |
Tests src/Sylius/Bundle/CoreBundle/tests/Doctrine/ORM/Promotion/Modifier/AtomicOrderPromotionsUsageModifierTest.php, src/Sylius/Component/Core/tests/Model/PromotionCouponTest.php |
Added tests verifying EntityManager refresh/lock interactions and delegation to the decorated modifier; added test confirming PromotionCoupon implements VersionedInterface and default version equals 1. |
Sequence Diagram
sequenceDiagram
participant Client as Client Code
participant AOUM as AtomicOrderPromotionsUsageModifier
participant EM as EntityManager
participant DM as Decorated Modifier
participant DB as Database
Client->>AOUM: increment(order, promotions, coupon?)
Note over AOUM: Refresh & optimistic lock phase
AOUM->>EM: refresh(promotion)
EM->>DB: SELECT promotion
DB-->>EM: promotion row (version=N)
AOUM->>EM: lock(promotion, OPTIMISTIC, N)
EM-->>AOUM: locked (version checked)
alt coupon present
AOUM->>EM: refresh(coupon)
EM->>DB: SELECT coupon
DB-->>EM: coupon row (version=M)
AOUM->>EM: lock(coupon, OPTIMISTIC, M)
EM-->>AOUM: locked (version checked)
end
Note over AOUM: Delegate actual usage change
AOUM->>DM: increment(order, promotions, coupon?)
DM->>DB: apply updates (via repositories/ORM)
DB-->>DM: updates persisted
DM-->>AOUM: done
AOUM-->>Client: complete
Estimated code review effort
🎯 3 (Moderate) | ⏱️ ~25 minutes
Poem
🐰 I nudged the versions up to one,
Locks in place before the fun,
I delegate with careful hops,
No rogue SQL, no sudden drops,
Hooray — concurrency now runs!
🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
| Check name | Status | Explanation | Resolution |
|---|---|---|---|
| Docstring Coverage | ⚠️ Warning | Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. | Write docstrings for the functions missing them to satisfy the coverage threshold. |
✅ Passed checks (2 passed)
| Check name | Status | Explanation |
|---|---|---|
| Description Check | ✅ Passed | Check skipped - CodeRabbit’s high-level summary is enabled. |
| Title check | ✅ Passed | The title accurately describes the main change: adding version locking to promotions and coupons. It is concise, clear, and directly related to the primary objective of the changeset. |
✏️ Tip: You can configure your own custom pre-merge checks in the settings.
✨ Finishing Touches
🧪 Generate unit tests (beta)
- Create PR with unit tests
📝 Coding Plan
- Generate coding plan for human review comments
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.
Comment @coderabbitai help to get the list of available commands and usage tips.