From 4952dbf3e29231a89b7436d263afd377ccd75be8 Mon Sep 17 00:00:00 2001 From: demeritcowboy Date: Mon, 26 Oct 2020 19:48:37 -0400 Subject: [PATCH] truncate unicode strings better --- CRM/Contact/BAO/Contact.php | 17 ++- tests/phpunit/CRM/Contact/BAO/ContactTest.php | 133 ++++++++++++++++++ 2 files changed, 145 insertions(+), 5 deletions(-) diff --git a/CRM/Contact/BAO/Contact.php b/CRM/Contact/BAO/Contact.php index d258641cb7..988cab9a5f 100644 --- a/CRM/Contact/BAO/Contact.php +++ b/CRM/Contact/BAO/Contact.php @@ -157,11 +157,18 @@ class CRM_Contact_BAO_Contact extends CRM_Contact_DAO_Contact { CRM_Contact_BAO_Individual::format($params, $contact); } - if (strlen($contact->display_name) > 128) { - $contact->display_name = substr($contact->display_name, 0, 128); - } - if (strlen($contact->sort_name) > 128) { - $contact->sort_name = substr($contact->sort_name, 0, 128); + // Note that copyValues() above might already call this, via + // CRM_Utils_String::ellipsify(), but e.g. for Individual it gets put + // back or altered by Individual::format() just above, so we need to + // check again. + // Note also orgs will get ellipsified, but if we do that here then + // some existing tests on individual fail. + // Also api v3 will enforce org naming length by failing, v4 will truncate. + if (mb_strlen($contact->display_name, 'UTF-8') > 128) { + $contact->display_name = mb_substr($contact->display_name, 0, 128, 'UTF-8'); + } + if (mb_strlen($contact->sort_name, 'UTF-8') > 128) { + $contact->sort_name = mb_substr($contact->sort_name, 0, 128, 'UTF-8'); } $privacy = $params['privacy'] ?? NULL; diff --git a/tests/phpunit/CRM/Contact/BAO/ContactTest.php b/tests/phpunit/CRM/Contact/BAO/ContactTest.php index b4fc988a67..075655206d 100644 --- a/tests/phpunit/CRM/Contact/BAO/ContactTest.php +++ b/tests/phpunit/CRM/Contact/BAO/ContactTest.php @@ -1656,4 +1656,137 @@ class CRM_Contact_BAO_ContactTest extends CiviUnitTestCase { } } + /** + * Test that long unicode individual names are truncated properly when + * creating sort/display name. + * + * @dataProvider longUnicodeIndividualNames + * + * @param array $input + * @param array $expected + */ + public function testLongUnicodeIndividualName(array $input, array $expected) { + // needs to be passed by reference + $params = [ + 'contact_type' => 'Individual', + 'first_name' => $input['first_name'], + 'last_name' => $input['last_name'], + ]; + $contact = CRM_Contact_BAO_Contact::add($params); + + $this->assertEquals($expected['sort_name'], $contact->sort_name); + $this->assertEquals($expected['display_name'], $contact->display_name); + + $this->contactDelete($contact->id); + } + + /** + * Data provider for testLongUnicodeIndividualName + * @return array + */ + public function longUnicodeIndividualNames():array { + return [ + 'much less than 128' => [ + [ + 'first_name' => 'асдадасда', + 'last_name' => 'лнплнплнп', + ], + [ + 'sort_name' => 'лнплнплнп, асдадасда', + 'display_name' => 'асдадасда лнплнплнп', + ], + ], + 'less than 128 but still too big' => [ + [ + 'first_name' => 'асдадасдашасдадасдашасдадасдашасдадасдашасдадасдашасдадасдаш', + 'last_name' => 'лнплнплнпшлнплнплнпшлнплнплнпшлнплнплнпшлнплнплнпшлнплнплнпш', + ], + [ + 'sort_name' => 'лнплнплнпшлнплнплнпшлнплнплнпшлнплнплнпшлнплнплнпшлнплнплнпш, асдадасдашасдадасдашасдадасдашасдадасдашасдадасдашасдадасдаш', + 'display_name' => 'асдадасдашасдадасдашасдадасдашасдадасдашасдадасдашасдадасдаш лнплнплнпшлнплнплнпшлнплнплнпшлнплнплнпшлнплнплнпшлнплнплнпш', + ], + ], + // note we have to account for the comma and space + 'equal 128 sort_name' => [ + [ + 'first_name' => 'асдадасдашасдадасдашасдадасдашасдадасдашасдадасдашасдадасдашасд', + 'last_name' => 'лнплнплнпшлнплнплнпшлнплнплнпшлнплнплнпшлнплнплнпшлнплнплнпшлнп', + ], + [ + 'sort_name' => 'лнплнплнпшлнплнплнпшлнплнплнпшлнплнплнпшлнплнплнпшлнплнплнпшлнп, асдадасдашасдадасдашасдадасдашасдадасдашасдадасдашасдадасдашасд', + 'display_name' => 'асдадасдашасдадасдашасдадасдашасдадасдашасдадасдашасдадасдашасд лнплнплнпшлнплнплнпшлнплнплнпшлнплнплнпшлнплнплнпшлнплнплнпшлнп', + ], + ], + // note we have to account for the space + 'equal 128 display_name' => [ + [ + 'first_name' => 'асдадасдашасдадасдашасдадасдашасдадасдашасдадасдашасдадасдашасдa', + 'last_name' => 'лнплнплнпшлнплнплнпшлнплнплнпшлнплнплнпшлнплнплнпшлнплнплнпшлнп', + ], + [ + 'sort_name' => 'лнплнплнпшлнплнплнпшлнплнплнпшлнплнплнпшлнплнплнпшлнплнплнпшлнп, асдадасдашасдадасдашасдадасдашасдадасдашасдадасдашасдадасдашасд', + 'display_name' => 'асдадасдашасдадасдашасдадасдашасдадасдашасдадасдашасдадасдашасдa лнплнплнпшлнплнплнпшлнплнплнпшлнплнплнпшлнплнплнпшлнплнплнпшлнп', + ], + ], + 'longer than 128' => [ + [ + 'first_name' => 'асдадасдашасдадасдашасдадасдашасдадасдашасдадасдашасдадасдашасдадасдаш', + 'last_name' => 'лнплнплнпшлнплнплнпшлнплнплнпшлнплнплнпшлнплнплнпшлнплнплнпшлнплнплнпш', + ], + [ + 'sort_name' => 'лнплнплнпшлнплнплнпшлнплнплнпшлнплнплнпшлнплнплнпшлнплнплнпшлнплнплнпш, асдадасдашасдадасдашасдадасдашасдадасдашасдадасдашасдада', + 'display_name' => 'асдадасдашасдадасдашасдадасдашасдадасдашасдадасдашасдадасдашасдадасдаш лнплнплнпшлнплнплнпшлнплнплнпшлнплнплнпшлнплнплнпшлнплнпл', + ], + ], + ]; + } + + /** + * Test that long unicode org names are truncated properly when creating + * sort/display name. + * + * @dataProvider longUnicodeOrgNames + * + * @param string $input + * @param string $expected + */ + public function testLongUnicodeOrgName(string $input, string $expected) { + // needs to be passed by reference + $params = [ + 'contact_type' => 'Organization', + 'organization_name' => $input, + ]; + $contact = CRM_Contact_BAO_Contact::add($params); + + $this->assertEquals($expected, $contact->sort_name); + $this->assertEquals($expected, $contact->display_name); + + $this->contactDelete($contact->id); + } + + /** + * Data provider for testLongUnicodeOrgName + * @return array + */ + public function longUnicodeOrgNames():array { + return [ + 'much less than 128' => [ + 'асдадасда шшшшшшшшшш', + 'асдадасда шшшшшшшшшш', + ], + 'less than 128 but still too big' => [ + 'асдадасда шшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшасд', + 'асдадасда шшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшасд', + ], + 'equal 128' => [ + 'асдадасда шшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшасд', + 'асдадасда шшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшасд', + ], + 'longer than 128' => [ + 'асдадасда шшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшасдасд', + 'асдадасда шшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшш...', + ], + ]; + } + } -- 2.25.1