private function normalizeAndAddJoins(array $levels, $sourceEntity, QueryBuilder $builder, &$distinctNeeded = false, &$value = null, &$modifier = '%any')
{
$column = array_pop($levels);
$sourceMapper = $this->mapper;
$sourceAlias = $builder->getFromAlias();
$sourceReflection = $sourceMapper->getStorageReflection();
$sourceEntityMeta = $this->metadataStorage->get($sourceEntity ?: $sourceMapper->getRepository()->getEntityClassNames()[0]);
foreach ($levels as $levelIndex => $level) {
$property = $sourceEntityMeta->getProperty($level);
if ($property->relationship === null) {
throw new InvalidArgumentException("Entity {$sourceEntityMeta->className}::\${$level} does not contain a relationship.");
}
$targetMapper = $this->model->getRepository($property->relationship->repository)->getMapper();
$targetReflection = $targetMapper->getStorageReflection();
$targetEntityMetadata = $this->metadataStorage->get($property->relationship->entity);
$relType = $property->relationship->type;
if ($relType === Relationship::ONE_HAS_MANY || $relType === Relationship::ONE_HAS_ONE && !$property->relationship->isMain) {
$targetColumn = $targetReflection->convertEntityToStorageKey($property->relationship->property);
$sourceColumn = $sourceReflection->getStoragePrimaryKey()[0];
$distinctNeeded = $relType === Relationship::ONE_HAS_MANY;
} elseif ($relType === Relationship::MANY_HAS_MANY) {
if ($property->relationship->isMain) {
list($joinTable, list($inColumn, $outColumn)) = $sourceMapper->getManyHasManyParameters($property, $targetMapper);
} else {
$sourceProperty = $targetEntityMetadata->getProperty($property->relationship->property);
list($joinTable, list($outColumn, $inColumn)) = $targetMapper->getManyHasManyParameters($sourceProperty, $sourceMapper);
}
$sourceColumn = $sourceReflection->getStoragePrimaryKey()[0];
$builder->leftJoin($sourceAlias, $joinTable, self::getAlias($joinTable), "[{$sourceAlias}.{$sourceColumn}] = [{$joinTable}.{$inColumn}]");
$sourceAlias = $joinTable;
$sourceColumn = $outColumn;
$targetColumn = $targetReflection->getStoragePrimaryKey()[0];
$distinctNeeded = true;
} else {
$targetColumn = $targetReflection->getStoragePrimaryKey()[0];
$sourceColumn = $sourceReflection->convertEntityToStorageKey($level);
}
$targetTable = $targetMapper->getTableName();
$targetAlias = $level . str_repeat('_', $levelIndex);
$builder->leftJoin($sourceAlias, $targetTable, $targetAlias, "[{$sourceAlias}.{$sourceColumn}] = [{$targetAlias}.{$targetColumn}]");
$sourceAlias = $targetAlias;
$sourceMapper = $targetMapper;
$sourceReflection = $targetReflection;
$sourceEntityMeta = $targetEntityMetadata;
}
$targetProperty = $sourceEntityMeta->getProperty($column);
if ($targetProperty->isPrimary && $targetProperty->isVirtual) {
// primary-proxy
$primaryKey = $sourceEntityMeta->getPrimaryKey();
if (count($primaryKey) > 1) {
// composite primary key
$modifier = '%any';
list($expression, $value) = $this->processMultiColumn($sourceReflection, $primaryKey, $value, $sourceAlias);
return $expression;
} else {
$column = reset($primaryKey);
}
}
list($expression, $modifier, $value) = $this->processColumn($sourceReflection, $column, $value, $sourceAlias);
return $expression;
}