APIv4 - Use bulk method for saving custom fields
authorColeman Watts <coleman@civicrm.org>
Tue, 11 May 2021 16:34:05 +0000 (12:34 -0400)
committerColeman Watts <coleman@civicrm.org>
Mon, 17 May 2021 02:08:30 +0000 (22:08 -0400)
Renames the prototype bulkSave => writeRecords to follow the convention now in APIv4 and CRM_Core_DAO

CRM/Core/BAO/CustomField.php
Civi/Api4/Generic/Traits/DAOActionTrait.php

index 323b9ce9cdc7f0e8e93fdcaf8e6aba8beab4c1a7..dc0a3f5cc881090657f4a65ab65e40b81b43ab6e 100644 (file)
@@ -109,11 +109,9 @@ class CRM_Core_BAO_CustomField extends CRM_Core_DAO_CustomField {
   }
 
   /**
-   * Create/ update several fields at once in a mysql efficient way.
-   *
+   * Save multiple fields, now deprecated in favor of self::writeRecords.
    * https://lab.civicrm.org/dev/core/issues/1093
-   *
-   * The intention is that apiv4 would expose any BAO with bulkSave as a new action.
+   * @deprecated
    *
    * @param array $bulkParams
    *   Array of arrays as would be passed into create
@@ -123,9 +121,25 @@ class CRM_Core_BAO_CustomField extends CRM_Core_DAO_CustomField {
    * @throws \CiviCRM_API3_Exception
    */
   public static function bulkSave($bulkParams, $defaults = []) {
-    $addedColumns = $sql = $customFields = $pre = $post = [];
     foreach ($bulkParams as $index => $fieldParams) {
-      $params = array_merge($defaults, $fieldParams);
+      $bulkParams[$index] = array_merge($defaults, $fieldParams);
+    }
+    self::writeRecords($bulkParams);
+  }
+
+  /**
+   * Create/update several fields at once in a mysql efficient way.
+   *
+   * @param array $records
+   * @return CRM_Core_DAO_CustomField[]
+   * @throws CRM_Core_Exception
+   * @throws CiviCRM_API3_Exception
+   */
+  public static function writeRecords(array $records) {
+    $addedColumns = $sql = $customFields = $pre = $post = [];
+    foreach ($records as $index => $params) {
+      CRM_Utils_Hook::pre(empty($params['id']) ? 'create' : 'edit', 'CustomField', $params['id'] ?? NULL, $params);
+
       $changeSerialize = self::getChangeSerialize($params);
       $customField = self::createCustomFieldRecord($params);
       // Serialize/deserialize sql must run after/before the table is altered
@@ -136,9 +150,7 @@ class CRM_Core_BAO_CustomField extends CRM_Core_DAO_CustomField {
         $post[] = self::getAlterSerializeSQL($customField);
       }
       $fieldSQL = self::getAlterFieldSQL($customField, empty($params['id']) ? 'add' : 'modify');
-      if (!isset($params['custom_group_id'])) {
-        $params['custom_group_id'] = civicrm_api3('CustomField', 'getvalue', ['id' => $customField->id, 'return' => 'custom_group_id']);
-      }
+
       $tableName = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomGroup', $customField->custom_group_id, 'table_name');
       $sql[$tableName][] = $fieldSQL;
       $addedColumns[$tableName][] = $customField->name;
@@ -166,9 +178,12 @@ class CRM_Core_BAO_CustomField extends CRM_Core_DAO_CustomField {
     }
 
     CRM_Utils_System::flushCache();
+    Civi::cache('metadata')->clear();
+
     foreach ($customFields as $index => $customField) {
-      CRM_Utils_Hook::post(empty($bulkParams[$index]['id']) ? 'create' : 'edit', 'CustomField', $customField->id, $customField);
+      CRM_Utils_Hook::post(empty($records[$index]['id']) ? 'create' : 'edit', 'CustomField', $customField->id, $customField);
     }
+    return $customFields;
   }
 
   /**
index c06475ce8efca51f1ff4306d940c2b1b1ecf8288..88d1a612cd4f82522125b6be501394363481672e 100644 (file)
@@ -106,15 +106,16 @@ trait DAOActionTrait {
   protected function writeObjects(&$items) {
     $baoName = $this->getBaoName();
 
-    // Some BAOs are weird and don't support a straightforward "create" method.
-    $oddballs = [
+    // TODO: Opt-in more entities to use the new writeRecords BAO method.
+    $functionNames = [
       'Address' => 'add',
+      'CustomField' => 'writeRecords',
       'EntityTag' => 'add',
       'GroupContact' => 'add',
     ];
-    $method = $oddballs[$this->getEntityName()] ?? 'create';
-    if (!method_exists($baoName, $method)) {
-      $method = method_exists($baoName, 'add') ? 'add' : FALSE;
+    $method = $functionNames[$this->getEntityName()] ?? NULL;
+    if (!isset($method)) {
+      $method = method_exists($baoName, 'create') ? 'create' : (method_exists($baoName, 'add') ? 'add' : 'writeRecords');
     }
 
     $result = [];
@@ -124,8 +125,8 @@ trait DAOActionTrait {
       FormattingUtil::formatWriteParams($item, $this->entityFields());
       $this->formatCustomParams($item, $entityId);
 
-      // Skip to writeRecords if not using legacy method
-      if (!$method) {
+      // Skip individual processing if using writeRecords
+      if ($method === 'writeRecords') {
         continue;
       }
       $item['check_permissions'] = $this->getCheckPermissions();
@@ -156,7 +157,7 @@ trait DAOActionTrait {
 
     // Use bulk `writeRecords` method if the BAO doesn't have a create or add method
     // TODO: reverse this from opt-in to opt-out and default to using `writeRecords` for all BAOs
-    if (!$method) {
+    if ($method === 'writeRecords') {
       $items = array_values($items);
       foreach ($baoName::writeRecords($items) as $i => $createResult) {
         $result[] = $this->baoToArray($createResult, $items[$i]);