@@ -112,17 +112,17 @@ public function initFields(EntitySchema $entity, \ReflectionClass $class, string
112
112
}
113
113
114
114
$ field = $ this ->initField ($ property ->getName (), $ column , $ class , $ columnPrefix );
115
- $ field ->setEntityClass ($ property ->getDeclaringClass ()->getName ());
115
+ $ field ->setEntityClass ($ this -> findOwningEntity ( $ class , $ property ->getDeclaringClass () )->getName ());
116
116
$ entity ->getFields ()->set ($ property ->getName (), $ field );
117
117
}
118
118
}
119
119
120
120
public function initRelations (EntitySchema $ entity , \ReflectionClass $ class ): void
121
121
{
122
122
foreach ($ class ->getProperties () as $ property ) {
123
- // ignore properties declared by parent class
123
+ // ignore properties declared by parent entties
124
124
// otherwise all the relation columns declared in parent would be duplicated across all child tables in JTI
125
- if ($ this ->propertyBelongsToOtherEntity ($ class , $ property ->getDeclaringClass ())) {
125
+ if ($ this ->findOwningEntity ($ class , $ property ->getDeclaringClass ())-> getName () !== $ class -> getName ( )) {
126
126
continue ;
127
127
}
128
128
@@ -420,26 +420,37 @@ private function isOnInsertGeneratedField(Field $field): bool
420
420
};
421
421
}
422
422
423
- private function propertyBelongsToOtherEntity (\ReflectionClass $ currentClass , \ReflectionClass $ declaringClass ): bool
423
+ /**
424
+ * Function to find an owning entity class in the inheritance hierarchy.
425
+ *
426
+ * Entity classes may extend a base class and this function is needed route the properties from declaring class to the entity class.
427
+ * The function stops only when the declaring class is truly found, it does not naively stop on first entity.
428
+ * This behaviour makes it also functional in cases of Joined Table Inheritance on theoretically any number of nesting levels.
429
+ */
430
+ private function findOwningEntity (\ReflectionClass $ currentClass , \ReflectionClass $ declaringClass ): \ReflectionClass
424
431
{
425
- // if the current class is the same as declaring class, than the property belongs to current Entity
426
- if ($ currentClass ->getName () === $ declaringClass ->getName ()) {
427
- return false ;
428
- }
429
-
430
- $ parentClass = $ currentClass ->getParentClass ();
432
+ // latest found entityClass before declaringClass
433
+ $ latestEntityClass = $ currentClass ;
434
+
435
+ do {
436
+ // we found declaringClass in the hierarchy
437
+ // in most cases the execution will stop here in first loop
438
+ if ($ currentClass ->getName () === $ declaringClass ->getName ()) {
439
+ return $ latestEntityClass ;
440
+ }
431
441
432
- // not possible to happen for logical reasons, but defensively check anyway
433
- if (!$ parentClass instanceof \ReflectionClass) {
434
- return false ;
435
- }
442
+ $ currentClass = $ currentClass ->getParentClass ();
436
443
437
- // if a parent class in hierarchy is an Entity on its own, the property belongs to that Entity
438
- if (\count ( $ parentClass -> getAttributes (Entity::class)) > 0 ) {
439
- return true ;
440
- }
444
+ // not possible to happen for logical reasons, but defensively check anyway
445
+ if (! $ currentClass instanceof \ReflectionClass ) {
446
+ return $ latestEntityClass ;
447
+ }
441
448
442
- // continue until we find a declaringClass or Entity attribute
443
- return $ this ->propertyBelongsToOtherEntity ($ parentClass , $ declaringClass );
449
+ // if a currentClass in hierarchy is an entity on its own, the property belongs to that entity
450
+ if (\count ($ currentClass ->getAttributes (Entity::class)) > 0 ) {
451
+ $ latestEntityClass = $ currentClass ;
452
+ }
453
+ } while (true ); // the inheritance hierarchy cannot be infinite
444
454
}
445
455
}
456
+
0 commit comments