From a43a59d788de7a35951879999505460422cd5559 Mon Sep 17 00:00:00 2001 From: Seamus Lee Date: Thu, 2 Feb 2023 11:42:21 +1100 Subject: [PATCH] [REF] Use Token Processor to generate sort name and display name for individuals Fix handling for when certain things should only show if there tokens filled out Handle for when the nameFormat is null (import tests) --- CRM/Contact/BAO/Individual.php | 27 +++++------ Civi/Token/TokenCompatSubscriber.php | 22 +++++++-- .../CRM/Contact/BAO/IndividualTest.php | 45 ++++++++++++++++++- .../CRM/Utils/TokenConsistencyTest.php | 4 +- 4 files changed, 78 insertions(+), 20 deletions(-) diff --git a/CRM/Contact/BAO/Individual.php b/CRM/Contact/BAO/Individual.php index 7209ef5000..fc375bb4ab 100644 --- a/CRM/Contact/BAO/Individual.php +++ b/CRM/Contact/BAO/Individual.php @@ -15,6 +15,8 @@ * @copyright CiviCRM LLC https://civicrm.org/licensing */ +use Civi\Token\TokenProcessor; + /** * Class contains functions for individual contact type. */ @@ -185,19 +187,18 @@ class CRM_Contact_BAO_Individual extends CRM_Contact_DAO_Contact { } } - //build the sort name. - $format = Civi::settings()->get('sort_name_format'); - $sortName = CRM_Utils_Address::format($formatted, $format, - FALSE, FALSE, $tokenFields - ); - $sortName = trim($sortName); - - //build the display name. - $format = Civi::settings()->get('display_name_format'); - $displayName = CRM_Utils_Address::format($formatted, $format, - FALSE, FALSE, $tokenFields - ); - $displayName = trim($displayName); + $formatted['id'] = $contact->id ?? $params['id'] ?? 0; + $tokenProcessor = new TokenProcessor(\Civi::dispatcher(), [ + 'class' => __CLASS__, + 'schema' => ['contactId'], + ]); + $tokenProcessor->addRow(['contactId' => $contactFields['id'] ?? 0, 'contact' => $formatted]); + $tokenProcessor->addMessage('sort_name', Civi::settings()->get('sort_name_format'), 'text/plain'); + $tokenProcessor->addMessage('display_name', Civi::settings()->get('display_name_format'), 'text/plain'); + $tokenProcessor->evaluate(); + $row = $tokenProcessor->getRow(0); + $sortName = trim($row->render('sort_name')); + $displayName = trim($row->render('display_name')); } //start further check for email. diff --git a/Civi/Token/TokenCompatSubscriber.php b/Civi/Token/TokenCompatSubscriber.php index 2dd0f9e1ef..9c81b9180e 100644 --- a/Civi/Token/TokenCompatSubscriber.php +++ b/Civi/Token/TokenCompatSubscriber.php @@ -68,10 +68,24 @@ class TokenCompatSubscriber implements EventSubscriberInterface { // This removes the pattern used in greetings of having bits of text that // depend on the tokens around them - ie '{first_name}{ }{last_name} - // has an extra construct '{ }' which will resolve as a space if the - // tokens on either side are resolved to 'something' - $e->string = preg_replace('/\\\\|\{(\s*)?\}/', ' ', $e->string); - + // has an extra construct '{ }' which will resolve what is inside the {} if the + // tokens on either side are resolved to 'something' (ie there is some sort of + // non whitespace character after the string. + // Accepted variants of { } are {`} {|} {,} {`} {*} {-} {(} {)} + // In each case any amount of preceding or trailing whitespace is acceptable. + // The accepted variants list contains known or suspected real world usages. + // Regex is to capture { followed by 0 or more white spaces followed by + // a white space or one of , ` ~ ( ) - * | + // followed by 0 or more white spaces + // followed by } + // the captured string is followed by 1 or more non-white spaces. + // If it is repeated it will be replaced by the first input - + // ie { }{ } will be replaced by the content of the latter token. + // Check testGenerateDisplayNameCustomFormats for test cover. + $e->string = preg_replace('/\\\\|{(\s*(\s|,|`|~|\(|\)|-|\*|\|)*\s*)?\}}*(?=[^{\s])/', '$1', $e->string); + // Now do a another pass, removing any remaining instances (which will get rid of any that were not + // followed by something). + $e->string = preg_replace('/\\\\|' . '\{(\s*(\s|,|`|~|\(|\)|-|\*|\|)*\s?)?\}/', '', $e->string); if ($useSmarty) { $smartyVars = []; foreach ($e->context['smartyTokenAlias'] ?? [] as $smartyName => $tokenName) { diff --git a/tests/phpunit/CRM/Contact/BAO/IndividualTest.php b/tests/phpunit/CRM/Contact/BAO/IndividualTest.php index 0928bfda59..b25d9ce21b 100644 --- a/tests/phpunit/CRM/Contact/BAO/IndividualTest.php +++ b/tests/phpunit/CRM/Contact/BAO/IndividualTest.php @@ -118,8 +118,51 @@ class CRM_Contact_BAO_IndividualTest extends CiviUnitTestCase { CRM_Contact_BAO_Individual::format($params, $contact); $this->assertEquals("bleu02@example.com", $contact->display_name); - $this->assertEquals("bleu02@example.com", $contact->sort_name); + $this->assertEquals('bleu02@example.com', $contact->sort_name); } + /** + * Display Format cases + */ + public static function displayFormatCases(): array { + return [ + 'Nick name with tilde' => ['{contact.first_name}{ }{contact.last_name}{ ~ }{contact.nick_name}', TRUE, FALSE], + 'Empty nick name' => ['{contact.first_name}{ }{contact.last_name}{ ~ }{contact.nick_name}', FALSE, FALSE], + 'No Nick Name but Prefix' => ['{contact.individual_prefix}{ }{contact.first_name}{ }{contact.middle_name}{ }{contact.last_name}{ }{contact.individual_suffix}{ ~ }{contact.nick_name}', FALSE, TRUE], + ]; + } + + /** + * @dataProvider displayFormatCases + */ + public function testGenerateDisplayNameCustomFormats(string $displayNameFormat, bool $includeNickName, bool $includePrefix): void { + $params = [ + 'contact_type' => 'Individual', + 'first_name' => 'Michael', + 'last_name' => 'Jackson', + 'individual_prefix' => 'Mr.', + 'individual_suffix' => 'Jr.', + ]; + if ($includeNickName) { + $params['nick_name'] = 'Mick'; + } + \Civi::settings()->set('display_name_format', $displayNameFormat); + $contact = new CRM_Contact_DAO_Contact(); + + CRM_Contact_BAO_Individual::format($params, $contact); + if ($includeNickName) { + $this->assertEquals('Michael Jackson ~ Mick', $contact->display_name); + } + else { + if ($includePrefix) { + $this->assertEquals('Mr. Michael Jackson Jr.', $contact->display_name); + } + else { + $this->assertEquals('Michael Jackson', $contact->display_name); + } + } + \Civi::settings()->set('display_name_format', \Civi::settings()->getDefault('display_name_format')); + } + } diff --git a/tests/phpunit/CRM/Utils/TokenConsistencyTest.php b/tests/phpunit/CRM/Utils/TokenConsistencyTest.php index b388619ac6..06dca14555 100644 --- a/tests/phpunit/CRM/Utils/TokenConsistencyTest.php +++ b/tests/phpunit/CRM/Utils/TokenConsistencyTest.php @@ -364,11 +364,11 @@ Czech Republic $variants = [ [ 'string' => '{contact.individual_prefix}{ }{contact.first_name}{ }{contact.middle_name}{ }{contact.last_name}{ }{contact.individual_suffix}', - 'expected' => 'Mr. Anthony Anderson II', + 'expected' => 'Mr. Anthony Anderson II', ], [ 'string' => '{contact.prefix_id:label}{ }{contact.first_name}{ }{contact.middle_name}{ }{contact.last_name}{ }{contact.suffix_id:label}', - 'expected' => 'Mr. Anthony Anderson II', + 'expected' => 'Mr. Anthony Anderson II', ], ]; $tokenProcessor = new TokenProcessor(\Civi::dispatcher(), [ -- 2.25.1