$side = array_shift($join) ? 'INNER' : 'LEFT';
// Add all fields from joined entity to spec
$joinEntityGet = \Civi\API\Request::create($entity, 'get', ['version' => 4, 'checkPermissions' => $this->getCheckPermissions()]);
- foreach ($joinEntityGet->entityFields() as $field) {
+ $joinEntityFields = $joinEntityGet->entityFields();
+ foreach ($joinEntityFields as $field) {
$field['sql_name'] = '`' . $alias . '`.`' . $field['column_name'] . '`';
$this->addSpecField($alias . '.' . $field['name'], $field);
}
$conditions = $this->getBridgeJoin($join, $entity, $alias);
}
else {
- $conditions = $this->getJoinConditions($join, $entity, $alias);
+ $conditions = $this->getJoinConditions($join, $entity, $alias, $joinEntityFields);
}
foreach (array_filter($join) as $clause) {
$conditions[] = $this->treeWalkClauses($clause, 'ON');
* @param array $joinTree
* @param string $joinEntity
* @param string $alias
+ * @param array $joinEntityFields
* @return array
*/
- private function getJoinConditions($joinTree, $joinEntity, $alias) {
+ private function getJoinConditions($joinTree, $joinEntity, $alias, $joinEntityFields) {
$conditions = [];
// getAclClause() expects a stack of 1-to-1 join fields to help it dedupe, but this is more flexible,
// so unless this is a direct 1-to-1 join with the main entity, we'll just hack it
// with a padded empty stack to bypass its deduping.
$stack = [NULL, NULL];
- // If we're not explicitly referencing the joinEntity ID in the ON clause, search for a default
- $explicitId = array_filter($joinTree, function($clause) use ($alias) {
+ // See if the ON clause already contains an FK reference to joinEntity
+ $explicitFK = array_filter($joinTree, function($clause) use ($alias, $joinEntityFields) {
list($sideA, $op, $sideB) = array_pad((array) $clause, 3, NULL);
- return $op === '=' && ($sideA === "$alias.id" || $sideB === "$alias.id");
+ if ($op !== '=' || !$sideB) {
+ return FALSE;
+ }
+ foreach ([$sideA, $sideB] as $expr) {
+ if ($expr === "$alias.id" || !empty($joinEntityFields["$alias.$expr"]['fk_entity'])) {
+ return TRUE;
+ }
+ }
+ return FALSE;
});
- if (!$explicitId) {
+ // If we're not explicitly referencing the ID (or some other FK field) of the joinEntity, search for a default
+ if (!$explicitFK) {
foreach ($this->apiFieldSpec as $name => $field) {
if ($field['entity'] !== $joinEntity && $field['fk_entity'] === $joinEntity) {
$conditions[] = $this->treeWalkClauses([$name, '=', "$alias.id"], 'ON');