From 2b6ccebcebd2e48ea184f58bcaaeb0c30784fde1 Mon Sep 17 00:00:00 2001 From: colemanw Date: Wed, 20 Dec 2023 21:55:34 -0500 Subject: [PATCH] SearchKit - Use getLinks api in formatLink --- .../SearchDisplay/AbstractRunAction.php | 55 ++++++++++++++----- .../api/v4/SearchDisplay/SearchRunTest.php | 2 +- 2 files changed, 43 insertions(+), 14 deletions(-) diff --git a/ext/search_kit/Civi/Api4/Action/SearchDisplay/AbstractRunAction.php b/ext/search_kit/Civi/Api4/Action/SearchDisplay/AbstractRunAction.php index 936eae620e..8dd1e9e126 100644 --- a/ext/search_kit/Civi/Api4/Action/SearchDisplay/AbstractRunAction.php +++ b/ext/search_kit/Civi/Api4/Action/SearchDisplay/AbstractRunAction.php @@ -507,13 +507,51 @@ abstract class AbstractRunAction extends \Civi\Api4\Generic\AbstractAction { return $out; } + /** + * Format a link to resolve tokens and form the url. + * + * There are 3 ways a link can be declared: + * 1. entity+action + * 2. entity+task + * 3. path + * + * @param array $link + * @param array $data + * @param string|NULL $text + * @param $index + * @return array|null + * @throws \CRM_Core_Exception + * @throws \Civi\API\Exception\NotImplementedException + */ protected function formatLink(array $link, array $data, string $text = NULL, $index = 0): ?array { - if (!$this->checkLinkAccess($link, $data, $index)) { + $useApi = (!empty($link['entity']) && !empty($link['action'])); + if (isset($index)) { + foreach ($data as $key => $value) { + if (is_array($value)) { + $data[$key] = $value[$index] ?? NULL; + } + } + } + if ($useApi) { + $checkPermissions = !in_array($link['action'], ['view', 'preview'], TRUE); + if (!empty($link['prefix'])) { + $data = \CRM_Utils_Array::filterByPrefix($data, $link['prefix']); + } + // Hack to support links to relationships + $linkEntity = ($link['entity'] === 'Relationship') ? 'RelationshipCache' : $link['entity']; + $apiInfo = civicrm_api4($linkEntity, 'getLinks', [ + 'checkPermissions' => $checkPermissions, + 'values' => $data, + 'where' => [['ui_action', '=', $link['action']]], + ]); + $link['path'] = $apiInfo[0]['path'] ?? ''; + } + elseif (!$this->checkLinkAccess($link, $data)) { return NULL; } $link['text'] = $text ?? $this->replaceTokens($link['text'], $data, 'view'); // Will return null if `$link[path]` is empty or if any tokens do not resolve - $path = $this->replaceTokens($link['path'], $data, 'url', $index); + $path = $this->replaceTokens($link['path'], $data, 'url'); if ($path) { $link['url'] = $this->getUrl($path); $keys = ['url', 'text', 'title', 'target', 'icon', 'style', 'autoOpen']; @@ -539,12 +577,11 @@ abstract class AbstractRunAction extends \Civi\Api4\Generic\AbstractAction { * * @param array $link * @param array $data - * @param int $index * @return bool * @throws \CRM_Core_Exception * @throws \Civi\API\Exception\NotImplementedException */ - private function checkLinkAccess(array $link, array $data, int $index = 0): bool { + private function checkLinkAccess(array $link, array $data): bool { if (empty($link['path']) && empty($link['task'])) { return FALSE; } @@ -560,7 +597,6 @@ abstract class AbstractRunAction extends \Civi\Api4\Generic\AbstractAction { $idField = CoreUtil::getIdFieldName($link['entity']); $idKey = $this->getIdKeyName($link['entity']); $id = $data[$link['prefix'] . $idKey] ?? NULL; - $id = is_array($id) ? $id[$index] ?? NULL : $id; if ($id) { $values = [$idField => $id]; // If not aggregated, add other values to help checkAccess be efficient @@ -714,7 +750,6 @@ abstract class AbstractRunAction extends \Civi\Api4\Generic\AbstractAction { ], ]); $link['path'] = $getLinks[0]['path'] ?? NULL; - $link['entity'] = $getLinks[0]['entity'] ?? NULL; // This is a bit clunky, the function_join_field gets un-munged later by $this->getJoinFromAlias() if ($this->canAggregate($link['prefix'] . $idKey)) { $link['prefix'] = 'GROUP_CONCAT_' . str_replace('.', '_', $link['prefix']); @@ -1002,7 +1037,6 @@ abstract class AbstractRunAction extends \Civi\Api4\Generic\AbstractAction { * @param string $tokenExpr * @param array $data * @param string $format view|raw|url - * @param int $index * @return string */ private function replaceTokens($tokenExpr, $data, $format, $index = NULL) { @@ -1012,12 +1046,7 @@ abstract class AbstractRunAction extends \Civi\Api4\Generic\AbstractAction { $dataType = $this->getSelectExpression($token)['dataType'] ?? NULL; $val = $this->formatViewValue($token, $val, $data, $dataType); } - if (!(is_null($index))) { - $replacement = is_array($val) ? $val[$index] ?? '' : $val; - } - else { - $replacement = implode(', ', (array) $val); - } + $replacement = implode(', ', (array) $val); // A missing token value in a url invalidates it if ($format === 'url' && (!isset($replacement) || $replacement === '')) { return NULL; diff --git a/ext/search_kit/tests/phpunit/api/v4/SearchDisplay/SearchRunTest.php b/ext/search_kit/tests/phpunit/api/v4/SearchDisplay/SearchRunTest.php index c0ad02827e..ade06c0854 100644 --- a/ext/search_kit/tests/phpunit/api/v4/SearchDisplay/SearchRunTest.php +++ b/ext/search_kit/tests/phpunit/api/v4/SearchDisplay/SearchRunTest.php @@ -428,7 +428,7 @@ class SearchRunTest extends Api4TestBase implements TransactionalInterface { $this->assertStringContainsString('Enable', $result[3]['columns'][1]['links'][2]['title']); // 4th link is to the case, and only for the relevant entity $this->assertEquals('Manage Case', $result[2]['columns'][1]['links'][3]['text']); - $this->assertStringContainsString('civicrm', $result[3]['columns'][1]['links'][3]['url']); + $this->assertStringContainsString("id={$case['id']}", $result[3]['columns'][1]['links'][3]['url']); } /** -- 2.25.1