The special-purpose API "Mailing.preview_recipients" is no longer necessary. Instead,
one can chain simpler APIs ("Mailing.create" + "MailingRecipients.get" + "force_rollback")
return civicrm_api3_create_success($params);
}
-/**
- * Generate a list of likely recipients for a (hypothetical) mailing.
- *
- * "Mailing.preview_recipients" == "Mailing.create" + "MailingRecipients.get" + "rollback"
- *
- * Ideally, we could add a "force_rollback" option to the API; then downstream code could
- * combine the actions without needing this function.
- *
- * @param array $params
- * @return array list of recipients
- * @throws API_Exception
- */
-function civicrm_api3_mailing_preview_recipients($params) {
- static $nextId = 0;
- $savePoint = "civimail_preview_" . ++$nextId;
- $tx = new CRM_Core_Transaction();
- CRM_Core_DAO::executeQuery("SAVEPOINT $savePoint");
-
- // We manually apply defaults (rather than using API defaults) because
- // (a) these are temporary/non-sense values and (b) we want to
- // apply defaults regardless of whether mailing has NULL/''/real-value.
- $params['name'] = 'Placeholder (not saved)';
- $params['subject'] = 'Placeholder (not saved)';
- $params['scheduled_date'] = date('YmdHis', time() + 24*60*60);
-
- // "Mailing.preview_recipients" == "Mailing.create"+"MailingRecipients.get"
- $params['debug'] = 1;
- $params['version'] = 3;
- $params['options']['force_rollback'] = 1;
- $params['api.MailingRecipients.get'] = array(
- 'options' => array(
- 'limit' => isset($params['options']['limit']) ? $params['options']['limit'] : 1000,
- ),
- 'api.contact.getvalue' => array(
- 'return' => 'display_name',
- ),
- 'api.email.getvalue' => array(
- 'return' => 'email',
- ),
- );
-
- try {
- $mailing = civicrm_api3('Mailing', 'create', $params);
- } catch (Exception $ex) {
- CRM_Core_DAO::executeQuery("ROLLBACK TO SAVEPOINT $savePoint");
- throw $ex;
- }
-
- CRM_Core_DAO::executeQuery("ROLLBACK TO SAVEPOINT $savePoint");
- return civicrm_api3_create_success($mailing['values'][$mailing['id']]['api.MailingRecipients.get']['values']);
-}
-
function civicrm_api3_mailing_preview($params) {
civicrm_api3_verify_mandatory($params,
'CRM_Mailing_DAO_Mailing',
// Time to wait before triggering AJAX update to recipients list
var RECIPIENTS_DEBOUNCE_MS = 100;
+ var RECIPIENTS_PREVIEW_LIMIT = 10000;
/**
* Initialize a new mailing
return ts('No recipients');
if ($scope.recipients.length == 1)
return ts('~1 recipient');
+ if (RECIPIENTS_PREVIEW_LIMIT > 0 && $scope.recipients.length >= RECIPIENTS_PREVIEW_LIMIT)
+ return ts('>%1 recipients', {1: RECIPIENTS_PREVIEW_LIMIT});
return ts('~%1 recipients', {1: $scope.recipients.length});
};
// We monitor four fields -- use debounce so that changes across the
var refreshRecipients = _.debounce(function () {
$scope.$apply(function () {
$scope.recipients = null;
- crmApi('Mailing', 'preview_recipients', $scope.mailing)
+ // To get list of recipients, we tentatively save the mailing and
+ // get the resulting recipients -- then rollback any changes.
+ var params = _.extend({}, $scope.mailing, {
+ options: {force_rollback: 1},
+ 'api.MailingRecipients.get': {
+ mailing_id: '$value.id',
+ options: {limit: RECIPIENTS_PREVIEW_LIMIT},
+ 'api.contact.getvalue': {'return': 'display_name'},
+ 'api.email.getvalue': {'return': 'email'}
+ }
+ });
+
+ crmApi('Mailing', 'create', params)
.then(function (recipResult) {
$scope.$apply(function () {
- $scope.recipients = recipResult.values;
+ $scope.recipients = recipResult.values[recipResult.id]['api.MailingRecipients.get'].values;
});
});
});
// BEGIN SAMPLE DATA
$this->groupIDs['inc'] = $this->groupCreate(array('name' => 'Example include group', 'title' => 'Example include group'));
$this->groupIDs['exc'] = $this->groupCreate(array('name' => 'Example exclude group', 'title' => 'Example exclude group'));
- $this->contactIDs['includeme'] = $this->individualCreate(array('include.me@example.org'));
- $this->contactIDs['excludeme'] = $this->individualCreate(array('exclude.me@example.org'));
+ $this->contactIDs['includeme'] = $this->individualCreate(array('email' => 'include.me@example.org', 'first_name' => 'Includer', 'last_name' => 'Person'));
+ $this->contactIDs['excludeme'] = $this->individualCreate(array('email' => 'exclude.me@example.org', 'last_name' => 'Excluder', 'last_name' => 'Excluder'));
$this->callAPISuccess('GroupContact', 'create', array('group_id' => $this->groupIDs['inc'], 'contact_id' => $this->contactIDs['includeme']));
$this->callAPISuccess('GroupContact', 'create', array('group_id' => $this->groupIDs['inc'], 'contact_id' => $this->contactIDs['excludeme']));
$this->callAPISuccess('GroupContact', 'create', array('group_id' => $this->groupIDs['exc'], 'contact_id' => $this->contactIDs['excludeme']));
$params['groups']['exclude'] = array($this->groupIDs['exc']);
$params['mailings']['include'] = array();
$params['mailings']['exclude'] = array();
+ $params['options']['force_rollback'] = 1;
+ $params['api.MailingRecipients.get'] = array(
+ 'mailing_id' => '$value.id',
+ 'api.contact.getvalue' => array(
+ 'return' => 'display_name',
+ ),
+ 'api.email.getvalue' => array(
+ 'return' => 'email',
+ ),
+ );
// END SAMPLE DATA
$maxIDs = array(
'job' => CRM_Core_DAO::singleValueQuery('SELECT MAX(id) FROM civicrm_mailing_job'),
'group' => CRM_Core_DAO::singleValueQuery('SELECT MAX(id) FROM civicrm_mailing_group'),
);
- $preview = $this->callAPIAndDocument('Mailing', 'preview_recipients', $params, __FUNCTION__, __FILE__);
+ $create = $this->callAPIAndDocument('Mailing', 'create', $params, __FUNCTION__, __FILE__);
$this->assertDBQuery($maxIDs['mailing'], 'SELECT MAX(id) FROM civicrm_mailing'); // 'Preview should not create any mailing records'
$this->assertDBQuery($maxIDs['job'], 'SELECT MAX(id) FROM civicrm_mailing_job'); // 'Preview should not create any mailing_job record'
$this->assertDBQuery($maxIDs['group'], 'SELECT MAX(id) FROM civicrm_mailing_group'); // 'Preview should not create any mailing_group records'
+ $preview = $create['values'][$create['id']]['api.MailingRecipients.get'];
$previewIds = array_values(CRM_Utils_Array::collect('contact_id', $preview['values']));
$this->assertEquals(array((string)$this->contactIDs['includeme']), $previewIds);
+ $previewEmails = array_values(CRM_Utils_Array::collect('api.email.getvalue', $preview['values']));
+ $this->assertEquals(array('include.me@example.org'), $previewEmails);
+ $previewNames = array_values(CRM_Utils_Array::collect('api.contact.getvalue', $preview['values']));
+ $this->assertTrue((bool)preg_match('/Includer Person/', $previewNames[0]), "Name 'Includer Person' should appear in '" . $previewNames[0] . '"');
}
public function testMailerSendTestMail() {