alengo / doctrine-compatibility-bundle
Compatibility fixes for Sulu 3 with Doctrine ORM 3.x and Gedmo DoctrineExtensions
Package info
github.com/alengodev/SuluDoctrineCompatibilityBundle
Type:symfony-bundle
pkg:composer/alengo/doctrine-compatibility-bundle
Requires
- php: ^8.2
- doctrine/orm: ^3.0
- gedmo/doctrine-extensions: ^3.0
- stof/doctrine-extensions-bundle: ^1.11
- sulu/sulu: ^3.0
- symfony/dependency-injection: ^7.0
- symfony/framework-bundle: ^7.0
- symfony/http-kernel: ^7.0
README
A Symfony bundle that fixes runtime incompatibilities between Sulu 3, Doctrine ORM 3.x, and Gedmo DoctrineExtensions.
The Problem
Sulu 3, Doctrine ORM 3.x, and Gedmo DoctrineExtensions all underwent major version changes around the same time. The combination of these three libraries produces three distinct bugs that surface at runtime.
1. Gedmo TreeListener fails for Sulu's Page entity
Sulu\Page\Domain\Model\Page is declared as a <mapped-superclass> in Sulu's ORM XML. Gedmo's ExtensionMetadataFactory explicitly returns [] for mapped-superclasses, so any call to getConfiguration() or getStrategy() with SuluPage::class throws:
UnexpectedValueException: Tree object class: Sulu\Page\Domain\Model\Page must have tree metadata at this point
2. Gedmo TreeObjectHydrator fails with Doctrine ORM 3.x
Doctrine ORM 3.x removed the mappedBy property from owning-side ManyToOneAssociationMapping. Gedmo's hydrator unconditionally accesses it for all associations, throwing:
Error: Unknown property "mappedBy" on class Doctrine\ORM\Mapping\ManyToOneAssociationMapping
3. Inherited association mappings missing declared property
When extending Sulu's Page or Article entities with Doctrine ORM 3.x and report_fields_where_declared: true, inherited association mappings have null as their declared property, causing schema validation errors.
Installation
composer require alengo/doctrine-compatibility-bundle
The bundle registers itself automatically via Symfony Flex.
Configuration
The default configuration works for standard Sulu projects where the concrete Page entity is App\Entity\Page. To override:
# config/packages/alengo_doctrine_compatibility.yaml alengo_doctrine_compatibility: page_entity_class: App\Entity\Page # adjust if your class differs
The configured class must extend Sulu\Page\Domain\Model\Page.
How It Works
SuluPageAwareTreeListener
Extends Gedmo's TreeListener and overrides getConfiguration() and getStrategy(). Any call with Sulu\Page\Domain\Model\Page is transparently delegated to the configured concrete Page entity class, which has valid tree metadata.
Registered via CompilerPass — overrides the stof_doctrine_extensions.listener.tree service after all bundle extensions have loaded, ensuring correct behavior regardless of bundle registration order.
SafeTreeObjectHydrator
Extends Gedmo's TreeObjectHydrator and overrides getChildrenField() to skip owning-side ManyToOne associations before accessing mappedBy, which does not exist in Doctrine ORM 3.x for owning-side mappings.
Registered as the sulu_page_tree hydrator via CompilerPass, overriding Sulu's default registration across all configured entity managers.
InheritedAssociationDeclaredFixerSubscriber
Listens to Doctrine's loadClassMetadata event and resolves the declared property for inherited association mappings where it is null, by walking the class hierarchy via reflection.
Requirements
| Package | Version |
|---|---|
| PHP | ^8.2 |
| Sulu | ^3.0 |
| Doctrine ORM | ^3.0 |
| Gedmo DoctrineExtensions | ^3.0 |
| stof/doctrine-extensions-bundle | ^1.11 |
| Symfony | ^7.0 |
License
MIT — alengo.dev