3 namespace Civi\Api4\Action\Afform
;
5 use Civi\Api4\CustomField
;
6 use Civi\Api4\CustomGroup
;
7 use CRM_Afform_ExtensionUtil
as E
;
11 * @package Civi\Api4\Action\Afform
13 class Get
extends \Civi\Api4\Generic\BasicGetAction
{
15 use \Civi\Api4\Utils\AfformFormatTrait
;
17 public function getRecords() {
18 /** @var \CRM_Afform_AfformScanner $scanner */
19 $scanner = \Civi
::service('afform_scanner');
20 $getComputed = $this->_isFieldSelected('has_local', 'has_base');
21 $getLayout = $this->_isFieldSelected('layout');
22 $getSearchDisplays = $this->_isFieldSelected('search_displays');
25 // This helps optimize lookups by file/module/directive name
26 $getNames = array_filter([
27 'name' => $this->_itemsToGet('name'),
28 'module_name' => $this->_itemsToGet('module_name'),
29 'directive_name' => $this->_itemsToGet('directive_name'),
31 $getTypes = $this->_itemsToGet('type');
33 $names = $getNames['name'] ??
array_keys($scanner->findFilePaths());
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);
40 if ($this->checkPermissions
) {
41 $names = array_filter($names, [$this, 'checkPermission']);
44 foreach ($names as $name) {
47 'module_name' => _afform_angular_module_name($name, 'camel'),
48 'directive_name' => _afform_angular_module_name($name, 'dash'),
50 // Skip if afform does not match requested name
51 foreach ($getNames as $key => $names) {
52 if (!in_array($info[$key], $names)) {
56 $record = $scanner->getMeta($name);
57 // Skip if afform does not exist or is not of requested type(s)
59 (!$record && !isset($values[$name])) ||
60 ($getTypes && isset($record['type']) && !in_array($record['type'], $getTypes, TRUE))
64 $values[$name] = array_merge($values[$name] ??
[], $record ??
[], $info);
66 $scanner->addComputedFields($values[$name]);
68 if ($getLayout ||
$getSearchDisplays) {
69 // Autogenerated layouts will already be in values but can be overridden; scanner takes priority
70 $values[$name]['layout'] = $scanner->getLayout($name) ??
$values[$name]['layout'] ??
'';
72 if ($getSearchDisplays) {
73 $values[$name]['search_displays'] = $this->getSearchDisplays($values[$name]['layout']);
77 if ($getLayout && $this->layoutFormat
!== 'html') {
78 foreach ($values as $name => $record) {
79 $values[$name]['layout'] = $this->convertHtmlToOutput($record['layout']);
87 * Assert that a form is authorized.
91 protected function checkPermission($name) {
92 return \CRM_Core_Permission
::check("@afform:$name");
96 * Generates afform blocks from custom field sets.
99 * @param array $getNames
100 * @param bool $getLayout
102 * @throws \API_Exception
104 protected function getAutoGenerated(&$names, $getNames, $getLayout) {
105 $values = $groupNames = [];
106 foreach ($getNames['name'] ??
[] as $name) {
107 if (strpos($name, 'afblockCustom_') === 0 && strlen($name) > 13) {
108 $groupNames[] = substr($name, 14);
111 // Early return if this api call is fetching afforms by name and those names are not custom-related
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'))
118 $customApi = CustomGroup
::get(FALSE)
119 ->addSelect('name', 'title', 'help_pre', 'help_post', 'extends', 'max_multiple')
120 ->addWhere('is_multiple', '=', 1)
121 ->addWhere('is_active', '=', 1);
123 $customApi->addWhere('name', 'IN', $groupNames);
126 $customApi->addSelect('help_pre', 'help_post');
127 $customApi->addChain('fields', CustomField
::get(FALSE)
129 ->addWhere('custom_group_id', '=', '$id')
130 ->addWhere('is_active', '=', 1)
131 ->addOrderBy('weight', 'ASC')
134 foreach ($customApi->execute() as $custom) {
135 $name = 'afblockCustom_' . $custom['name'];
136 if (!in_array($name, $names)) {
143 'title' => E
::ts('%1 block', [1 => $custom['title']]),
145 'is_dashlet' => FALSE,
146 'is_public' => FALSE,
148 'permission' => 'access CiviCRM',
149 'join_entity' => 'Custom_' . $custom['name'],
150 'entity_type' => $custom['extends'],
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";
158 $item['layout'] .= ($custom['help_post'] ?
'<div class="af-markup">' . $custom['help_post'] . "</div>\n" : '');
160 $values[$name] = $item;
166 * Find search display tags in afform markup
168 * @param string $html
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);
177 // Note: display name will be blank when using the default (autogenerated) display
178 preg_match('/display-name\\s*=\\s*[\'"]([^\'"]+)[\'"]/', $tag, $displayName);
179 if (!empty($searchName[1])) {
180 $searchDisplays[] = $searchName[1] . (empty($displayName[1]) ?
'' : '.' . $displayName[1]);
183 return $searchDisplays;