Fix api profile.submit to work with tag & note fields
authorColeman Watts <coleman@civicrm.org>
Sat, 15 Sep 2018 02:46:43 +0000 (22:46 -0400)
committerColeman Watts <coleman@civicrm.org>
Tue, 18 Sep 2018 14:05:45 +0000 (10:05 -0400)
api/v3/EntityTag.php
api/v3/Profile.php
tests/phpunit/api/v3/ProfileTest.php

index a3098bea8591850d7c90df5553017f31bc5f8b2b..6b0bd7033e1db81c51ddbaae92c5e99429dcb938 100644 (file)
@@ -101,7 +101,7 @@ function _civicrm_api3_entity_tag_delete_spec(&$params) {
  */
 function _civicrm_api3_entity_tag_common($params, $op = 'add') {
 
-  $entityIDs   = array();
+  $entityIDs = $tagIDs = array();
   $entityTable = 'civicrm_contact';
   if (is_array($params)) {
     foreach ($params as $n => $v) {
@@ -109,7 +109,12 @@ function _civicrm_api3_entity_tag_common($params, $op = 'add') {
         $entityIDs[] = $v;
       }
       elseif (substr($n, 0, 6) == 'tag_id') {
-        $tagIDs[] = $v;
+        if (is_array($v)) {
+          $tagIDs = array_merge($tagIDs, $v);
+        }
+        else {
+          $tagIDs[] = $v;
+        }
       }
       elseif (substr($n, 0, 12) == 'entity_table') {
         $entityTable = $v;
@@ -156,3 +161,38 @@ function _civicrm_api3_entity_tag_common($params, $op = 'add') {
   }
   return $values;
 }
+
+/**
+ * Replace tags for an entity
+ */
+function civicrm_api3_entity_tag_replace($params) {
+  $transaction = new CRM_Core_Transaction();
+  try {
+    civicrm_api3_verify_one_mandatory($params, NULL, ['values', 'tag_id']);
+
+    $baseParams = _civicrm_api3_generic_replace_base_params($params);
+    unset($baseParams['tag_id']);
+
+    // Lookup pre-existing records
+    $preexisting = civicrm_api3('entity_tag', 'get', $baseParams);
+    $preexisting = array_column($preexisting['values'], 'tag_id');
+    $toAdd = isset($params['tag_id']) ? $params['tag_id'] : array_column($params['values'], 'tag_id');
+    $toRemove = array_diff($preexisting, $toAdd);
+
+    $result = [];
+    if ($toAdd) {
+      $result = _civicrm_api3_entity_tag_common(array_merge($baseParams, ['tag_id' => $toAdd]), 'add');
+    }
+    if ($toRemove) {
+      $result += _civicrm_api3_entity_tag_common(array_merge($baseParams, ['tag_id' => $toRemove]), 'remove');
+    }
+    // Not really errors
+    unset($result['is_error'], $result['error_message']);
+
+    return civicrm_api3_create_success($result, $params, 'EntityTag', 'replace');
+  }
+  catch(Exception $e) {
+    $transaction->rollback();
+    return civicrm_api3_create_error($e->getMessage());
+  }
+}
index 2951c8d65c37a8de947acb331874f8bf42f6bd2a..22a26becab367ba7ca71c1beadc1fb584fad4aa5 100644 (file)
@@ -202,14 +202,35 @@ function civicrm_api3_profile_submit($params) {
 
     $entity = strtolower(CRM_Utils_Array::value('entity', $field));
     if ($entity && !in_array($entity, array_merge($contactEntities, $locationEntities))) {
-      $contactParams['api.' . $entity . '.create'][$fieldName] = $value;
-      //@todo we are not currently declaring this option
-      if (isset($params['batch_id']) && strtolower($entity) == 'contribution') {
-        $contactParams['api.' . $entity . '.create']['batch_id'] = $params['batch_id'];
-      }
-      if (isset($params[$entity . '_id'])) {
-        //todo possibly declare $entity_id in getfields ?
-        $contactParams['api.' . $entity . '.create']['id'] = $params[$entity . '_id'];
+      switch ($entity) {
+        case 'note':
+          if ($value) {
+            $contactParams['api.Note.create'] = [
+              'note' => $value,
+              'contact_id' => 'user_contact_id',
+            ];
+          }
+          break;
+
+        case 'entity_tag':
+          if (!is_array($value)) {
+            $value = $value ? explode(',', $value) : [];
+          }
+          $contactParams['api.entity_tag.replace'] = [
+            'tag_id' => $value,
+          ];
+          break;
+
+        default:
+          $contactParams['api.' . $entity . '.create'][$fieldName] = $value;
+          //@todo we are not currently declaring this option
+          if (isset($params['batch_id']) && strtolower($entity) == 'contribution') {
+            $contactParams['api.' . $entity . '.create']['batch_id'] = $params['batch_id'];
+          }
+          if (isset($params[$entity . '_id'])) {
+            //todo possibly declare $entity_id in getfields ?
+            $contactParams['api.' . $entity . '.create']['id'] = $params[$entity . '_id'];
+          }
       }
     }
     else {
@@ -230,7 +251,7 @@ function civicrm_api3_profile_submit($params) {
     );
   }
 
-  $contactParams['contact_id'] = CRM_Utils_Array::value('contact_id', $params);
+  $contactParams['contact_id'] = empty($params['contact_id']) ? CRM_Utils_Array::value('id', $params) : $params['contact_id'];
   $contactParams['profile_id'] = $profileID;
   $contactParams['skip_custom'] = 1;
 
@@ -291,6 +312,11 @@ function _civicrm_api3_profile_submit_spec(&$params, $apirequest) {
   }
   $params['profile_id']['api.required'] = TRUE;
   $params['profile_id']['title'] = 'Profile ID';
+  // Profile forms submit tag values as a string; hack to get past api wrapper validation
+  if (!empty($params['tag_id'])) {
+    unset($params['tag_id']['pseudoconstant']);
+    $params['tag_id']['type'] = CRM_Utils_Type::T_STRING;
+  }
 }
 
 /**
@@ -663,6 +689,7 @@ function _civicrm_api3_map_profile_fields_to_entity(&$field) {
     'soft_credit_type' => 'contribution_soft',
     'group' => 'group_contact',
     'tag' => 'entity_tag',
+    'note' => 'note',
   );
   if (array_key_exists($fieldName, $hardCodedEntityMappings)) {
     $entity = $hardCodedEntityMappings[$fieldName];
index e09abecfb0200e13ae9cf6127b6858e2d691490c..1ceee078b704e5fc9bcdfdc1cc4e7792b774f24c 100644 (file)
@@ -85,7 +85,7 @@ class api_v3_ProfileTest extends CiviUnitTestCase {
    */
   public function testProfileGet() {
     $profileFieldValues = $this->_createIndividualContact();
-    $expected = current($profileFieldValues);
+    $expected = reset($profileFieldValues);
     $contactId = key($profileFieldValues);
     $params = array(
       'profile_id' => $this->_profileID,
@@ -99,7 +99,7 @@ class api_v3_ProfileTest extends CiviUnitTestCase {
 
   public function testProfileGetMultiple() {
     $profileFieldValues = $this->_createIndividualContact();
-    $expected = current($profileFieldValues);
+    $expected = reset($profileFieldValues);
     $contactId = key($profileFieldValues);
     $params = array(
       'profile_id' => array($this->_profileID, 1, 'Billing'),
@@ -382,9 +382,8 @@ class api_v3_ProfileTest extends CiviUnitTestCase {
    * Check with missing required field in profile.
    */
   public function testProfileSubmitCheckProfileRequired() {
-    $pofileFieldValues = $this->_createIndividualContact();
-    current($pofileFieldValues);
-    $contactId = key($pofileFieldValues);
+    $profileFieldValues = $this->_createIndividualContact();
+    $contactId = key($profileFieldValues);
     $updateParams = array(
       'first_name' => 'abc2',
       'last_name' => 'xyz2',
@@ -406,9 +405,8 @@ class api_v3_ProfileTest extends CiviUnitTestCase {
    * Check with success.
    */
   public function testProfileSubmit() {
-    $pofileFieldValues = $this->_createIndividualContact();
-    current($pofileFieldValues);
-    $contactId = key($pofileFieldValues);
+    $profileFieldValues = $this->_createIndividualContact();
+    $contactId = key($profileFieldValues);
 
     $updateParams = array(
       'first_name' => 'abc2',
@@ -505,9 +503,8 @@ class api_v3_ProfileTest extends CiviUnitTestCase {
    * Set is deprecated but we need to ensure it still works.
    */
   public function testLegacySet() {
-    $pofileFieldValues = $this->_createIndividualContact();
-    current($pofileFieldValues);
-    $contactId = key($pofileFieldValues);
+    $profileFieldValues = $this->_createIndividualContact();
+    $contactId = key($profileFieldValues);
 
     $updateParams = array(
       'first_name' => 'abc2',
@@ -706,6 +703,65 @@ class api_v3_ProfileTest extends CiviUnitTestCase {
     }
   }
 
+  /**
+   * Check success with tags.
+   */
+  public function testSubmitWithTags() {
+    $profileFieldValues = $this->_createIndividualContact();
+    $params = reset($profileFieldValues);
+    $contactId = key($profileFieldValues);
+    $params['profile_id'] = $this->_profileID;
+    $params['contact_id'] = $contactId;
+
+    $this->callAPISuccess('ufField', 'create', array(
+      'uf_group_id' => $this->_profileID,
+      'field_name' => 'tag',
+      'visibility' => 'Public Pages and Listings',
+      'field_type' => 'Contact',
+      'label' => 'Tags',
+    ));
+
+    $tag_1 = $this->callAPISuccess('tag', 'create', ['name' => 'abc'])['id'];
+    $tag_2 = $this->callAPISuccess('tag', 'create', ['name' => 'def'])['id'];
+
+    $params['tag'] = "$tag_1,$tag_2";
+    $result = $this->callAPISuccess('profile', 'submit', $params);
+
+    $tags = $this->callAPISuccess('entityTag', 'get', ['entity_id' => $contactId]);
+    $this->assertEquals(2, $tags['count']);
+
+    $params['tag'] = [$tag_1];
+    $result = $this->callAPISuccess('profile', 'submit', $params);
+
+    $tags = $this->callAPISuccess('entityTag', 'get', ['entity_id' => $contactId]);
+    $this->assertEquals(1, $tags['count']);
+  }
+
+  /**
+   * Check success with a note.
+   */
+  public function testSubmitWithNote() {
+    $profileFieldValues = $this->_createIndividualContact();
+    $params = reset($profileFieldValues);
+    $contactId = key($profileFieldValues);
+    $params['profile_id'] = $this->_profileID;
+    $params['contact_id'] = $contactId;
+
+    $this->callAPISuccess('ufField', 'create', array(
+      'uf_group_id' => $this->_profileID,
+      'field_name' => 'note',
+      'visibility' => 'Public Pages and Listings',
+      'field_type' => 'Contact',
+      'label' => 'Note',
+    ));
+
+    $params['note'] = "Hello 123";
+    $this->callAPISuccess('profile', 'submit', $params);
+
+    $note = $this->callAPISuccessGetSingle('note', ['entity_id' => $contactId]);
+    $this->assertEquals("Hello 123", $note['note']);
+  }
+
   /**
    * Helper function to create an Individual with address/email/phone info. Import UF Group and UF Fields
    * @param array $params