diff --git a/CRM/Core/BAO/CustomField.php b/CRM/Core/BAO/CustomField.php index 6940c885f8a2..e3e565521c42 100644 --- a/CRM/Core/BAO/CustomField.php +++ b/CRM/Core/BAO/CustomField.php @@ -164,6 +164,43 @@ public static function create($params) { return $customField; } + /** + * Create several fields at once in a mysql efficient way. + * + * https://lab.civicrm.org/dev/core/issues/1093 + * + * The intention is that apiv4 would expose any BAO with bulkCreate as a new action. + * + * Note that in the first instance this supports 'create' only. It's possible edit + * is fine in the same function - just treading slowly. + * + * @param array $bulkParams + * Array of arrays as would be passed into create + * @param array $defaults + * Default parameters to be be merged into each of the params. + */ + public static function bulkCreate($bulkParams, $defaults) { + $sql = []; + $customFields = []; + foreach ($bulkParams as $fieldParams) { + $params = array_merge($defaults, $fieldParams); + $customField = self::createCustomFieldRecord($params); + // Only doing 'add' for now - so hard coded & no indexExists. + $fieldSQL = self::getAlterFieldSQL($customField, 'add', $params); + $sql[$params['table_name']][] = $fieldSQL; + $customFields[] = $customField; + } + foreach ($sql as $tableName => $statements) { + // CRM-7007: do not i18n-rewrite this query + CRM_Core_DAO::executeQuery("ALTER TABLE $tableName " . implode(', ', $statements), [], TRUE, NULL, FALSE, FALSE); + Civi::service('sql_triggers')->rebuild($params['table_name'], TRUE); + } + CRM_Utils_System::flushCache(); + foreach ($customFields as $customField) { + CRM_Utils_Hook::post('create', 'CustomField', $customField->id, $customField); + } + } + /** * Fetch object based on array of properties. * diff --git a/CRM/Utils/Migrate/Import.php b/CRM/Utils/Migrate/Import.php index 340e10d51a6d..9315339212d6 100644 --- a/CRM/Utils/Migrate/Import.php +++ b/CRM/Utils/Migrate/Import.php @@ -386,6 +386,7 @@ public function customFields(&$xml, &$idMap) { // Only rebuild the table's trigger on the last field added to avoid un-necessary // and slow rebuilds when adding many fields at the same time. + // @todo - call bulkCreate instead. $triggerRebuild = FALSE; if ($count == $total) { $triggerRebuild = TRUE; diff --git a/tests/phpunit/CRM/Core/BAO/CustomFieldTest.php b/tests/phpunit/CRM/Core/BAO/CustomFieldTest.php index 70449f8d6ccb..0865f3090afc 100644 --- a/tests/phpunit/CRM/Core/BAO/CustomFieldTest.php +++ b/tests/phpunit/CRM/Core/BAO/CustomFieldTest.php @@ -636,4 +636,37 @@ public function testGetFieldsForImport() { $this->assertEquals($expected, CRM_Core_BAO_CustomField::getFieldsForImport()); } + /** + * Test the bulk create function works. + */ + public function testBulkCreate() { + $customGroup = $this->customGroupCreate([ + 'extends' => 'Individual', + 'title' => 'my bulk group', + ]); + CRM_Core_BAO_CustomField::bulkCreate([ + [ + 'label' => 'Test', + 'data_type' => 'String', + 'html_type' => 'Text', + 'column_name' => 'my_text', + ], + [ + 'label' => 'test_link', + 'data_type' => 'Link', + 'html_type' => 'Link', + 'is_search_range' => '0', + ], + ], + [ + 'custom_group_id' => $customGroup['id'], + 'is_active' => 1, + 'is_searchable' => 1, + ]); + $dao = CRM_Core_DAO::executeQuery(('SHOW CREATE TABLE ' . $customGroup['values'][$customGroup['id']]['table_name'])); + $dao->fetch(); + $this->assertContains('`test_link_2` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL', $dao->Create_Table); + $this->assertContains('KEY `INDEX_my_text` (`my_text`)', $dao->Create_Table); + } + }