Skip to content

Commit

Permalink
Implement entity lookup in hierarchy, closes cycle#101
Browse files Browse the repository at this point in the history
  • Loading branch information
peldax authored Jun 21, 2024
1 parent 8954c01 commit 90989a4
Showing 1 changed file with 31 additions and 20 deletions.
51 changes: 31 additions & 20 deletions src/Configurator.php
Original file line number Diff line number Diff line change
Expand Up @@ -112,17 +112,17 @@ public function initFields(EntitySchema $entity, \ReflectionClass $class, string
}

$field = $this->initField($property->getName(), $column, $class, $columnPrefix);
$field->setEntityClass($property->getDeclaringClass()->getName());
$field->setEntityClass($this->findOwningEntity($class, $property->getDeclaringClass())->getName());
$entity->getFields()->set($property->getName(), $field);
}
}

public function initRelations(EntitySchema $entity, \ReflectionClass $class): void
{
foreach ($class->getProperties() as $property) {
// ignore properties declared by parent class
// ignore properties declared by parent entties
// otherwise all the relation columns declared in parent would be duplicated across all child tables in JTI
if ($this->propertyBelongsToOtherEntity($class, $property->getDeclaringClass())) {
if ($this->findOwningEntity($class, $property->getDeclaringClass())->getName() !== $class->getName()) {
continue;
}

Expand Down Expand Up @@ -420,26 +420,37 @@ private function isOnInsertGeneratedField(Field $field): bool
};
}

private function propertyBelongsToOtherEntity(\ReflectionClass $currentClass, \ReflectionClass $declaringClass): bool
/**
* Function to find an owning entity class in the inheritance hierarchy.
*
* Entity classes may extend a base class and this function is needed route the properties from declaring class to the entity class.
* The function stops only when the declaring class is truly found, it does not naively stop on first entity.
* This behaviour makes it also functional in cases of Joined Table Inheritance on theoretically any number of nesting levels.
*/
private function findOwningEntity(\ReflectionClass $currentClass, \ReflectionClass $declaringClass): \ReflectionClass
{
// if the current class is the same as declaring class, than the property belongs to current Entity
if ($currentClass->getName() === $declaringClass->getName()) {
return false;
}

$parentClass = $currentClass->getParentClass();
// latest found entityClass before declaringClass
$latestEntityClass = $currentClass;

do {
// we found declaringClass in the hierarchy
// in most cases the execution will stop here in first loop
if ($currentClass->getName() === $declaringClass->getName()) {
return $latestEntityClass;
}

// not possible to happen for logical reasons, but defensively check anyway
if (!$parentClass instanceof \ReflectionClass) {
return false;
}
$currentClass = $currentClass->getParentClass();

// if a parent class in hierarchy is an Entity on its own, the property belongs to that Entity
if (\count($parentClass->getAttributes(Entity::class)) > 0) {
return true;
}
// not possible to happen for logical reasons, but defensively check anyway
if (!$currentClass instanceof \ReflectionClass) {
return $latestEntityClass;
}

// continue until we find a declaringClass or Entity attribute
return $this->propertyBelongsToOtherEntity($parentClass, $declaringClass);
// if a currentClass in hierarchy is an entity on its own, the property belongs to that entity
if (\count($currentClass->getAttributes(Entity::class)) > 0) {
$latestEntityClass = $currentClass;
}
} while (true); // the inheritance hierarchy cannot be infinite
}
}

0 comments on commit 90989a4

Please sign in to comment.