CRM-21474 add support for setting non-required fields to 'null'
authoreileen <emcnaughton@wikimedia.org>
Mon, 4 Dec 2017 05:10:01 +0000 (18:10 +1300)
committereileen <emcnaughton@wikimedia.org>
Mon, 4 Dec 2017 07:16:45 +0000 (20:16 +1300)
When a field is not required in the database the 'null' should be pass through the pseudoconstant validation.

Note the unit test on this is failing because the BAO is not respecting setting null. Follow up patch

api/v3/Contact.php
api/v3/utils.php
tests/phpunit/api/v3/ContactTest.php

index 4f4912acd3bc13beae3260000a86d31378a68cf6..2f93c1b4b72034b7150d8dc2cae88f1c2b099d95 100644 (file)
@@ -647,11 +647,6 @@ function _civicrm_api3_greeting_format_params($params) {
     }
 
     if ($greetingId) {
-
-      if (!array_key_exists($greetingId, $greetings)) {
-        throw new API_Exception(ts('Invalid %1 greeting Id', array(1 => $key)));
-      }
-
       if (!$customGreeting && ($greetingId == array_search('Customized', $greetings))) {
         throw new API_Exception(ts('Please provide a custom value for %1 greeting',
             array(1 => $key)
index 8cd62eb150855d7623886cda0172de12743fd5ca..3fed9d32a9666ea4c48bc04416dcd908585275c0 100644 (file)
@@ -2280,7 +2280,7 @@ function _civicrm_api3_api_match_pseudoconstant(&$fieldValue, $entity, $fieldNam
   if (is_array($fieldValue)) {
     foreach ($fieldValue as &$value) {
       if (!is_array($value)) {
-        _civicrm_api3_api_match_pseudoconstant_value($value, $options, $fieldName);
+        _civicrm_api3_api_match_pseudoconstant_value($value, $options, $fieldName, CRM_Utils_Array::value('api.required', $fieldInfo));
       }
     }
     // TODO: unwrap the call to implodePadded from the conditional and do it always
@@ -2291,7 +2291,7 @@ function _civicrm_api3_api_match_pseudoconstant(&$fieldValue, $entity, $fieldNam
     }
   }
   else {
-    _civicrm_api3_api_match_pseudoconstant_value($fieldValue, $options, $fieldName);
+    _civicrm_api3_api_match_pseudoconstant_value($fieldValue, $options, $fieldName, CRM_Utils_Array::value('api.required', $fieldInfo));
   }
 }
 
@@ -2301,10 +2301,14 @@ function _civicrm_api3_api_match_pseudoconstant(&$fieldValue, $entity, $fieldNam
  * @param string $value field value
  * @param array $options array of options for this field
  * @param string $fieldName field name used in api call (not necessarily the canonical name)
+ * @param bool $isRequired
+ *   Is this a required field or is 'null' an acceptable option. We allow 'null' last
+ *   in case we have the weird situation of it being a valid option in which case our
+ *   brains will probably explode.
  *
  * @throws API_Exception
  */
-function _civicrm_api3_api_match_pseudoconstant_value(&$value, $options, $fieldName) {
+function _civicrm_api3_api_match_pseudoconstant_value(&$value, $options, $fieldName, $isRequired) {
   // If option is a key, no need to translate
   // or if no options are avaiable for pseudoconstant 'table' property
   if (array_key_exists($value, $options) || !$options) {
@@ -2323,6 +2327,10 @@ function _civicrm_api3_api_match_pseudoconstant_value(&$value, $options, $fieldN
   $options = array_map("strtolower", $options);
   $newValue = array_search($newValue, $options);
   if ($newValue === FALSE) {
+    if ($value === 'null' && !$isRequired) {
+      // CiviMagic syntax for Nulling out the field - let it through.
+      return;
+    }
     throw new API_Exception("'$value' is not a valid option for field $fieldName", 2001, array('error_field' => $fieldName));
   }
   $value = $newValue;
index 08118db788005f399683b81a5d7c1d91bb7d4bba..0e792c74fa36b5019e17f36c28b8751822f62853 100644 (file)
@@ -3621,6 +3621,11 @@ class api_v3_ContactTest extends CiviUnitTestCase {
     $contact = $this->callAPISuccessGetSingle('Contact', array('id' => $contact['id'], 'return' => 'postal_greeting'));
     $this->assertEquals('Dear Alan Mice', $contact['postal_greeting_display']);
 
+    // Set contact to have no postal greeting & check it is correct.
+    $this->callAPISuccess('Contact', 'create', array('id' => $contact['id'], 'postal_greeting_id' => 'null'));
+    $contact = $this->callAPISuccessGetSingle('Contact', array('id' => $contact['id'], 'return' => 'postal_greeting'));
+    $this->assertEquals('', $contact['postal_greeting_display']);
+
     //Cleanup
     $this->callAPISuccess('OptionValue', 'create', array('id' => $postalOption['id'], 'name' => 'Dear {contact.first_name}'));
     $this->customFieldDelete($ids['custom_field_id']);