Commit | Line | Data |
---|---|---|
66aa0f5e TO |
1 | <?php |
2 | ||
3 | require_once 'afform.civix.php'; | |
4 | use CRM_Afform_ExtensionUtil as E; | |
5 | ||
bc3b7c5b TO |
6 | /** |
7 | * Filter the content of $params to only have supported afform fields. | |
8 | * | |
9 | * @param array $params | |
10 | * @return array | |
11 | */ | |
12 | function _afform_fields_filter($params) { | |
5591cfbf | 13 | $result = []; |
67d666c6 | 14 | $fields = \Civi\Api4\Afform::getfields(FALSE)->setAction('create')->execute()->indexBy('name'); |
50868e8d CW |
15 | foreach ($fields as $fieldName => $field) { |
16 | if (isset($params[$fieldName])) { | |
17 | $result[$fieldName] = $params[$fieldName]; | |
d1ec770c | 18 | |
e38db494 CW |
19 | if ($field['data_type'] === 'Boolean' && !is_bool($params[$fieldName])) { |
20 | $result[$fieldName] = CRM_Utils_String::strtobool($params[$fieldName]); | |
d1ec770c TO |
21 | } |
22 | } | |
bc3b7c5b TO |
23 | } |
24 | return $result; | |
25 | } | |
26 | ||
8f4a0ee9 | 27 | /** |
5591cfbf | 28 | * @param \Symfony\Component\DependencyInjection\ContainerBuilder $container |
8f4a0ee9 TO |
29 | */ |
30 | function afform_civicrm_container($container) { | |
77dccccb | 31 | $container->addResource(new \Symfony\Component\Config\Resource\FileResource(__FILE__)); |
8f4a0ee9 TO |
32 | $container->setDefinition('afform_scanner', new \Symfony\Component\DependencyInjection\Definition( |
33 | 'CRM_Afform_AfformScanner', | |
5591cfbf | 34 | [] |
b53fe171 | 35 | ))->setPublic(TRUE); |
8f4a0ee9 TO |
36 | } |
37 | ||
66aa0f5e TO |
38 | /** |
39 | * Implements hook_civicrm_config(). | |
40 | * | |
41 | * @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_config | |
42 | */ | |
43 | function afform_civicrm_config(&$config) { | |
44 | _afform_civix_civicrm_config($config); | |
77dccccb TO |
45 | |
46 | if (isset(Civi::$statics[__FUNCTION__])) { | |
47 | return; | |
48 | } | |
49 | Civi::$statics[__FUNCTION__] = 1; | |
50 | ||
b7edd04e | 51 | $dispatcher = Civi::dispatcher(); |
07a1bc45 A |
52 | $dispatcher->addListener('civi.afform.submit', ['\Civi\Api4\Action\Afform\Submit', 'processGenericEntity'], 0); |
53 | $dispatcher->addListener('civi.afform.submit', ['\Civi\Api4\Action\Afform\Submit', 'preprocessContact'], 10); | |
e1f79950 | 54 | $dispatcher->addListener('civi.afform.submit', ['\Civi\Api4\Action\Afform\Submit', 'processRelationships'], 1); |
b7edd04e TO |
55 | $dispatcher->addListener('hook_civicrm_angularModules', ['\Civi\Afform\AngularDependencyMapper', 'autoReq'], -1000); |
56 | $dispatcher->addListener('hook_civicrm_alterAngular', ['\Civi\Afform\AfformMetadataInjector', 'preprocess']); | |
bdceaf62 | 57 | $dispatcher->addListener('hook_civicrm_check', ['\Civi\Afform\StatusChecks', 'hook_civicrm_check']); |
92a43aef | 58 | $dispatcher->addListener('civi.afform.get', ['\Civi\Api4\Action\Afform\Get', 'getCustomGroupBlocks']); |
b7edd04e TO |
59 | |
60 | // Register support for email tokens | |
bdceaf62 TO |
61 | if (CRM_Extension_System::singleton()->getMapper()->isActiveModule('authx')) { |
62 | $dispatcher->addListener('hook_civicrm_alterMailContent', ['\Civi\Afform\Tokens', 'applyCkeditorWorkaround']); | |
63 | $dispatcher->addListener('hook_civicrm_tokens', ['\Civi\Afform\Tokens', 'hook_civicrm_tokens']); | |
64 | $dispatcher->addListener('hook_civicrm_tokenValues', ['\Civi\Afform\Tokens', 'hook_civicrm_tokenValues']); | |
65 | } | |
66aa0f5e TO |
66 | } |
67 | ||
66aa0f5e TO |
68 | /** |
69 | * Implements hook_civicrm_install(). | |
70 | * | |
71 | * @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_install | |
72 | */ | |
73 | function afform_civicrm_install() { | |
74 | _afform_civix_civicrm_install(); | |
75 | } | |
76 | ||
77 | /** | |
78 | * Implements hook_civicrm_postInstall(). | |
79 | * | |
80 | * @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_postInstall | |
81 | */ | |
82 | function afform_civicrm_postInstall() { | |
83 | _afform_civix_civicrm_postInstall(); | |
84 | } | |
85 | ||
86 | /** | |
87 | * Implements hook_civicrm_uninstall(). | |
88 | * | |
89 | * @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_uninstall | |
90 | */ | |
91 | function afform_civicrm_uninstall() { | |
92 | _afform_civix_civicrm_uninstall(); | |
93 | } | |
94 | ||
95 | /** | |
96 | * Implements hook_civicrm_enable(). | |
97 | * | |
98 | * @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_enable | |
99 | */ | |
100 | function afform_civicrm_enable() { | |
101 | _afform_civix_civicrm_enable(); | |
102 | } | |
103 | ||
104 | /** | |
105 | * Implements hook_civicrm_disable(). | |
106 | * | |
107 | * @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_disable | |
108 | */ | |
109 | function afform_civicrm_disable() { | |
110 | _afform_civix_civicrm_disable(); | |
111 | } | |
112 | ||
113 | /** | |
114 | * Implements hook_civicrm_upgrade(). | |
115 | * | |
116 | * @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_upgrade | |
117 | */ | |
118 | function afform_civicrm_upgrade($op, CRM_Queue_Queue $queue = NULL) { | |
119 | return _afform_civix_civicrm_upgrade($op, $queue); | |
120 | } | |
121 | ||
122 | /** | |
123 | * Implements hook_civicrm_managed(). | |
124 | * | |
125 | * Generate a list of entities to create/deactivate/delete when this module | |
126 | * is installed, disabled, uninstalled. | |
127 | * | |
128 | * @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_managed | |
129 | */ | |
fdc67a75 TO |
130 | function afform_civicrm_managed(&$entities, $modules) { |
131 | if ($modules && !in_array(E::LONG_NAME, $modules, TRUE)) { | |
132 | return; | |
133 | } | |
521b232a TO |
134 | /** @var \CRM_Afform_AfformScanner $scanner */ |
135 | if (\Civi::container()->has('afform_scanner')) { | |
136 | $scanner = \Civi::service('afform_scanner'); | |
137 | } | |
138 | else { | |
139 | // This might happen at oddballs points - e.g. while you're in the middle of re-enabling the ext. | |
140 | // This AfformScanner instance only lives during this method call, and it feeds off the regular cache. | |
141 | $scanner = new CRM_Afform_AfformScanner(); | |
142 | } | |
143 | ||
144 | foreach ($scanner->getMetas() as $afform) { | |
145 | if (empty($afform['is_dashlet']) || empty($afform['name'])) { | |
146 | continue; | |
147 | } | |
148 | $entities[] = [ | |
149 | 'module' => E::LONG_NAME, | |
150 | 'name' => 'afform_dashlet_' . $afform['name'], | |
151 | 'entity' => 'Dashboard', | |
152 | 'update' => 'always', | |
153 | // ideal cleanup policy might be to (a) deactivate if used and (b) remove if unused | |
154 | 'cleanup' => 'always', | |
155 | 'params' => [ | |
9bed436a CW |
156 | 'version' => 4, |
157 | 'values' => [ | |
158 | // Q: Should we loop through all domains? | |
159 | 'domain_id' => 'current_domain', | |
160 | 'is_active' => TRUE, | |
161 | 'name' => $afform['name'], | |
162 | 'label' => $afform['title'] ?? E::ts('(Untitled)'), | |
163 | 'directive' => _afform_angular_module_name($afform['name'], 'dash'), | |
164 | 'permission' => "@afform:" . $afform['name'], | |
165 | 'url' => NULL, | |
166 | ], | |
521b232a TO |
167 | ], |
168 | ]; | |
169 | } | |
66aa0f5e TO |
170 | } |
171 | ||
172 | /** | |
c63f20d3 | 173 | * Implements hook_civicrm_tabset(). |
66aa0f5e | 174 | * |
c63f20d3 CW |
175 | * Adds afforms as contact summary tabs. |
176 | */ | |
177 | function afform_civicrm_tabset($tabsetName, &$tabs, $context) { | |
178 | if ($tabsetName !== 'civicrm/contact/view') { | |
179 | return; | |
180 | } | |
181 | $scanner = \Civi::service('afform_scanner'); | |
182 | $weight = 111; | |
183 | foreach ($scanner->getMetas() as $afform) { | |
184 | if (!empty($afform['contact_summary']) && $afform['contact_summary'] === 'tab') { | |
185 | $module = _afform_angular_module_name($afform['name']); | |
186 | $tabs[] = [ | |
187 | 'id' => $afform['name'], | |
188 | 'title' => $afform['title'], | |
189 | 'weight' => $weight++, | |
190 | 'icon' => 'crm-i fa-list-alt', | |
191 | 'is_active' => TRUE, | |
192 | 'template' => 'afform/contactSummary/AfformTab.tpl', | |
193 | 'module' => $module, | |
194 | 'directive' => _afform_angular_module_name($afform['name'], 'dash'), | |
195 | ]; | |
196 | // If this is the real contact summary page (and not a callback from ContactLayoutEditor), load module. | |
197 | if (empty($context['caller'])) { | |
198 | Civi::service('angularjs.loader')->addModules($module); | |
199 | } | |
200 | } | |
201 | } | |
202 | } | |
203 | ||
204 | /** | |
205 | * Implements hook_civicrm_pageRun(). | |
66aa0f5e | 206 | * |
c63f20d3 CW |
207 | * Adds afforms as contact summary blocks. |
208 | */ | |
209 | function afform_civicrm_pageRun(&$page) { | |
210 | if (get_class($page) !== 'CRM_Contact_Page_View_Summary') { | |
211 | return; | |
212 | } | |
213 | $scanner = \Civi::service('afform_scanner'); | |
214 | $cid = $page->get('cid'); | |
215 | $side = 'left'; | |
216 | foreach ($scanner->getMetas() as $afform) { | |
217 | if (!empty($afform['contact_summary']) && $afform['contact_summary'] === 'block') { | |
218 | $module = _afform_angular_module_name($afform['name']); | |
219 | $block = [ | |
220 | 'module' => $module, | |
221 | 'directive' => _afform_angular_module_name($afform['name'], 'dash'), | |
222 | ]; | |
223 | $content = CRM_Core_Smarty::singleton()->fetchWith('afform/contactSummary/AfformBlock.tpl', ['contactId' => $cid, 'block' => $block]); | |
224 | CRM_Core_Region::instance("contact-basic-info-$side")->add([ | |
225 | 'markup' => '<div class="crm-summary-block">' . $content . '</div>', | |
226 | 'weight' => 1, | |
227 | ]); | |
228 | Civi::service('angularjs.loader')->addModules($module); | |
229 | $side = $side === 'left' ? 'right' : 'left'; | |
230 | } | |
231 | } | |
232 | } | |
233 | ||
234 | /** | |
235 | * Implements hook_civicrm_contactSummaryBlocks(). | |
66aa0f5e | 236 | * |
c63f20d3 | 237 | * @link https://github.com/civicrm/org.civicrm.contactlayout |
66aa0f5e | 238 | */ |
c63f20d3 | 239 | function afform_civicrm_contactSummaryBlocks(&$blocks) { |
4f664e9c CW |
240 | $afforms = \Civi\Api4\Afform::get(FALSE) |
241 | ->setSelect(['name', 'title', 'directive_name', 'module_name', 'type', 'type:icon', 'type:label']) | |
242 | ->addWhere('contact_summary', '=', 'block') | |
243 | ->execute(); | |
4096e4b0 | 244 | foreach ($afforms as $index => $afform) { |
4f664e9c CW |
245 | // Create a group per afform type |
246 | $blocks += [ | |
247 | "afform_{$afform['type']}" => [ | |
248 | 'title' => $afform['type:label'], | |
249 | 'icon' => $afform['type:icon'], | |
250 | 'blocks' => [], | |
251 | ], | |
252 | ]; | |
253 | $blocks["afform_{$afform['type']}"]['blocks'][$afform['name']] = [ | |
254 | 'title' => $afform['title'], | |
255 | 'tpl_file' => 'afform/contactSummary/AfformBlock.tpl', | |
256 | 'module' => $afform['module_name'], | |
257 | 'directive' => $afform['directive_name'], | |
258 | 'sample' => [ | |
259 | $afform['type:label'], | |
260 | ], | |
261 | 'edit' => 'civicrm/admin/afform#/edit/' . $afform['name'], | |
4096e4b0 | 262 | 'system_default' => [0, $index % 2], |
4f664e9c | 263 | ]; |
c63f20d3 | 264 | } |
66aa0f5e TO |
265 | } |
266 | ||
267 | /** | |
268 | * Implements hook_civicrm_angularModules(). | |
269 | * | |
e1aca853 | 270 | * Generate a list of Afform Angular modules. |
66aa0f5e TO |
271 | */ |
272 | function afform_civicrm_angularModules(&$angularModules) { | |
5e04a2d4 | 273 | $afforms = \Civi\Api4\Afform::get(FALSE) |
e38db494 | 274 | ->setSelect(['name', 'requires', 'module_name', 'directive_name']) |
2d4bfef1 CW |
275 | ->execute(); |
276 | ||
277 | foreach ($afforms as $afform) { | |
e38db494 | 278 | $angularModules[$afform['module_name']] = [ |
bb56ac78 | 279 | 'ext' => E::LONG_NAME, |
2d4bfef1 CW |
280 | 'js' => ['assetBuilder://afform.js?name=' . urlencode($afform['name'])], |
281 | 'requires' => $afform['requires'], | |
bb56ac78 | 282 | 'basePages' => [], |
aa6abb77 | 283 | 'partialsCallback' => '_afform_get_partials', |
2d4bfef1 | 284 | '_afform' => $afform['name'], |
292054ac CW |
285 | // TODO: Allow afforms to declare their own theming requirements |
286 | 'bundles' => ['bootstrap3'], | |
77dccccb | 287 | 'exports' => [ |
04417491 | 288 | $afform['directive_name'] => 'E', |
77dccccb | 289 | ], |
bb56ac78 | 290 | ]; |
bb56ac78 | 291 | } |
66aa0f5e TO |
292 | } |
293 | ||
aa6abb77 | 294 | /** |
2d4bfef1 CW |
295 | * Callback to retrieve partials for a given afform/angular module. |
296 | * | |
297 | * @see afform_civicrm_angularModules | |
aa6abb77 TO |
298 | * |
299 | * @param string $moduleName | |
300 | * The module name. | |
301 | * @param array $module | |
302 | * The module definition. | |
303 | * @return array | |
304 | * Array(string $filename => string $html). | |
2d4bfef1 | 305 | * @throws API_Exception |
aa6abb77 TO |
306 | */ |
307 | function _afform_get_partials($moduleName, $module) { | |
2d4bfef1 CW |
308 | $afform = civicrm_api4('Afform', 'get', [ |
309 | 'where' => [['name', '=', $module['_afform']]], | |
310 | 'select' => ['layout'], | |
311 | 'layoutFormat' => 'html', | |
312 | 'checkPermissions' => FALSE, | |
313 | ], 0); | |
aa6abb77 | 314 | return [ |
2d4bfef1 | 315 | "~/$moduleName/$moduleName.aff.html" => $afform['layout'], |
aa6abb77 TO |
316 | ]; |
317 | } | |
318 | ||
66aa0f5e TO |
319 | /** |
320 | * Implements hook_civicrm_entityTypes(). | |
321 | * | |
322 | * Declare entity types provided by this module. | |
323 | * | |
324 | * @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_entityTypes | |
325 | */ | |
326 | function afform_civicrm_entityTypes(&$entityTypes) { | |
327 | _afform_civix_civicrm_entityTypes($entityTypes); | |
328 | } | |
329 | ||
bb56ac78 TO |
330 | /** |
331 | * Implements hook_civicrm_buildAsset(). | |
332 | */ | |
333 | function afform_civicrm_buildAsset($asset, $params, &$mimeType, &$content) { | |
334 | if ($asset !== 'afform.js') { | |
335 | return; | |
336 | } | |
337 | ||
338 | if (empty($params['name'])) { | |
339 | throw new RuntimeException("Missing required parameter: afform.js?name=NAME"); | |
340 | } | |
341 | ||
2d4bfef1 | 342 | $moduleName = _afform_angular_module_name($params['name'], 'camel'); |
b6e13973 SL |
343 | $formMetaData = (array) civicrm_api4('Afform', 'get', [ |
344 | 'checkPermissions' => FALSE, | |
007167df | 345 | 'select' => ['redirect', 'name', 'title'], |
b6e13973 SL |
346 | 'where' => [['name', '=', $params['name']]], |
347 | ], 0); | |
bb56ac78 TO |
348 | $smarty = CRM_Core_Smarty::singleton(); |
349 | $smarty->assign('afform', [ | |
aa6abb77 | 350 | 'camel' => $moduleName, |
b6e13973 | 351 | 'meta' => $formMetaData, |
aa6abb77 | 352 | 'templateUrl' => "~/$moduleName/$moduleName.aff.html", |
bb56ac78 TO |
353 | ]); |
354 | $mimeType = 'text/javascript'; | |
9ec944f2 | 355 | $content = $smarty->fetch('afform/AfformAngularModule.tpl'); |
bb56ac78 TO |
356 | } |
357 | ||
8775c48a TO |
358 | /** |
359 | * Implements hook_civicrm_alterMenu(). | |
360 | */ | |
361 | function afform_civicrm_alterMenu(&$items) { | |
92a43aef CW |
362 | try { |
363 | $afforms = \Civi\Api4\Afform::get(FALSE) | |
364 | ->addWhere('server_route', 'IS NOT EMPTY') | |
365 | ->addSelect('name', 'server_route', 'is_public') | |
366 | ->execute()->indexBy('name'); | |
8f4a0ee9 | 367 | } |
92a43aef | 368 | catch (Exception $e) { |
8f4a0ee9 TO |
369 | // During installation... |
370 | $scanner = new CRM_Afform_AfformScanner(); | |
92a43aef | 371 | $afforms = $scanner->getMetas(); |
8f4a0ee9 | 372 | } |
92a43aef | 373 | foreach ($afforms as $name => $meta) { |
8775c48a TO |
374 | if (!empty($meta['server_route'])) { |
375 | $items[$meta['server_route']] = [ | |
376 | 'page_callback' => 'CRM_Afform_Page_AfformBase', | |
377 | 'page_arguments' => 'afform=' . urlencode($name), | |
f16b2aee | 378 | 'access_arguments' => [["@afform:$name"], 'and'], |
254f01f0 | 379 | 'is_public' => $meta['is_public'], |
8775c48a TO |
380 | ]; |
381 | } | |
382 | } | |
f16b2aee TO |
383 | } |
384 | ||
92d6b3d4 CW |
385 | /** |
386 | * Implements hook_civicrm_permission(). | |
387 | * | |
388 | * Define Afform permissions. | |
389 | */ | |
390 | function afform_civicrm_permission(&$permissions) { | |
391 | $permissions['administer afform'] = [ | |
392 | E::ts('Form Builder: edit and delete forms'), | |
393 | E::ts('Allows non-admin users to create, update and delete forms'), | |
394 | ]; | |
395 | } | |
396 | ||
f16b2aee TO |
397 | /** |
398 | * Implements hook_civicrm_permission_check(). | |
399 | * | |
586344a7 TO |
400 | * This extends the list of permissions available in `CRM_Core_Permission:check()` |
401 | * by introducing virtual-permissions named `@afform:myForm`. The evaluation | |
402 | * of these virtual-permissions is dependent on the settings for `myForm`. | |
403 | * `myForm` may be exposed/integrated through multiple subsystems (routing, | |
404 | * nav-menu, API, etc), and the use of virtual-permissions makes easy to enforce | |
405 | * consistent permissions across any relevant subsystems. | |
406 | * | |
f16b2aee TO |
407 | * @see CRM_Utils_Hook::permission_check() |
408 | */ | |
409 | function afform_civicrm_permission_check($permission, &$granted, $contactId) { | |
14b26ac5 | 410 | if ($permission[0] !== '@') { |
f16b2aee TO |
411 | // Micro-optimization - this function may get hit a lot. |
412 | return; | |
413 | } | |
414 | ||
415 | if (preg_match('/^@afform:(.*)/', $permission, $m)) { | |
416 | $name = $m[1]; | |
417 | ||
2d4bfef1 CW |
418 | $afform = \Civi\Api4\Afform::get() |
419 | ->setCheckPermissions(FALSE) | |
420 | ->addWhere('name', '=', $name) | |
421 | ->setSelect(['permission']) | |
422 | ->execute() | |
423 | ->first(); | |
424 | if ($afform) { | |
425 | $granted = CRM_Core_Permission::check($afform['permission'], $contactId); | |
426 | } | |
f16b2aee | 427 | } |
8775c48a TO |
428 | } |
429 | ||
c4e6b413 TO |
430 | /** |
431 | * Implements hook_civicrm_permissionList(). | |
432 | * | |
433 | * @see CRM_Utils_Hook::permissionList() | |
434 | */ | |
435 | function afform_civicrm_permissionList(&$permissions) { | |
436 | $scanner = Civi::service('afform_scanner'); | |
437 | foreach ($scanner->getMetas() as $name => $meta) { | |
438 | $permissions['@afform:' . $name] = [ | |
439 | 'group' => 'afform', | |
67d666c6 | 440 | 'title' => E::ts('Afform: Inherit permission of %1', [ |
c4e6b413 TO |
441 | 1 => $name, |
442 | ]), | |
443 | ]; | |
444 | } | |
445 | } | |
446 | ||
74f862e4 TO |
447 | /** |
448 | * Clear any local/in-memory caches based on afform data. | |
449 | */ | |
450 | function _afform_clear() { | |
451 | $container = \Civi::container(); | |
452 | $container->get('afform_scanner')->clear(); | |
76b9562a | 453 | $container->get('angular')->clear(); |
74f862e4 TO |
454 | } |
455 | ||
bb56ac78 | 456 | /** |
87dde5eb TO |
457 | * @param string $fileBaseName |
458 | * Ex: foo-bar | |
841850b1 TO |
459 | * @param string $format |
460 | * 'camel' or 'dash'. | |
bb56ac78 | 461 | * @return string |
841850b1 | 462 | * Ex: 'FooBar' or 'foo-bar'. |
3cd5c38b | 463 | * @throws \Exception |
bb56ac78 | 464 | */ |
87dde5eb | 465 | function _afform_angular_module_name($fileBaseName, $format = 'camel') { |
841850b1 TO |
466 | switch ($format) { |
467 | case 'camel': | |
87dde5eb | 468 | $camelCase = ''; |
9c84a124 | 469 | foreach (preg_split('/[-_ ]/', $fileBaseName, NULL, PREG_SPLIT_NO_EMPTY) as $shortNamePart) { |
87dde5eb TO |
470 | $camelCase .= ucfirst($shortNamePart); |
471 | } | |
14b26ac5 | 472 | return strtolower($camelCase[0]) . substr($camelCase, 1); |
841850b1 TO |
473 | |
474 | case 'dash': | |
9c84a124 | 475 | return strtolower(implode('-', preg_split('/[-_ ]|(?=[A-Z])/', $fileBaseName, NULL, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE))); |
841850b1 TO |
476 | |
477 | default: | |
478 | throw new \Exception("Unrecognized format"); | |
479 | } | |
bb56ac78 | 480 | } |
355881ac SL |
481 | |
482 | /** | |
483 | * Implements hook_civicrm_alterApiRoutePermissions(). | |
484 | * | |
485 | * @see CRM_Utils_Hook::alterApiRoutePermissions | |
486 | */ | |
487 | function afform_civicrm_alterApiRoutePermissions(&$permissions, $entity, $action) { | |
f362c531 | 488 | if ($entity == 'Afform') { |
db393580 CW |
489 | // These actions should be accessible to anonymous users; permissions are checked internally |
490 | $allowedActions = ['prefill', 'submit', 'submitFile', 'getOptions']; | |
491 | if (in_array($action, $allowedActions, TRUE)) { | |
f362c531 TO |
492 | $permissions = CRM_Core_Permission::ALWAYS_ALLOW_PERMISSION; |
493 | } | |
355881ac SL |
494 | } |
495 | } | |
f228ad74 CW |
496 | |
497 | /** | |
498 | * Implements hook_civicrm_preProcess(). | |
499 | * | |
500 | * Wordpress only: Adds Afforms to the shortcode dialog (when editing pages/posts). | |
501 | */ | |
502 | function afform_civicrm_preProcess($formName, &$form) { | |
503 | if ($formName === 'CRM_Core_Form_ShortCode') { | |
504 | $form->components['afform'] = [ | |
505 | 'label' => E::ts('Form Builder'), | |
506 | 'select' => [ | |
507 | 'key' => 'name', | |
508 | 'entity' => 'Afform', | |
509 | 'select' => ['minimumInputLength' => 0], | |
510 | 'api' => [ | |
511 | 'params' => ['type' => ['IN' => ['form', 'search']]], | |
512 | ], | |
513 | ], | |
514 | ]; | |
515 | } | |
516 | } | |
517 | ||
1c3d1f8d CW |
518 | /** |
519 | * Implements hook_civicrm_pre(). | |
520 | */ | |
521 | function afform_civicrm_pre($op, $entity, $id, &$params) { | |
522 | // When deleting a searchDisplay, also delete any Afforms the display is embedded within | |
523 | if ($entity === 'SearchDisplay' && $op === 'delete') { | |
524 | $display = \Civi\Api4\SearchDisplay::get(FALSE) | |
525 | ->addSelect('saved_search_id.name', 'name') | |
526 | ->addWhere('id', '=', $id) | |
527 | ->execute()->first(); | |
528 | \Civi\Api4\Afform::revert(FALSE) | |
529 | ->addWhere('search_displays', 'CONTAINS', $display['saved_search_id.name'] . ".{$display['name']}") | |
530 | ->execute(); | |
531 | } | |
04309075 | 532 | // When deleting a savedSearch, delete any Afforms which use the default display |
b6553656 | 533 | elseif ($entity === 'SavedSearch' && $op === 'delete') { |
04309075 CW |
534 | $search = \Civi\Api4\SavedSearch::get(FALSE) |
535 | ->addSelect('name') | |
536 | ->addWhere('id', '=', $id) | |
537 | ->execute()->first(); | |
538 | \Civi\Api4\Afform::revert(FALSE) | |
539 | ->addWhere('search_displays', 'CONTAINS', $search['name']) | |
540 | ->execute(); | |
541 | } | |
542 | } | |
543 | ||
544 | /** | |
545 | * Implements hook_civicrm_referenceCounts(). | |
546 | */ | |
547 | function afform_civicrm_referenceCounts($dao, &$counts) { | |
548 | // Count afforms which contain a search display | |
549 | if (is_a($dao, 'CRM_Search_DAO_SearchDisplay') && $dao->id) { | |
550 | if (empty($dao->saved_search_id) || empty($dao->name)) { | |
551 | $dao->find(TRUE); | |
552 | } | |
553 | $search = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_SavedSearch', $dao->saved_search_id); | |
554 | $afforms = \Civi\Api4\Afform::get(FALSE) | |
555 | ->selectRowCount() | |
556 | ->addWhere('search_displays', 'CONTAINS', "$search.$dao->name") | |
557 | ->execute(); | |
558 | if ($afforms->count()) { | |
559 | $counts[] = [ | |
560 | 'name' => 'Afform', | |
561 | 'type' => 'Afform', | |
562 | 'count' => $afforms->count(), | |
563 | ]; | |
564 | } | |
565 | } | |
566 | // Count afforms which contain any displays from a SavedSearch (including the default display) | |
567 | elseif (is_a($dao, 'CRM_Contact_DAO_SavedSearch') && $dao->id) { | |
568 | if (empty($dao->name)) { | |
569 | $dao->find(TRUE); | |
570 | } | |
571 | $clauses = [ | |
572 | ['search_displays', 'CONTAINS', $dao->name], | |
573 | ]; | |
574 | try { | |
575 | $displays = civicrm_api4('SearchDisplay', 'get', [ | |
576 | 'where' => [['saved_search_id', '=', $dao->id]], | |
577 | 'select' => 'name', | |
578 | ], ['name']); | |
579 | foreach ($displays as $displayName) { | |
580 | $clauses[] = ['search_displays', 'CONTAINS', $dao->name . '.' . $displayName]; | |
581 | } | |
582 | } | |
583 | catch (Exception $e) { | |
584 | // In case SearchKit is not installed, the api call would fail | |
585 | } | |
586 | $afforms = \Civi\Api4\Afform::get(FALSE) | |
587 | ->selectRowCount() | |
588 | ->addClause('OR', $clauses) | |
589 | ->execute(); | |
590 | if ($afforms->count()) { | |
591 | $counts[] = [ | |
592 | 'name' => 'Afform', | |
593 | 'type' => 'Afform', | |
594 | 'count' => $afforms->count(), | |
595 | ]; | |
596 | } | |
597 | } | |
1c3d1f8d CW |
598 | } |
599 | ||
f228ad74 CW |
600 | // Wordpress only: Register callback for rendering shortcodes |
601 | if (function_exists('add_filter')) { | |
602 | add_filter('civicrm_shortcode_get_markup', 'afform_shortcode_content', 10, 4); | |
603 | } | |
604 | ||
605 | /** | |
606 | * Wordpress only: Render Afform content for shortcodes. | |
607 | * | |
608 | * @param string $content | |
609 | * HTML Markup | |
610 | * @param array $atts | |
611 | * Shortcode attributes. | |
612 | * @param array $args | |
613 | * Existing shortcode arguments. | |
614 | * @param string $context | |
615 | * How many shortcodes are present on the page: 'single' or 'multiple'. | |
616 | * @return string | |
617 | * Modified markup. | |
618 | */ | |
619 | function afform_shortcode_content($content, $atts, $args, $context) { | |
620 | if ($atts['component'] === 'afform') { | |
621 | $afform = civicrm_api4('Afform', 'get', [ | |
622 | 'select' => ['directive_name', 'module_name'], | |
623 | 'where' => [['name', '=', $atts['name']]], | |
624 | ])->first(); | |
625 | if ($afform) { | |
626 | Civi::service('angularjs.loader')->addModules($afform['module_name']); | |
627 | $content = " | |
628 | <div class='crm-container' id='bootstrap-theme'> | |
629 | <crm-angular-js modules='{$afform['module_name']}'> | |
630 | <{$afform['directive_name']}></{$afform['directive_name']}> | |
631 | </crm-angular-js> | |
632 | </div>"; | |
633 | } | |
634 | } | |
635 | return $content; | |
636 | } |