From 809e1a833f58c1e595f73dcd1f9101e2179caa8a Mon Sep 17 00:00:00 2001 From: eileen Date: Fri, 26 Oct 2018 13:57:48 +1300 Subject: [PATCH] Prevent hard error when a string is too long for a field. Over time we have had various requests to extend the length of various fields (currently https://github.com/civicrm/civicrm-core/pull/12939 ). The main issue is not that it matters to capture every single character of a crazy long user entered field - but that a hard fail when the data is too long can lose payment or registration or other data & provide a bad experience. This PR makes it still save, with a logged message & the utf friendly function in play. As of writing the api validation is stilltight - see ``` // Check our field length throw new API_Exception("Value for $fieldName is " . strlen(utf8_decode($value)) . " characters - This field has a maxlength of {$fieldInfo['maxlength']} characters.", 2100, array('field' => $fieldName) ); } ``` and changing this is up for discussion. Note that at the UI level max field lengths can be enforced by using addField which uses metadata to determine field length etc --- CRM/Core/DAO.php | 8 ++++++++ tests/phpunit/api/v3/ParticipantTest.php | 20 +++++++++++++++----- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/CRM/Core/DAO.php b/CRM/Core/DAO.php index c6a495b61d..2892d32891 100644 --- a/CRM/Core/DAO.php +++ b/CRM/Core/DAO.php @@ -696,6 +696,14 @@ class CRM_Core_DAO extends DB_DataObject { if (!$serializeArrays && is_array($pValue) && !empty($value['serialize'])) { Civi::log()->warning(ts('use copyParams to serialize arrays (' . __CLASS__ . '.' . $name . ')'), ['civi.tag' => 'deprecated']); } + $maxLength = CRM_Utils_Array::value('maxlength', $value); + if (!is_array($pValue) && $maxLength && mb_strlen($pValue) > $maxLength + && empty($value['pseudoconstant']) + ) { + Civi::log()->warning(ts('A string for field $dbName has been truncated. The original string was %1', [CRM_Utils_Type::escape($pValue, 'String')])); + // The string is too long - what to do what to do? Well losing data is generally bad so lets' truncate + $pValue = CRM_Utils_String::ellipsify($pValue, $maxLength); + } $this->$dbName = $pValue; $allNull = FALSE; } diff --git a/tests/phpunit/api/v3/ParticipantTest.php b/tests/phpunit/api/v3/ParticipantTest.php index 4946445da8..8ad353a9f8 100644 --- a/tests/phpunit/api/v3/ParticipantTest.php +++ b/tests/phpunit/api/v3/ParticipantTest.php @@ -447,12 +447,22 @@ class api_v3_ParticipantTest extends CiviUnitTestCase { * Check with complete array. */ public function testCreateAllParams() { - $params = $this->_params; - - $participant = $this->callAPISuccess('participant', 'create', $params); + $participant = $this->callAPISuccess('participant', 'create', $this->_params); $this->_participantID = $participant['id']; - // assertDBState compares expected values in $match to actual values in the DB - $this->assertDBState('CRM_Event_DAO_Participant', $participant['id'], $params); + $this->assertDBState('CRM_Event_DAO_Participant', $participant['id'], $this->_params); + } + + /** + * Test that an overlong source is handled. + */ + public function testLongSource() { + $params = array_merge($this->_params, [ + 'source' => 'a string that is even longer than the 128 character limit that is allowed for this field because sometimes you want, you know, an essay', + ]); + $baoCreated = CRM_Event_BAO_Participant::create($params); + $this->assertEquals('a string that is even longer than the 128 character limit that is allowed for this field because sometimes you want, you know...', $baoCreated->source); + // @todo - currently the api will still reject the long string. + //$this->callAPISuccess('participant', 'create', $params); } /** -- 2.25.1