4 +--------------------------------------------------------------------+
6 +--------------------------------------------------------------------+
7 | Copyright CiviCRM LLC (c) 2004-2019 |
8 +--------------------------------------------------------------------+
9 | This file is a part of CiviCRM. |
11 | CiviCRM is free software; you can copy, modify, and distribute it |
12 | under the terms of the GNU Affero General Public License |
13 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
15 | CiviCRM is distributed in the hope that it will be useful, but |
16 | WITHOUT ANY WARRANTY; without even the implied warranty of |
17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
18 | See the GNU Affero General Public License for more details. |
20 | You should have received a copy of the GNU Affero General Public |
21 | License and the CiviCRM Licensing Exception along |
22 | with this program; if not, contact CiviCRM LLC |
23 | at info[AT]civicrm[DOT]org. If you have questions about the |
24 | GNU Affero General Public License or the licensing of CiviCRM, |
25 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
26 +--------------------------------------------------------------------+
32 * @copyright CiviCRM LLC (c) 2004-2019
38 namespace Civi\Api4\Service\Schema
;
40 use Civi\Api4\Service\Schema\Joinable\BridgeJoinable
;
44 const MAX_JOIN_DEPTH
= 3;
49 protected $tables = [];
52 * @param $baseTableName
53 * @param $targetTableAlias
55 * @return \Civi\Api4\Service\Schema\Joinable\Joinable[]
56 * Array of links to the target table, empty if no path found
58 public function getPath($baseTableName, $targetTableAlias) {
59 $table = $this->getTableByName($baseTableName);
66 $this->findPaths($table, $targetTableAlias, 1, $path);
68 foreach ($path as $index => $pathLink) {
69 if ($pathLink instanceof BridgeJoinable
) {
70 $start = array_slice($path, 0, $index);
71 $middle = [$pathLink->getMiddleLink()];
72 $end = array_slice($path, $index, count($path) - $index);
73 $path = array_merge($start, $middle, $end);
83 public function getTables() {
92 public function getTableByName($name) {
93 foreach ($this->tables
as $table) {
94 if ($table->getName() === $name) {
103 * Adds a table to the schema map if it has not already been added
105 * @param Table $table
109 public function addTable(Table
$table) {
110 if (!$this->getTableByName($table->getName())) {
111 $this->tables
[] = $table;
118 * @param array $tables
120 public function addTables(array $tables) {
121 foreach ($tables as $table) {
122 $this->addTable($table);
127 * Recursive function to traverse the schema looking for a path
129 * @param Table $table
130 * The current table to base fromm
131 * @param string $target
132 * The target joinable table alias
134 * The current level of recursion which reflects the number of joins needed
135 * @param \Civi\Api4\Service\Schema\Joinable\Joinable[] $path
136 * (By-reference) The possible paths to the target table
137 * @param \Civi\Api4\Service\Schema\Joinable\Joinable[] $currentPath
138 * For internal use only to track the path to reach the target table
140 private function findPaths(Table
$table, $target, $depth, &$path, $currentPath = []
142 static $visited = [];
149 $canBeShorter = empty($path) ||
count($currentPath) +
1 < count($path);
150 $tooFar = $depth > self
::MAX_JOIN_DEPTH
;
151 $beenHere = in_array($table->getName(), $visited);
153 if ($tooFar ||
$beenHere ||
!$canBeShorter) {
157 // prevent circular reference
158 $visited[] = $table->getName();
160 foreach ($table->getExternalLinks() as $link) {
161 if ($link->getAlias() === $target) {
162 $path = array_merge($currentPath, [$link]);
165 $linkTable = $this->getTableByName($link->getTargetTable());
167 $nextStep = array_merge($currentPath, [$link]);
168 $this->findPaths($linkTable, $target, $depth +
1, $path, $nextStep);