From: Coleman Watts Date: Wed, 21 Apr 2021 19:27:52 +0000 (-0400) Subject: SearchKit - Fix display of contact reference fields (single-value) X-Git-Url: https://vcs.fsf.org/?a=commitdiff_plain;h=ede387bbf5478b96f53684383e19213920c9fef6;p=civicrm-core.git SearchKit - Fix display of contact reference fields (single-value) This fixes the display of contact reference fields, giving feature parity with other FK fields. Both ID and Display Name are shown as available columns. This does not address the more difficult question of how to join multi-valued contact reference fields with contact display names. --- diff --git a/Civi/Api4/Service/Schema/SchemaMapBuilder.php b/Civi/Api4/Service/Schema/SchemaMapBuilder.php index bcaad8ee35..77666cb4a7 100644 --- a/Civi/Api4/Service/Schema/SchemaMapBuilder.php +++ b/Civi/Api4/Service/Schema/SchemaMapBuilder.php @@ -91,6 +91,7 @@ class SchemaMapBuilder { if ($fkClass) { $tableName = AllCoreTables::getTableForClass($fkClass); $fkKey = $data['FKKeyColumn'] ?? 'id'; + // Fixme: Clumsy string manipulation to transform e.g. "contact_id" to "contact" - we never should have done this $alias = str_replace('_id', '', $field); $joinable = new Joinable($tableName, $fkKey, $alias); $joinable->setJoinType($joinable::JOIN_TYPE_MANY_TO_ONE); @@ -154,7 +155,7 @@ class SchemaMapBuilder { } $fieldData = \CRM_Utils_SQL_Select::from('civicrm_custom_field f') ->join('custom_group', 'INNER JOIN civicrm_custom_group g ON g.id = f.custom_group_id') - ->select(['g.name as custom_group_name', 'g.table_name', 'g.is_multiple', 'f.name', 'label', 'column_name', 'option_group_id']) + ->select(['g.name as custom_group_name', 'g.table_name', 'g.is_multiple', 'f.name', 'f.data_type', 'label', 'column_name', 'option_group_id']) ->where('g.extends IN (@entity)', ['@entity' => $customInfo['extends']]) ->where('g.is_active') ->where('f.is_active') @@ -182,6 +183,11 @@ class SchemaMapBuilder { $joinable = new Joinable($baseTable->getName(), $customInfo['column'], AllCoreTables::convertEntityNameToLower($entityName)); $customTable->addTableLink('entity_id', $joinable); } + + if ($fieldData->data_type === 'ContactReference') { + $joinable = new Joinable('civicrm_contact', 'id', $fieldData->name); + $customTable->addTableLink($fieldData->column_name, $joinable); + } } foreach ($links as $alias => $link) { diff --git a/ext/search/Civi/Search/Admin.php b/ext/search/Civi/Search/Admin.php index 92b2f60565..5a28f6d6f0 100644 --- a/ext/search/Civi/Search/Admin.php +++ b/ext/search/Civi/Search/Admin.php @@ -136,11 +136,20 @@ class Admin { if (in_array('DAOEntity', $entity['type'], TRUE) && !in_array('EntityBridge', $entity['type'], TRUE)) { foreach (array_reverse($entity['fields'], TRUE) as $index => $field) { if (!empty($field['fk_entity']) && !$field['options'] && !empty($schema[$field['fk_entity']]['label_field'])) { - // The original field will get title instead of label since it represents the id (title usually ends in ID but label does not) - $entity['fields'][$index]['label'] = $field['title']; + $isCustom = strpos($field['name'], '.'); + // Custom fields: append "ID" to original field label + if ($isCustom) { + $entity['fields'][$index]['label'] .= ' ' . E::ts('Contact ID'); + } + // DAO fields: use title instead of label since it represents the id (title usually ends in ID but label does not) + else { + $entity['fields'][$index]['label'] = $field['title']; + } // Add the label field from the other entity to this entity's list of fields $newField = \CRM_Utils_Array::findAll($schema[$field['fk_entity']]['fields'], ['name' => $schema[$field['fk_entity']]['label_field']])[0]; - $newField['name'] = str_replace('_id', '', $field['name']) . '.' . $schema[$field['fk_entity']]['label_field']; + // Due to string manipulation in \Civi\Api4\Service\Schema\SchemaMapBuilder::addJoins() + $alias = $isCustom ? $field['name'] : str_replace('_id', '', $field['name']); + $newField['name'] = $alias . '.' . $schema[$field['fk_entity']]['label_field']; $newField['label'] = $field['label'] . ' ' . $newField['label']; array_splice($entity['fields'], $index, 0, [$newField]); } diff --git a/ext/search/ang/crmSearchAdmin.module.js b/ext/search/ang/crmSearchAdmin.module.js index 88cdddbe69..dfa3910d79 100644 --- a/ext/search/ang/crmSearchAdmin.module.js +++ b/ext/search/ang/crmSearchAdmin.module.js @@ -105,7 +105,6 @@ return new RegExp('^' + join.alias + '_\\d\\d').test(path); }); if (!join) { - console.warn( 'Join ' + fullNameOrAlias + ' not found.'); return; } path = path.replace(join.alias + '_', ''); @@ -138,28 +137,20 @@ return result; } function getFieldAndJoin(fieldName, entityName) { - var dotSplit = fieldName.split('.'), - joinEntity = dotSplit.length > 1 ? dotSplit[0] : null, - name = _.last(dotSplit).split(':')[0], + var fieldPath = fieldName.split(':')[0], + dotSplit = fieldPath.split('.'), + name, join, field; - // Custom fields contain a dot in their fieldname - // If 3 segments, the first is the joinEntity and the last 2 are the custom field - if (dotSplit.length === 3) { - name = dotSplit[1] + '.' + name; - } - // If 2 segments, it's ambiguous whether this is a custom field or joined field. Search the main entity first. - if (dotSplit.length === 2) { - field = _.find(getEntity(entityName).fields, {name: dotSplit[0] + '.' + name}); - if (field) { - field.baseEntity = entityName; - return {field: field}; + // If 2 or more segments, the first might be the name of a join + if (dotSplit.length > 1) { + join = getJoin(dotSplit[0]); + if (join) { + dotSplit.shift(); + entityName = join.entity; } } - if (joinEntity) { - join = getJoin(joinEntity); - entityName = getJoin(joinEntity).entity; - } + name = dotSplit.join('.'); field = _.find(getEntity(entityName).fields, {name: name}); if (!field && join && join.bridge) { field = _.find(getEntity(join.bridge).fields, {name: name}); diff --git a/tests/phpunit/api/v4/Action/CustomJoinTest.php b/tests/phpunit/api/v4/Action/CustomJoinTest.php new file mode 100644 index 0000000000..9605577ee3 --- /dev/null +++ b/tests/phpunit/api/v4/Action/CustomJoinTest.php @@ -0,0 +1,73 @@ +addValue('name', 'MyContactRef') + ->addValue('extends', 'Individual') + ->execute() + ->first(); + + CustomField::create(FALSE) + ->addValue('label', 'FavPerson') + ->addValue('custom_group_id', $customGroup['id']) + ->addValue('html_type', 'Autocomplete-Select') + ->addValue('data_type', 'ContactReference') + ->execute(); + + $favPersonId = Contact::create(FALSE) + ->addValue('first_name', 'Favorite') + ->addValue('last_name', 'Person') + ->addValue('contact_type', 'Individual') + ->execute() + ->first()['id']; + + $contactId = Contact::create(FALSE) + ->addValue('first_name', 'Mya') + ->addValue('last_name', 'Tester') + ->addValue('contact_type', 'Individual') + ->addValue('MyContactRef.FavPerson', $favPersonId) + ->execute() + ->first()['id']; + + $contact = Contact::get(FALSE) + ->addSelect('display_name') + ->addSelect('MyContactRef.FavPerson.first_name') + ->addSelect('MyContactRef.FavPerson.last_name') + ->addWhere('id', '=', $contactId) + ->execute() + ->first(); + + $this->assertEquals('Favorite', $contact['MyContactRef.FavPerson.first_name']); + $this->assertEquals('Person', $contact['MyContactRef.FavPerson.last_name']); + } + +} diff --git a/tests/phpunit/api/v4/AllTests.php b/tests/phpunit/api/v4/AllTests.php index 67304b923a..0a4965ecc5 100644 --- a/tests/phpunit/api/v4/AllTests.php +++ b/tests/phpunit/api/v4/AllTests.php @@ -16,37 +16,6 @@ * @copyright CiviCRM LLC https://civicrm.org/licensing */ -// vim: set si ai expandtab tabstop=4 shiftwidth=4 softtabstop=4: - -/** - * File for the api_v4_AllTests class - * - * (PHP 5) - * - * @author Walt Haas (801) 534-1262 - * @copyright Copyright CiviCRM LLC (C) 2009 - * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html - * GNU Affero General Public License version 3 - * @version $Id: AllTests.php 40328 2012-05-11 23:06:13Z allen $ - * @package CiviCRM - * - * This file is part of CiviCRM - * - * CiviCRM is free software; you can redistribute it and/or - * modify it under the terms of the GNU Affero General Public License - * as published by the Free Software Foundation; either version 3 of - * the License, or (at your option) any later version. - * - * CiviCRM is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public - * License along with this program. If not, see - * . - */ - /** * Class containing the APIv4 test suite * @@ -73,13 +42,3 @@ class api_v4_AllTests extends CiviTestSuite { } } -// class AllTests - -// -- set Emacs parameters -- -// Local variables: -// mode: php; -// tab-width: 4 -// c-basic-offset: 4 -// c-hanging-comment-ender-p: nil -// indent-tabs-mode: nil -// End: