SearchKit - Expose default display to the UI
[civicrm-core.git] / ext / afform / core / Civi / Api4 / Action / Afform / Get.php
CommitLineData
11e724f0
TO
1<?php
2
3namespace Civi\Api4\Action\Afform;
4
9c84a124
CW
5use Civi\Api4\CustomField;
6use Civi\Api4\CustomGroup;
67d666c6 7use CRM_Afform_ExtensionUtil as E;
9c84a124 8
11e724f0 9/**
28b4ace4 10 * @inheritDoc
11e724f0
TO
11 * @package Civi\Api4\Action\Afform
12 */
28b4ace4 13class Get extends \Civi\Api4\Generic\BasicGetAction {
11e724f0 14
28b4ace4 15 use \Civi\Api4\Utils\AfformFormatTrait;
11e724f0
TO
16
17 public function getRecords() {
18 /** @var \CRM_Afform_AfformScanner $scanner */
19 $scanner = \Civi::service('afform_scanner');
60a62215 20 $getComputed = $this->_isFieldSelected('has_local', 'has_base');
9c84a124 21 $getLayout = $this->_isFieldSelected('layout');
b076c308 22 $getSearchDisplays = $this->_isFieldSelected('search_displays');
2ca6eeda 23 $values = [];
9c84a124 24
edf837b4 25 // This helps optimize lookups by file/module/directive name
2ca6eeda 26 $getNames = array_filter([
edf837b4
CW
27 'name' => $this->_itemsToGet('name'),
28 'module_name' => $this->_itemsToGet('module_name'),
29 'directive_name' => $this->_itemsToGet('directive_name'),
30 ]);
2ca6eeda 31 $getTypes = $this->_itemsToGet('type');
11e724f0 32
2ca6eeda 33 $names = $getNames['name'] ?? array_keys($scanner->findFilePaths());
25f2b36b 34
2ca6eeda
CW
35 // Get autogenerated blocks if type block is not excluded
36 if (!$getTypes || in_array('block', $getTypes, TRUE)) {
37 $values = $this->getAutoGenerated($names, $getNames, $getLayout);
38 }
11e724f0 39
48be26b0
CW
40 if ($this->checkPermissions) {
41 $names = array_filter($names, [$this, 'checkPermission']);
42 }
43
11e724f0 44 foreach ($names as $name) {
25f2b36b 45 $info = [
edf837b4 46 'name' => $name,
25f2b36b
CW
47 'module_name' => _afform_angular_module_name($name, 'camel'),
48 'directive_name' => _afform_angular_module_name($name, 'dash'),
49 ];
2ca6eeda
CW
50 // Skip if afform does not match requested name
51 foreach ($getNames as $key => $names) {
52 if (!in_array($info[$key], $names)) {
fa8dc3f2 53 continue 2;
edf837b4 54 }
25f2b36b 55 }
11e724f0 56 $record = $scanner->getMeta($name);
2ca6eeda
CW
57 // Skip if afform does not exist or is not of requested type(s)
58 if (
59 (!$record && !isset($values[$name])) ||
a003d5f7 60 ($getTypes && isset($record['type']) && !in_array($record['type'], $getTypes, TRUE))
2ca6eeda 61 ) {
9c84a124
CW
62 continue;
63 }
25f2b36b 64 $values[$name] = array_merge($values[$name] ?? [], $record ?? [], $info);
9c84a124
CW
65 if ($getComputed) {
66 $scanner->addComputedFields($values[$name]);
1aebf5b0 67 }
b076c308 68 if ($getLayout || $getSearchDisplays) {
236719c6 69 // Autogenerated layouts will already be in values but can be overridden; scanner takes priority
9c84a124 70 $values[$name]['layout'] = $scanner->getLayout($name) ?? $values[$name]['layout'] ?? '';
11e724f0 71 }
b076c308
CW
72 if ($getSearchDisplays) {
73 $values[$name]['search_displays'] = $this->getSearchDisplays($values[$name]['layout']);
74 }
11e724f0
TO
75 }
76
9c84a124
CW
77 if ($getLayout && $this->layoutFormat !== 'html') {
78 foreach ($values as $name => $record) {
79 $values[$name]['layout'] = $this->convertHtmlToOutput($record['layout']);
80 }
81 }
82
83 return $values;
84 }
85
48be26b0
CW
86 /**
87 * Assert that a form is authorized.
88 *
89 * @return bool
90 */
91 protected function checkPermission($name) {
92 return \CRM_Core_Permission::check("@afform:$name");
93 }
94
9c84a124
CW
95 /**
96 * Generates afform blocks from custom field sets.
97 *
2ca6eeda
CW
98 * @param array $names
99 * @param array $getNames
100 * @param bool $getLayout
9c84a124
CW
101 * @return array
102 * @throws \API_Exception
103 */
2ca6eeda 104 protected function getAutoGenerated(&$names, $getNames, $getLayout) {
9c84a124 105 $values = $groupNames = [];
2ca6eeda 106 foreach ($getNames['name'] ?? [] as $name) {
fa8dc3f2
CW
107 if (strpos($name, 'afblockCustom_') === 0 && strlen($name) > 13) {
108 $groupNames[] = substr($name, 14);
9c84a124
CW
109 }
110 }
c3273f01 111 // Early return if this api call is fetching afforms by name and those names are not custom-related
2ca6eeda
CW
112 if ((!empty($getNames['name']) && !$groupNames)
113 || (!empty($getNames['module_name']) && !strstr(implode(' ', $getNames['module_name']), 'afblockCustom'))
114 || (!empty($getNames['directive_name']) && !strstr(implode(' ', $getNames['directive_name']), 'afblock-custom'))
edf837b4 115 ) {
9c84a124
CW
116 return $values;
117 }
2ca6eeda 118 $customApi = CustomGroup::get(FALSE)
83412ba5 119 ->addSelect('name', 'title', 'help_pre', 'help_post', 'extends', 'max_multiple')
9c84a124
CW
120 ->addWhere('is_multiple', '=', 1)
121 ->addWhere('is_active', '=', 1);
122 if ($groupNames) {
123 $customApi->addWhere('name', 'IN', $groupNames);
124 }
125 if ($getLayout) {
83412ba5
CW
126 $customApi->addSelect('help_pre', 'help_post');
127 $customApi->addChain('fields', CustomField::get(FALSE)
9c84a124
CW
128 ->addSelect('name')
129 ->addWhere('custom_group_id', '=', '$id')
130 ->addWhere('is_active', '=', 1)
131 ->addOrderBy('weight', 'ASC')
132 );
133 }
134 foreach ($customApi->execute() as $custom) {
fa8dc3f2 135 $name = 'afblockCustom_' . $custom['name'];
9c84a124
CW
136 if (!in_array($name, $names)) {
137 $names[] = $name;
138 }
139 $item = [
140 'name' => $name,
b1335297 141 'type' => 'block',
9c84a124 142 'requires' => [],
fa8dc3f2 143 'title' => E::ts('%1 block', [1 => $custom['title']]),
9c84a124 144 'description' => '',
1887d8bd 145 'is_dashlet' => FALSE,
9c84a124 146 'is_public' => FALSE,
053ab2a5 147 'is_token' => FALSE,
9c84a124 148 'permission' => 'access CiviCRM',
fa8dc3f2
CW
149 'join_entity' => 'Custom_' . $custom['name'],
150 'entity_type' => $custom['extends'],
9c84a124
CW
151 'has_base' => TRUE,
152 ];
153 if ($getLayout) {
154 $item['layout'] = ($custom['help_pre'] ? '<div class="af-markup">' . $custom['help_pre'] . "</div>\n" : '');
155 foreach ($custom['fields'] as $field) {
156 $item['layout'] .= "<af-field name=\"{$field['name']}\" />\n";
157 }
158 $item['layout'] .= ($custom['help_post'] ? '<div class="af-markup">' . $custom['help_post'] . "</div>\n" : '');
159 }
160 $values[$name] = $item;
161 }
11e724f0
TO
162 return $values;
163 }
164
b076c308
CW
165 /**
166 * Find search display tags in afform markup
167 *
168 * @param string $html
169 * @return string[]
170 */
171 private function getSearchDisplays(string $html) {
172 $tags = $searchDisplays = [];
173 preg_match_all('/<\\s*crm-search-display[^>]+>/', $html, $tags);
174 foreach ($tags[0] ?? [] as $tag) {
175 $searchName = $displayName = [];
176 preg_match('/search-name\\s*=\\s*[\'"]([^\'"]+)[\'"]/', $tag, $searchName);
5c952e51 177 // Note: display name will be blank when using the default (autogenerated) display
b076c308 178 preg_match('/display-name\\s*=\\s*[\'"]([^\'"]+)[\'"]/', $tag, $displayName);
5c952e51
CW
179 if (!empty($searchName[1])) {
180 $searchDisplays[] = $searchName[1] . (empty($displayName[1]) ? '' : '.' . $displayName[1]);
b076c308
CW
181 }
182 }
183 return $searchDisplays;
184 }
185
11e724f0 186}