summaryrefslogtreecommitdiff
path: root/www/crm/wp-content/plugins/civicrm/civicrm/ext/api4/Civi/Api4/Service/Schema/Joiner.php
blob: cb30ab5703c025e676bbbb59b7f609920e063956 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
<?php

namespace Civi\Api4\Service\Schema;

use Civi\Api4\Query\Api4SelectQuery;
use Civi\Api4\Service\Schema\Joinable\Joinable;

class Joiner {
  /**
   * @var SchemaMap
   */
  protected $schemaMap;

  /**
   * @var Joinable[][]
   */
  protected $cache = [];

  /**
   * @param SchemaMap $schemaMap
   */
  public function __construct(SchemaMap $schemaMap) {
    $this->schemaMap = $schemaMap;
  }

  /**
   * @param Api4SelectQuery $query
   *   The query object to do the joins on
   * @param string $joinPath
   *   A path of aliases in dot notation, e.g. contact.phone
   * @param string $side
   *   Can be LEFT or INNER
   *
   * @throws \Exception
   * @return Joinable[]
   *   The path used to make the join
   */
  public function join(Api4SelectQuery $query, $joinPath, $side = 'LEFT') {
    $fullPath = $this->getPath($query->getFrom(), $joinPath);
    $baseTable = $query::MAIN_TABLE_ALIAS;

    foreach ($fullPath as $link) {
      $target = $link->getTargetTable();
      $alias = $link->getAlias();
      $conditions = $link->getConditionsForJoin($baseTable);

      $query->join($side, $target, $alias, $conditions);
      $query->addJoinedTable($link);

      $baseTable = $link->getAlias();
    }

    return $fullPath;
  }

  /**
   * @param Api4SelectQuery $query
   * @param $joinPath
   *
   * @return bool
   */
  public function canJoin(Api4SelectQuery $query, $joinPath) {
    return !empty($this->getPath($query->getFrom(), $joinPath));
  }

  /**
   * @param string $baseTable
   * @param string $joinPath
   *
   * @return array
   * @throws \Exception
   */
  protected function getPath($baseTable, $joinPath) {
    $cacheKey = sprintf('%s.%s', $baseTable, $joinPath);
    if (!isset($this->cache[$cacheKey])) {
      $stack = explode('.', $joinPath);
      $fullPath = [];

      foreach ($stack as $key => $targetAlias) {
        $links = $this->schemaMap->getPath($baseTable, $targetAlias);

        if (empty($links)) {
          throw new \Exception(sprintf('Cannot join %s to %s', $baseTable, $targetAlias));
        }
        else {
          $fullPath = array_merge($fullPath, $links);
          $lastLink = end($links);
          $baseTable = $lastLink->getTargetTable();
        }
      }

      $this->cache[$cacheKey] = $fullPath;
    }

    return $this->cache[$cacheKey];
  }

}