if ($address->id) {
// first get custom field from master address if any
if (isset($params['master_id']) && !CRM_Utils_System::isNull($params['master_id'])) {
- $address->copyCustomFields($params['master_id'], $address->id);
+ $address->copyCustomFields($params['master_id'], $address->id, $hook);
}
if (isset($params['custom'])) {
if (!empty($customValue['id'])) {
$cvParam['id'] = $customValue['id'];
}
+ elseif (empty($cvParam['is_multiple']) && !empty($entityID)) {
+ // dev/core#3000 Ensure that if we are not dealing with multiple record custom data and for some reason have got here without getting the id of the record in the custom table for this entityId let us give it one last shot
+ $rowId = CRM_Core_DAO::singleValueQuery("SELECT id FROM {$cvParam['table_name']} WHERE entity_id = %1", [1 => [$entityID, 'Integer']]);
+ if (!empty($rowId)) {
+ $cvParam['id'] = $rowId;
+ }
+ }
if (!array_key_exists($customValue['table_name'], $cvParams)) {
$cvParams[$customValue['table_name']] = [];
}
*
* Generated from xml/schema/CRM/Core/CustomField.xml
* DO NOT EDIT. Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:b53a928be3c87ec7da4f88da3ec825b8)
+ * (GenCodeChecksum:c093cac865bba7796c2c7deda6579f40)
*/
/**
*/
public static $_log = TRUE;
+ /**
+ * Paths for accessing this entity in the UI.
+ *
+ * @var string[]
+ */
+ protected static $_paths = [
+ 'add' => 'civicrm/admin/custom/group/field/add?reset=1&action=add&gid=[custom_group_id]',
+ 'update' => 'civicrm/admin/custom/group/field/update?action=update&reset=1&id=[id]&gid=[custom_group_id]',
+ 'preview' => 'civicrm/admin/custom/group/field?action=preview&reset=1&id=[id]&gid=[custom_group_id]',
+ 'delete' => 'civicrm/admin/custom/group/field?action=delete&reset=1&id=[id]&gid=[custom_group_id]',
+ 'move' => 'civicrm/admin/custom/group/field/move?reset=1&fid=[id]',
+ ];
+
/**
* Unique Custom Field ID
*
*
* Generated from xml/schema/CRM/Core/CustomGroup.xml
* DO NOT EDIT. Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:27a1b80ba9d2696e97dd1df33468caff)
+ * (GenCodeChecksum:57ebfb396e58116709f9d883a46edfa7)
*/
/**
*/
public static $_log = TRUE;
+ /**
+ * Paths for accessing this entity in the UI.
+ *
+ * @var string[]
+ */
+ protected static $_paths = [
+ 'add' => 'civicrm/admin/custom/group?action=add&reset=1',
+ 'update' => 'civicrm/admin/custom/group?action=update&reset=1&id=[id]',
+ 'preview' => 'civicrm/admin/custom/group?action=preview&reset=1&id=[id]',
+ 'delete' => 'civicrm/admin/custom/group?action=delete&reset=1&id=[id]',
+ ];
+
/**
* Unique Custom Group ID
*
}
$options = _civicrm_api3_get_options_from_params($params, TRUE, 'contribution', 'get');
$fnName = '_civicrm_api3_mailing_contact_get_' . strtolower($params['type']);
+ if (!function_exists($fnName)) {
+ throw new API_Exception('Invalid mailing type: ' . $params['type']);
+ }
return $fnName(
$params['contact_id'],
$options['offset'],
foreach ($finalfields as $fieldInfo) {
$fieldName = $fieldInfo['name'];
try {
- _civicrm_api3_validate_switch_cases($fieldName, $fieldInfo, $entity, $params);
+ _civicrm_api3_validate_switch_cases($fieldName, $fieldInfo, $entity, $params, $action);
}
catch (Exception $e) {
$errors[$fieldName] = [
* @param array $fieldInfo
* @param string $entity
* @param array $params
+ * @param string $action
*
* @throws API_Exception
* @throws Exception
*/
-function _civicrm_api3_validate_switch_cases($fieldName, $fieldInfo, $entity, $params) {
+function _civicrm_api3_validate_switch_cases($fieldName, $fieldInfo, $entity, $params, $action) {
switch (CRM_Utils_Array::value('type', $fieldInfo)) {
case CRM_Utils_Type::T_INT:
_civicrm_api3_validate_integer($params, $fieldName, $fieldInfo, $entity);
case CRM_Utils_Type::T_TEXT:
case CRM_Utils_Type::T_STRING:
- _civicrm_api3_validate_string($params, $fieldName, $fieldInfo, $entity);
+ _civicrm_api3_validate_string($params, $fieldName, $fieldInfo, $entity, $action);
break;
case CRM_Utils_Type::T_MONEY:
case CRM_Utils_Type::T_TEXT:
case CRM_Utils_Type::T_STRING:
- _civicrm_api3_validate_string($params, $fieldName, $fieldInfo, $entity);
+ _civicrm_api3_validate_string($params, $fieldName, $fieldInfo, $entity, $action);
break;
case CRM_Utils_Type::T_MONEY:
* @param array $fieldInfo
* Array of fields from getfields function.
* @param string $entity
+ * @param string $action
*
* @throws API_Exception
* @throws Exception
*/
-function _civicrm_api3_validate_string(&$params, &$fieldName, &$fieldInfo, $entity) {
+function _civicrm_api3_validate_string(&$params, &$fieldName, &$fieldInfo, $entity, $action) {
+ $isGet = substr($action, 0, 3) === 'get';
list($fieldValue, $op) = _civicrm_api3_field_value_check($params, $fieldName, 'String');
if (strpos($op, 'NULL') !== FALSE || strpos($op, 'EMPTY') !== FALSE || CRM_Utils_System::isNull($fieldValue)) {
return;
}
}
if (!empty($fieldInfo['pseudoconstant']) || !empty($fieldInfo['options'])) {
- _civicrm_api3_api_match_pseudoconstant($fieldValue, $entity, $fieldName, $fieldInfo, $op);
+ try {
+ _civicrm_api3_api_match_pseudoconstant($fieldValue, $entity, $fieldName, $fieldInfo, $op);
+ }
+ catch (API_Exception $e) {
+ // For get operations, allow any string
+ if (!$isGet) {
+ throw $e;
+ }
+ }
}
// Check our field length
elseif (is_string($fieldValue) && !empty($fieldInfo['maxlength']) && strlen(utf8_decode($fieldValue)) > $fieldInfo['maxlength']) {
}
// Check access for edit/update links
// (presumably if a record is shown in SearchKit the user already has view access, and the check is expensive)
- if ($path && isset($data) && $link['action'] !== 'view') {
+ if ($path && isset($data) && !in_array($link['action'], ['view', 'preview'], TRUE)) {
$id = $data[$prefix . $idKey] ?? NULL;
$id = is_array($id) ? $id[$index] ?? NULL : $id;
if ($id) {
$access = civicrm_api4($link['entity'], 'checkAccess', [
- 'action' => $link['action'],
+ // Fudge links with funny action names to check 'update'
+ 'action' => $link['action'] === 'delete' ? 'delete' : 'update',
'values' => [
$idField => $id,
],
// Contacts and cases are too cumbersome to view in a popup
'target' => in_array($entity, ['Contact', 'Case']) ? '_blank' : 'crm-popup',
],
+ 'preview' => [
+ 'action' => 'preview',
+ 'entity' => $entity,
+ 'text' => E::ts('Preview %1', $label),
+ 'icon' => 'fa-eye',
+ 'style' => 'default',
+ 'target' => 'crm-popup',
+ ],
'update' => [
'action' => 'update',
'entity' => $entity,
// Contacts and cases are too cumbersome to edit in a popup
'target' => in_array($entity, ['Contact', 'Case']) ? '_blank' : 'crm-popup',
],
+ 'move' => [
+ 'action' => 'move',
+ 'entity' => $entity,
+ 'text' => E::ts('Move %1', $label),
+ 'icon' => 'fa-random',
+ 'style' => 'default',
+ 'target' => 'crm-popup',
+ ],
'delete' => [
'action' => 'delete',
'entity' => $entity,
$this->assertNotContains($this->household, $result['values']);
}
- /**
- * Search with invalid type or subtype.
- */
- public function testSearchWithInvalidData() {
- // for invalid type
- $params = [
- 'contact_type' => 'Invalid' . CRM_Core_DAO::VALUE_SEPARATOR . 'Invalid',
- 'version' => 3,
- ];
- $result = civicrm_api('contact', 'get', $params);
- $this->assertEquals(empty($result['values']), TRUE);
-
- // for invalid subtype
- $params = ['contact_sub_type' => 'Invalid', 'version' => 3];
- $result = civicrm_api('contact', 'get', $params);
- $this->assertEquals(empty($result['values']), TRUE);
-
- // for invalid contact type as well as subtype
- $params = [
- 'contact_type' => 'Invalid' . CRM_Core_DAO::VALUE_SEPARATOR . 'Invalid',
- 'version' => 3,
- ];
- $result = civicrm_api('contact', 'get', $params);
- $this->assertEquals(empty($result['values']), TRUE);
-
- // for valid type and invalid subtype
- $params = [
- 'contact_type' => 'Individual' . CRM_Core_DAO::VALUE_SEPARATOR . 'Invalid',
- 'version' => 3,
- ];
- $result = civicrm_api('contact', 'get', $params);
- $this->assertEquals(empty($result['values']), TRUE);
-
- // for invalid type and valid subtype
- $params = [
- 'contact_type' => 'Invalid' . CRM_Core_DAO::VALUE_SEPARATOR . 'indivi_student',
- 'version' => 3,
- ];
- $result = civicrm_api('contact', 'get', $params);
- $this->assertEquals(empty($result['values']), TRUE);
- }
-
- /**
- * Search with wrong type or subtype.
- */
- public function testSearchWithWrongdData() {
-
- // for type:Individual subtype:Sponsor
- $defaults = [];
- $params = [
- 'contact_type' => 'Individual' . CRM_Core_DAO::VALUE_SEPARATOR . $this->sponsor,
- 'version' => 3,
- ];
- $result = civicrm_api('contact', 'get', $params);
- $this->assertEquals(empty($result['values']), TRUE);
-
- // for type:Orgaization subtype:Parent
- $params = [
- 'contact_type' => 'Orgaization' . CRM_Core_DAO::VALUE_SEPARATOR . $this->parent,
- 'version' => 3,
- ];
- $result = civicrm_api('contact', 'get', $params, $defaults);
- $this->assertEquals(empty($result['values']), TRUE);
-
- // for type:Household subtype:Sponsor
- $params = [
- 'contact_type' => 'Household' . CRM_Core_DAO::VALUE_SEPARATOR . $this->sponsor,
- 'version' => 3,
- ];
- $result = civicrm_api('contact', 'get', $params, $defaults);
- $this->assertEquals(empty($result['values']), TRUE);
-
- // for type:Household subtype:Student
- $params = [
- 'contact_type' => 'Household' . CRM_Core_DAO::VALUE_SEPARATOR . $this->student,
- 'version' => 3,
- ];
- $result = civicrm_api('contact', 'get', $params, $defaults);
- $this->assertEquals(empty($result['values']), TRUE);
- }
-
}
$this->assertNotContains('Alabama', $result['values']);
}
+ public function testUpdateSharedAddressWithCustomFields() {
+ $ids = $this->entityCustomGroupWithSingleFieldCreate(__FUNCTION__, __FILE__);
+
+ $params = $this->_params;
+ $params['custom_' . $ids['custom_field_id']] = "custom string";
+
+ $firstAddress = $this->callAPISuccess($this->_entity, 'create', $params);
+
+ $contactIdB = $this->individualCreate();
+
+ $secondAddressParams = array_merge(['contact_id' => $contactIdB, 'master_id' => $firstAddress['id']], $firstAddress);
+ unset($secondAddressParams['id']);
+ $secondAddress = $this->callAPISuccess('Address', 'create', $secondAddressParams);
+ // Ensure an update to the second address doesn't cause a "db error: already exists" when resaving the custom fields.
+ $this->callAPISuccess('Address', 'create', ['id' => $secondAddress['id'], 'contact_id' => $contactIdB, 'master_id' => $firstAddress['id']]);
+ }
+
}
<add>1.1</add>
<log>true</log>
<labelField>label</labelField>
+ <paths>
+ <add>civicrm/admin/custom/group/field/add?reset=1&action=add&gid=[custom_group_id]</add>
+ <update>civicrm/admin/custom/group/field/update?action=update&reset=1&id=[id]&gid=[custom_group_id]</update>
+ <preview>civicrm/admin/custom/group/field?action=preview&reset=1&id=[id]&gid=[custom_group_id]</preview>
+ <delete>civicrm/admin/custom/group/field?action=delete&reset=1&id=[id]&gid=[custom_group_id]</delete>
+ <move>civicrm/admin/custom/group/field/move?reset=1&fid=[id]</move>
+ </paths>
<field>
<name>id</name>
<type>int unsigned</type>
<log>true</log>
<title>Custom Field Group</title>
<labelField>title</labelField>
+ <paths>
+ <add>civicrm/admin/custom/group?action=add&reset=1</add>
+ <update>civicrm/admin/custom/group?action=update&reset=1&id=[id]</update>
+ <preview>civicrm/admin/custom/group?action=preview&reset=1&id=[id]</preview>
+ <delete>civicrm/admin/custom/group?action=delete&reset=1&id=[id]</delete>
+ </paths>
<field>
<name>id</name>
<type>int unsigned</type>