Skip to content

Commit

Permalink
Merge pull request #19275 from colemanw/apiJoinConditions
Browse files Browse the repository at this point in the history
APIv4 - Smarter check for adding default ON clause to explicit joins
  • Loading branch information
eileenmcnaughton authored Dec 28, 2020
2 parents e4e20a1 + a5d7af6 commit a4b487a
Showing 1 changed file with 18 additions and 7 deletions.
25 changes: 18 additions & 7 deletions Civi/Api4/Query/Api4SelectQuery.php
Original file line number Diff line number Diff line change
Expand Up @@ -535,15 +535,16 @@ private function addExplicitJoins() {
$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);
}
if (!empty($join[0]) && is_string($join[0]) && \CRM_Utils_Rule::alphanumeric($join[0])) {
$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');
Expand All @@ -559,20 +560,30 @@ private function addExplicitJoins() {
* @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');
Expand Down

0 comments on commit a4b487a

Please sign in to comment.