Commit | Line | Data |
---|---|---|
19b53e5b C |
1 | <?php |
2 | ||
380f3545 TO |
3 | /* |
4 | +--------------------------------------------------------------------+ | |
41498ac5 | 5 | | Copyright CiviCRM LLC. All rights reserved. | |
380f3545 | 6 | | | |
41498ac5 TO |
7 | | This work is published under the GNU AGPLv3 license with some | |
8 | | permitted exceptions and without any warranty. For full license | | |
9 | | and copyright information, see https://civicrm.org/licensing | | |
380f3545 TO |
10 | +--------------------------------------------------------------------+ |
11 | */ | |
12 | ||
19b53e5b C |
13 | namespace Civi\Api4\Service\Schema; |
14 | ||
15 | use Civi\Api4\Entity; | |
16 | use Civi\Api4\Event\Events; | |
17 | use Civi\Api4\Event\SchemaMapBuildEvent; | |
18 | use Civi\Api4\Service\Schema\Joinable\CustomGroupJoinable; | |
19 | use Civi\Api4\Service\Schema\Joinable\Joinable; | |
20 | use Symfony\Component\EventDispatcher\EventDispatcherInterface; | |
19b53e5b | 21 | use CRM_Core_DAO_AllCoreTables as AllCoreTables; |
19b53e5b C |
22 | |
23 | class SchemaMapBuilder { | |
24 | /** | |
25 | * @var \Symfony\Component\EventDispatcher\EventDispatcherInterface | |
26 | */ | |
27 | protected $dispatcher; | |
28 | /** | |
29 | * @var array | |
30 | */ | |
31 | protected $apiEntities; | |
32 | ||
33 | /** | |
34 | * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $dispatcher | |
35 | */ | |
36 | public function __construct(EventDispatcherInterface $dispatcher) { | |
37 | $this->dispatcher = $dispatcher; | |
fe806431 | 38 | $this->apiEntities = array_keys((array) Entity::get(FALSE)->addSelect('name')->execute()->indexBy('name')); |
19b53e5b C |
39 | } |
40 | ||
41 | /** | |
42 | * @return SchemaMap | |
43 | */ | |
44 | public function build() { | |
45 | $map = new SchemaMap(); | |
46 | $this->loadTables($map); | |
47 | ||
48 | $event = new SchemaMapBuildEvent($map); | |
49 | $this->dispatcher->dispatch(Events::SCHEMA_MAP_BUILD, $event); | |
50 | ||
51 | return $map; | |
52 | } | |
53 | ||
54 | /** | |
55 | * Add all tables and joins | |
56 | * | |
57 | * @param SchemaMap $map | |
58 | */ | |
59 | private function loadTables(SchemaMap $map) { | |
60 | /** @var \CRM_Core_DAO $daoName */ | |
40ac12d3 | 61 | foreach (AllCoreTables::get() as $data) { |
19b53e5b | 62 | $table = new Table($data['table']); |
40ac12d3 | 63 | foreach ($data['class']::fields() as $fieldData) { |
60677581 | 64 | $this->addJoins($table, $fieldData['name'], $fieldData); |
19b53e5b C |
65 | } |
66 | $map->addTable($table); | |
67 | if (in_array($data['name'], $this->apiEntities)) { | |
68 | $this->addCustomFields($map, $table, $data['name']); | |
69 | } | |
70 | } | |
19b53e5b C |
71 | } |
72 | ||
73 | /** | |
74 | * @param Table $table | |
75 | * @param string $field | |
76 | * @param array $data | |
77 | */ | |
78 | private function addJoins(Table $table, $field, array $data) { | |
1b8e3bc8 | 79 | $fkClass = $data['FKClassName'] ?? NULL; |
19b53e5b C |
80 | |
81 | // can there be multiple methods e.g. pseudoconstant and fkclass | |
82 | if ($fkClass) { | |
83 | $tableName = AllCoreTables::getTableForClass($fkClass); | |
1b8e3bc8 | 84 | $fkKey = $data['FKKeyColumn'] ?? 'id'; |
2b139d1b CW |
85 | // Backward-compatibility for older api calls using e.g. "contact" instead of "contact_id" |
86 | if (strpos($field, '_id')) { | |
87 | $alias = str_replace('_id', '', $field); | |
88 | $joinable = new Joinable($tableName, $fkKey, $alias); | |
89 | $joinable->setJoinType($joinable::JOIN_TYPE_MANY_TO_ONE); | |
90 | $joinable->setDeprecated(); | |
91 | $table->addTableLink($field, $joinable); | |
92 | } | |
93 | $joinable = new Joinable($tableName, $fkKey, $field); | |
19b53e5b C |
94 | $joinable->setJoinType($joinable::JOIN_TYPE_MANY_TO_ONE); |
95 | $table->addTableLink($field, $joinable); | |
96 | } | |
19b53e5b C |
97 | } |
98 | ||
19b53e5b C |
99 | /** |
100 | * @param \Civi\Api4\Service\Schema\SchemaMap $map | |
101 | * @param \Civi\Api4\Service\Schema\Table $baseTable | |
cbda9790 | 102 | * @param string $entityName |
19b53e5b | 103 | */ |
cbda9790 CW |
104 | private function addCustomFields(SchemaMap $map, Table $baseTable, string $entityName) { |
105 | $customInfo = \Civi\Api4\Utils\CoreUtil::getCustomGroupExtends($entityName); | |
19b53e5b | 106 | // Don't be silly |
cbda9790 | 107 | if (!$customInfo) { |
19b53e5b C |
108 | return; |
109 | } | |
19b53e5b C |
110 | $fieldData = \CRM_Utils_SQL_Select::from('civicrm_custom_field f') |
111 | ->join('custom_group', 'INNER JOIN civicrm_custom_group g ON g.id = f.custom_group_id') | |
1c339746 | 112 | ->select(['g.name as custom_group_name', 'g.table_name', 'g.is_multiple', 'f.name', 'f.data_type', 'label', 'column_name', 'option_group_id', 'serialize']) |
cbda9790 | 113 | ->where('g.extends IN (@entity)', ['@entity' => $customInfo['extends']]) |
19b53e5b C |
114 | ->where('g.is_active') |
115 | ->where('f.is_active') | |
116 | ->execute(); | |
117 | ||
118 | $links = []; | |
119 | ||
120 | while ($fieldData->fetch()) { | |
121 | $tableName = $fieldData->table_name; | |
122 | ||
123 | $customTable = $map->getTableByName($tableName); | |
124 | if (!$customTable) { | |
125 | $customTable = new Table($tableName); | |
126 | } | |
127 | ||
19b53e5b C |
128 | $map->addTable($customTable); |
129 | ||
130 | $alias = $fieldData->custom_group_name; | |
131 | $links[$alias]['tableName'] = $tableName; | |
132 | $links[$alias]['isMultiple'] = !empty($fieldData->is_multiple); | |
133 | $links[$alias]['columns'][$fieldData->name] = $fieldData->column_name; | |
5e327f37 CW |
134 | |
135 | // Add backreference | |
136 | if (!empty($fieldData->is_multiple)) { | |
cbda9790 | 137 | $joinable = new Joinable($baseTable->getName(), $customInfo['column'], AllCoreTables::convertEntityNameToLower($entityName)); |
5e327f37 CW |
138 | $customTable->addTableLink('entity_id', $joinable); |
139 | } | |
ede387bb CW |
140 | |
141 | if ($fieldData->data_type === 'ContactReference') { | |
142 | $joinable = new Joinable('civicrm_contact', 'id', $fieldData->name); | |
1c339746 CW |
143 | if ($fieldData->serialize) { |
144 | $joinable->setSerialize((int) $fieldData->serialize); | |
145 | } | |
ede387bb CW |
146 | $customTable->addTableLink($fieldData->column_name, $joinable); |
147 | } | |
19b53e5b C |
148 | } |
149 | ||
150 | foreach ($links as $alias => $link) { | |
6fe7bdee | 151 | $joinable = new CustomGroupJoinable($link['tableName'], $alias, $link['isMultiple'], $link['columns']); |
cbda9790 | 152 | $baseTable->addTableLink($customInfo['column'], $joinable); |
19b53e5b C |
153 | } |
154 | } | |
155 | ||
156 | } |