namespace Civi\Api4\Service\Spec\Provider;
+use Civi\Api4\Query\Api4SelectQuery;
use Civi\Api4\Service\Spec\FieldSpec;
use Civi\Api4\Service\Spec\RequestSpec;
$spec->getFieldByName('activity_type_id')
->setDefaultValue(NULL)
->setRequired($action === 'create');
+ }
+ if (in_array($action, ['get', 'create', 'update'], TRUE)) {
$field = new FieldSpec('source_contact_id', 'Activity', 'Integer');
$field->setTitle(ts('Source Contact'));
$field->setLabel(ts('Added by'));
$field->setRequired($action === 'create');
$field->setFkEntity('Contact');
$field->setInputType('EntityRef');
+ $field->setSqlRenderer([__CLASS__, 'renderSqlForActivityContactIds']);
$spec->addFieldSpec($field);
$field = new FieldSpec('target_contact_id', 'Activity', 'Array');
$field->setTitle(ts('Target Contacts'));
- $field->setLabel(ts('With Contact(s)'));
- $field->setDescription(ts('Contact(s) involved in this activity.'));
+ $field->setLabel(ts('With Contacts'));
+ $field->setDescription(ts('Contacts involved in this activity.'));
$field->setFkEntity('Contact');
$field->setInputType('EntityRef');
$field->setInputAttrs(['multiple' => TRUE]);
+ $field->setSqlRenderer([__CLASS__, 'renderSqlForActivityContactIds']);
+ $field->addOutputFormatter([__CLASS__, 'formatOutputForMultipleActivityContactIds']);
$spec->addFieldSpec($field);
$field = new FieldSpec('assignee_contact_id', 'Activity', 'Array');
$field->setTitle(ts('Assignee Contacts'));
$field->setLabel(ts('Assigned to'));
- $field->setDescription(ts('Contact(s) assigned to this activity.'));
+ $field->setDescription(ts('Contacts assigned to this activity.'));
$field->setFkEntity('Contact');
$field->setInputType('EntityRef');
$field->setInputAttrs(['multiple' => TRUE]);
+ $field->setSqlRenderer([__CLASS__, 'renderSqlForActivityContactIds']);
+ $field->addOutputFormatter([__CLASS__, 'formatOutputForMultipleActivityContactIds']);
$spec->addFieldSpec($field);
}
}
return $entity === 'Activity';
}
+ public static function renderSqlForActivityContactIds(array $field, Api4SelectQuery $query): string {
+ $contactLinkTypes = [
+ 'source_contact_id' => 'Activity Source',
+ 'target_contact_id' => 'Activity Targets',
+ 'assignee_contact_id' => 'Activity Assignees',
+ ];
+ $recordTypeId = \CRM_Core_PseudoConstant::getKey(
+ 'CRM_Activity_BAO_ActivityContact',
+ 'record_type_id',
+ $contactLinkTypes[$field['name']]);
+ return '(SELECT GROUP_CONCAT(`civicrm_activity_contact`.`contact_id`) '
+ . 'FROM `civicrm_activity_contact` '
+ . 'WHERE `civicrm_activity_contact`.`activity_id` = `a`.`id` '
+ . 'AND record_type_id = ' . $recordTypeId . ')';
+ }
+
+ public static function formatOutputForMultipleActivityContactIds(
+ ?string &$value, array $row, array $field
+ ): void {
+ $value = explode(',', $value ?? '');
+ }
+
}
*/
public function testCreateDocumentBasicTokens(): void {
CRM_Core_BAO_ConfigSetting::enableComponent('CiviCase');
- $case = $this->createCase($this->individualCreate());
+ $sourceContactId = $this->individualCreate();
+ $case = $this->createCase($sourceContactId);
$activity = $this->activityCreate([
'campaign_id' => $this->campaignCreate(),
'case_id' => $case->id,
+ 'source_contact_id' => $sourceContactId,
]);
$data = [
['Subject: {activity.subject}', 'Subject: Discussion on warm beer'],
['(legacy) Activity ID: {activity.activity_id}', '(legacy) Activity ID: ' . $activity['id']],
['Activity ID: {activity.id}', 'Activity ID: ' . $activity['id']],
['(APIv4 virtual field) Case ID: {activity.case_id}', '(APIv4 virtual field) Case ID: ' . $case->id],
+ ['(APIv4 virtual field) Source Contact ID: {activity.source_contact_id}', '(APIv4 virtual field) Source Contact ID: ' . $sourceContactId],
+ ['(APIv4 virtual field) Target Contact IDs: {activity.target_contact_id}', '(APIv4 virtual field) Target Contact IDs: ' . $activity['target_contact_id']],
+ ['(APIv4 virtual field) Assignee Contact IDs: {activity.assignee_contact_id}', '(APIv4 virtual field) Assignee Contact IDs: ' . $activity['assignee_contact_id']],
];
$tokenProcessor = new TokenProcessor(Civi::dispatcher(), ['schema' => ['activityId']]);
'{activity.status_id:label}' => 'Activity Status',
'{activity.campaign_id:label}' => 'Campaign',
'{activity.case_id}' => 'Case ID',
+ '{activity.source_contact_id}' => 'Source Contact',
+ '{activity.target_contact_id}' => 'Target Contacts',
+ '{activity.assignee_contact_id}' => 'Assignee Contacts',
];
}
$this->assertEquals($expectedActivityContacts, $activityContacts, "ActivityContacts not as expected after update.");
}
+ public function testActivityCreateAndGetVirtualFields() {
+ $meetingActivityTypeID = \Civi\Api4\OptionValue::get()
+ ->addSelect('value')
+ ->addWhere('option_group_id:name', '=', 'activity_type')
+ ->execute()->first()['value'];
+
+ $sourceContactId = \CRM_Core_BAO_Domain::getDomain()->contact_id;
+ $c1 = Contact::create(FALSE)->addValue('first_name', '1')->execute()->first()['id'];
+ $c2 = Contact::create(FALSE)->addValue('first_name', '2')->execute()->first()['id'];
+ $c3 = Contact::create(FALSE)->addValue('first_name', '3')->execute()->first()['id'];
+ $c4 = Contact::create(FALSE)->addValue('first_name', '4')->execute()->first()['id'];
+
+ $targetContactIds = [$c1, $c2];
+ $assigneeContactIds = [$c3, $c4];
+
+ // Test that we can write to and read from the virtual fields.
+ $activityID = Activity::create(FALSE)
+ ->setValues([
+ 'target_contact_id' => $targetContactIds,
+ 'assignee_contact_id' => $assigneeContactIds,
+ 'activity_type_id' => $meetingActivityTypeID,
+ 'source_contact_id' => $sourceContactId,
+ 'subject' => 'test activity',
+ ])->execute()->first()['id'];
+
+ $activity = Activity::get(FALSE)
+ ->addSelect('id', 'source_contact_id', 'target_contact_id', 'assignee_contact_id')
+ ->addWhere('id', '=', $activityID)
+ ->execute()->first();
+
+ $this->assertEquals($sourceContactId, $activity['source_contact_id']);
+ $this->assertEquals($targetContactIds, $activity['target_contact_id']);
+ $this->assertEquals($assigneeContactIds, $activity['assignee_contact_id']);
+ }
+
}