🚀 Migration Plan: Upgrade Roadiz to Doctrine ORM 3.x
Context
Roadiz currently relies on Doctrine ORM 2.x, which has reached end-of-life. Doctrine ORM 3.x introduces significant internal refactoring, removal of deprecated APIs, and ecosystem alignment (DoctrineBundle 3, DBAL 3+, etc.).
This issue tracks the full migration of Roadiz to Doctrine ORM 3.6.x (stable minor target), ensuring:
- Forward compatibility
- Removal of deprecated APIs
- Improved performance and maintainability
- Alignment with the current Symfony/Doctrine ecosystem
🎯 Target Stack
| Package |
Target Version |
| doctrine/orm |
^3.6 |
| doctrine/dbal |
^3 |
| doctrine/doctrine-bundle |
^3 |
| doctrine/persistence |
latest compatible |
| doctrine/migrations |
latest compatible |
🧭 Migration Strategy (Phased Approach)
We will not attempt a big-bang upgrade. Migration will be done in controlled phases.
Phase 1 — Stabilize on Latest ORM 2.x (Pre-Upgrade Cleanup)
Goal
Eliminate all deprecations under ORM 2.21 before moving to 3.x.
Tasks
Why?
Doctrine officially recommends upgrading to the latest 2.x and clearing deprecations before jumping to 3.x.
Phase 2 — DoctrineBundle 3 Upgrade
DoctrineBundle 3 removed legacy support (annotations, YAML mapping, legacy config options).
Tasks
Phase 3 — Mapping Migration (Critical)
DoctrineBundle 3 removes support for:
- ❌ Annotations
- ❌ YAML mapping
If Roadiz uses annotations:
They must be converted to PHP Attributes:
If YAML mappings exist:
They must be converted to:
- PHP Attributes (preferred)
- OR XML mapping
Tasks
Phase 4 — Removed APIs & Breaking Changes (ORM 3)
This is the most critical phase.
1️⃣ EntityManager::merge() Removed
Find
Required Refactor
Replace merge usage with explicit load + patch pattern:
$entity = $repository->find($id);
$entity->setFoo($dto->foo);
$em->flush();
No automatic graph reattachment exists in ORM 3.
2️⃣ Cascade "merge" Removed
Find
Action
Remove merge from cascade definitions.
Allowed cascade options:
- persist
- remove
- refresh
- detach
3️⃣ Flush Behavior Review
Audit usage of:
Ensure no reliance on legacy partial flush semantics.
Prefer full flush unless explicitly safe.
4️⃣ Proxy & Lazy Loading Changes
ORM 3 introduces internal improvements and optional Native Lazy Objects.
Tasks
Phase 5 — Query & Hydration Review
Audit advanced ORM usage:
ResultSetMapping
- Custom hydrators
iterate()
toIterable()
- Scalar hydration
- DQL PARTIAL objects
- Custom query hints
Tasks
Phase 6 — Migrations & Tooling
🔎 Repository Audit Commands
Run these before starting Phase 4:
rg -n "->merge\s*\(" .
rg -n "cascade\s*=\s*\{[^}]*merge|cascade:\s*\[[^\]]*merge|cascade:\s*\{[^}]*merge" .
rg -n "@ORM\\\\" .
rg -n "type:\s*yml|\\.orm\\.yml" .
rg -n "Doctrine\\\\Common\\\\Persistence" .
rg -n "Doctrine\\\\ORM\\\\Tools\\\\Setup" .
Attach results to this issue for tracking.
🧪 Testing Requirements
Minimum validation checklist before merge:
⚠️ Risk Areas
| Area |
Risk Level |
| Entity graphs |
High |
| Backoffice forms |
High |
| Serialization |
Medium |
| Custom DQL |
Medium |
| Event subscribers |
Medium |
| Performance |
Medium |
📦 Delivery Strategy
Recommended workflow:
- Create branch
feature/orm3-migration
- Maintain ORM2-compatible branch for hotfixes
- Enable strict CI rules
- Merge only when fully green
- Squash commits per migration phase
✅ Definition of Done
- Roadiz runs fully on Doctrine ORM 3.6+
- No deprecated APIs remain
- No runtime regressions
- Documentation updated
- CI enforces Doctrine 3 compatibility
- All mapping uses PHP Attributes or XML
This issue serves as the canonical migration blueprint.
All related PRs must reference it.
🚀 Migration Plan: Upgrade Roadiz to Doctrine ORM 3.x
Context
Roadiz currently relies on Doctrine ORM 2.x, which has reached end-of-life. Doctrine ORM 3.x introduces significant internal refactoring, removal of deprecated APIs, and ecosystem alignment (DoctrineBundle 3, DBAL 3+, etc.).
This issue tracks the full migration of Roadiz to Doctrine ORM 3.6.x (stable minor target), ensuring:
🎯 Target Stack
🧭 Migration Strategy (Phased Approach)
We will not attempt a big-bang upgrade. Migration will be done in controlled phases.
Phase 1 — Stabilize on Latest ORM 2.x (Pre-Upgrade Cleanup)
Goal
Eliminate all deprecations under ORM 2.21 before moving to 3.x.
Tasks
doctrine/orm:^2.21doctrine/dbal:^3bin/console doctrine:schema:validateWhy?
Doctrine officially recommends upgrading to the latest 2.x and clearing deprecations before jumping to 3.x.
Phase 2 — DoctrineBundle 3 Upgrade
DoctrineBundle 3 removed legacy support (annotations, YAML mapping, legacy config options).
Tasks
doctrine/doctrine-bundle:^3Doctrine\ORM\Tools\SetupusagePhase 3 — Mapping Migration (Critical)
DoctrineBundle 3 removes support for:
If Roadiz uses annotations:
They must be converted to PHP Attributes:
#[ORM\Entity]If YAML mappings exist:
They must be converted to:
Tasks
@ORM\.orm.ymlfilesdoctrine:schema:validatePhase 4 — Removed APIs & Breaking Changes (ORM 3)
This is the most critical phase.
1️⃣
EntityManager::merge()RemovedFind
Required Refactor
Replace merge usage with explicit load + patch pattern:
No automatic graph reattachment exists in ORM 3.
2️⃣ Cascade "merge" Removed
Find
Action
Remove
mergefrom cascade definitions.Allowed cascade options:
3️⃣ Flush Behavior Review
Audit usage of:
Ensure no reliance on legacy partial flush semantics.
Prefer full flush unless explicitly safe.
4️⃣ Proxy & Lazy Loading Changes
ORM 3 introduces internal improvements and optional Native Lazy Objects.
Tasks
Phase 5 — Query & Hydration Review
Audit advanced ORM usage:
ResultSetMappingiterate()toIterable()Tasks
Phase 6 — Migrations & Tooling
🔎 Repository Audit Commands
Run these before starting Phase 4:
Attach results to this issue for tracking.
🧪 Testing Requirements
Minimum validation checklist before merge:
📦 Delivery Strategy
Recommended workflow:
feature/orm3-migration✅ Definition of Done
This issue serves as the canonical migration blueprint.
All related PRs must reference it.