<?php/* +--------------------------------------------------------------------+ | CiviCRM version 2.0 | +--------------------------------------------------------------------+ | Copyright CiviCRM LLC (c) 2004-2007 | +--------------------------------------------------------------------+ | This file is a part of CiviCRM. | | | | CiviCRM is free software; you can copy, modify, and distribute it | | under the terms of the GNU Affero General Public License | | Version 3, 19 November 2007. | | | | CiviCRM is distributed in the hope that it will be useful, but | | WITHOUT ANY WARRANTY; without even the implied warranty of | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | | See the GNU Affero General Public License for more details. | | | | You should have received a copy of the GNU Affero General Public | | License along with this program; if not, contact CiviCRM LLC | | at info[AT]civicrm[DOT]org. If you have questions about the | | GNU Affero General Public License or the licensing of CiviCRM, | | see the CiviCRM license FAQ at http://civicrm.org/licensing | +--------------------------------------------------------------------+*//** * * @package CRM * @copyright CiviCRM LLC (c) 2004-2007 * $Id$ * */require_once 'Mail/mime.php';require_once 'CRM/Contact/BAO/SavedSearch.php';require_once 'CRM/Contact/BAO/Query.php';require_once 'CRM/Contact/BAO/Group.php';require_once 'CRM/Mailing/DAO/Mailing.php';require_once 'CRM/Mailing/DAO/Group.php';require_once 'CRM/Mailing/Event/BAO/Queue.php';require_once 'CRM/Mailing/Event/BAO/Delivered.php';require_once 'CRM/Mailing/Event/BAO/Bounce.php';require_once 'CRM/Mailing/BAO/TrackableURL.php';require_once 'CRM/Mailing/BAO/Component.php';require_once 'CRM/Mailing/BAO/Spool.php';class CRM_Mailing_BAO_Mailing extends CRM_Mailing_DAO_Mailing { /** * An array that holds the complete templates * including any headers or footers that need to be prepended * or appended to the body */ private $preparedTemplates = null; /** * An array that holds the complete templates * including any headers or footers that need to be prepended * or appended to the body */ private $templates = null; /** * An array that holds the tokens that are specifically found in our text and html bodies */ private $tokens = null; /** * The header associated with this mailing */ private $header = null; /** * The footer associated with this mailing */ private $footer = null; /** * The HTML content of the message */ private $html = null; /** * The text content of the message */ private $text = null; /** * Cached BAO for the domain */ private $_domain = null; /** * class constructor */ function __construct( ) { parent::__construct( ); } /** * Find all intended recipients of a mailing * * @param int $job_id Job ID * @param bool $includeDelivered Whether to include the recipients who already got the mailing * @return object A DAO loaded with results of the form (email_id, contact_id) */ function &getRecipientsObject($job_id, $includeDelivered = false) { $eq = self::getRecipients($job_id, $includeDelivered, $this->id); return $eq; } function &getRecipientsCount($job_id, $includeDelivered = false, $mailing_id = null) { $eq = self::getRecipients($job_id, $includeDelivered, $mailing_id); return $eq->N; } function &getRecipients($job_id, $includeDelivered = false, $mailing_id = null) { $mailingGroup =& new CRM_Mailing_DAO_Group(); $mailing = CRM_Mailing_BAO_Mailing::getTableName(); $job = CRM_Mailing_BAO_Job::getTableName(); $mg = CRM_Mailing_DAO_Group::getTableName(); $eq = CRM_Mailing_Event_DAO_Queue::getTableName(); $ed = CRM_Mailing_Event_DAO_Delivered::getTableName(); $eb = CRM_Mailing_Event_DAO_Bounce::getTableName(); $email = CRM_Core_DAO_Email::getTableName(); $contact = CRM_Contact_DAO_Contact::getTableName(); require_once 'CRM/Contact/DAO/Group.php'; $group = CRM_Contact_DAO_Group::getTableName(); $g2contact = CRM_Contact_DAO_GroupContact::getTableName(); /* Create a temp table for contact exclusion */ $mailingGroup->query( "CREATE TEMPORARY TABLE X_$job_id (contact_id int primary key) ENGINE=HEAP" ); /* Add all the members of groups excluded from this mailing to the temp * table */ $excludeSubGroup = "INSERT INTO X_$job_id (contact_id) SELECT DISTINCT $g2contact.contact_id FROM $g2contact INNER JOIN $mg ON $g2contact.group_id = $mg.entity_id AND $mg.entity_table = '$group' WHERE $mg.mailing_id = {$mailing_id} AND $g2contact.status = 'Added' AND $mg.group_type = 'Exclude'"; $mailingGroup->query($excludeSubGroup); /* Add all the (intended) recipients of an excluded prior mailing to * the temp table */ $excludeSubMailing = "INSERT IGNORE INTO X_$job_id (contact_id) SELECT DISTINCT $eq.contact_id FROM $eq INNER JOIN $job ON $eq.job_id = $job.id INNER JOIN $mg ON $job.mailing_id = $mg.entity_id AND $mg.entity_table = '$mailing' WHERE $mg.mailing_id = {$mailing_id} AND $mg.group_type = 'Exclude'"; $mailingGroup->query($excludeSubMailing); $ss =& new CRM_Core_DAO(); $ss->query( "SELECT $group.saved_search_id as saved_search_id, $group.id as id FROM $group INNER JOIN $mg ON $mg.entity_id = $group.id WHERE $mg.entity_table = '$group' AND $mg.group_type = 'Exclude' AND $mg.mailing_id = {$mailing_id} AND $group.saved_search_id IS NOT null"); $whereTables = array( ); while ( $ss->fetch( ) ) { /* run the saved search query and dump result contacts into the temp * table */ $tables = array($contact => 1); $sql = CRM_Contact_BAO_SavedSearch::contactIDsSQL( $ss->saved_search_id ); $sql = $sql. " AND contact_a.id NOT IN ( SELECT contact_id FROM $g2contact WHERE $g2contact.group_id = {$ss->id} AND $g2contact.status = 'Removed')"; $mailingGroup->query( "INSERT IGNORE INTO X_$job_id (contact_id) $sql" ); } /* Get all the group contacts we want to include */ $mailingGroup->query( "CREATE TEMPORARY TABLE I_$job_id (email_id int, contact_id int primary key) ENGINE=HEAP" ); /* Get the group contacts, but only those which are not in the * exclusion temp table */ /* Get the emails with no override */ $query = "REPLACE INTO I_$job_id (email_id, contact_id) SELECT DISTINCT $email.id as email_id, $contact.id as contact_id FROM $email INNER JOIN $contact ON $email.contact_id = $contact.id INNER JOIN $g2contact ON $contact.id = $g2contact.contact_id INNER JOIN $mg ON $g2contact.group_id = $mg.entity_id AND $mg.entity_table = '$group' LEFT JOIN X_$job_id ON $contact.id = X_$job_id.contact_id WHERE $mg.group_type = 'Include' AND $g2contact.status = 'Added' AND $g2contact.email_id IS null AND $contact.do_not_email = 0 AND $contact.is_opt_out = 0 AND ($email.is_bulkmail = 1 OR $email.is_primary = 1) AND $email.on_hold = 0 AND $mg.mailing_id = {$mailing_id} AND X_$job_id.contact_id IS null ORDER BY $email.is_bulkmail"; $mailingGroup->query($query); /* Query prior mailings */ $mailingGroup->query( "REPLACE INTO I_$job_id (email_id, contact_id) SELECT DISTINCT $email.id as email_id, $contact.id as contact_id FROM $email INNER JOIN $contact ON $email.contact_id = $contact.id INNER JOIN $eq ON $eq.contact_id = $contact.id INNER JOIN $job ON $eq.job_id = $job.id INNER JOIN $mg ON $job.mailing_id = $mg.entity_id AND $mg.entity_table = '$mailing' LEFT JOIN X_$job_id ON $contact.id = X_$job_id.contact_id WHERE $mg.group_type = 'Include' AND $contact.do_not_email = 0 AND $contact.is_opt_out = 0 AND ($email.is_bulkmail = 1 OR $email.is_primary = 1) AND $email.on_hold = 0 AND $mg.mailing_id = {$mailing_id} AND X_$job_id.contact_id IS null ORDER BY $email.is_bulkmail"); /* Construct the saved-search queries */ $ss->query("SELECT $group.saved_search_id as saved_search_id, $group.id as id FROM $group INNER JOIN $mg ON $mg.entity_id = $group.id AND $mg.entity_table = '$group' WHERE $mg.group_type = 'Include' AND $mg.mailing_id = {$mailing_id} AND $group.saved_search_id IS NOT null"); $whereTables = array( ); while ($ss->fetch()) { $tables = array($contact => 1, $location => 1, $email => 1); list( $from, $where ) = CRM_Contact_BAO_SavedSearch::fromWhereEmail( $ss->saved_search_id ); $where = trim( $where ); if ( $where ) { $where = " AND $where "; } $ssq = "INSERT IGNORE INTO I_$job_id (email_id, contact_id) SELECT DISTINCT $email.id as email_id, contact_a.id as contact_id $from LEFT JOIN $email ON $email.contact_id = contact_a.id LEFT JOIN X_$job_id ON contact_a.id = X_$job_id.contact_id WHERE contact_a.do_not_email = 0 AND contact_a.is_opt_out = 0 AND ($email.is_bulkmail = 1 OR $email.is_primary = 1) AND $email.on_hold = 0 $where AND contact_a.id NOT IN ( SELECT contact_id FROM $g2contact WHERE $g2contact.group_id = {$ss->id} AND $g2contact.status = 'Removed') AND X_$job_id.contact_id IS null ORDER BY $email.is_bulkmail"; $mailingGroup->query($ssq); } /* Get the emails with only location override */ $query = "REPLACE INTO I_$job_id (email_id, contact_id) SELECT DISTINCT $email.id as local_email_id, $contact.id as contact_id FROM $email INNER JOIN $contact ON $email.contact_id = $contact.id INNER JOIN $g2contact ON $contact.id = $g2contact.contact_id INNER JOIN $mg ON $g2contact.group_id = $mg.entity_id LEFT JOIN X_$job_id ON $contact.id = X_$job_id.contact_id WHERE $mg.entity_table = '$group' AND $mg.group_type = 'Include' AND $g2contact.status = 'Added' AND $g2contact.email_id is null AND $contact.do_not_email = 0 AND $contact.is_opt_out = 0 AND ($email.is_bulkmail = 1 OR $email.is_primary = 1) AND $email.on_hold = 0 AND $mg.mailing_id = {$mailing_id} AND X_$job_id.contact_id IS null ORDER BY $email.is_bulkmail"; $mailingGroup->query($query); /* Get the emails with full override */ $mailingGroup->query( "REPLACE INTO I_$job_id (email_id, contact_id) SELECT DISTINCT $email.id as email_id, $contact.id as contact_id FROM $email INNER JOIN $g2contact ON $email.id = $g2contact.email_id INNER JOIN $contact ON $contact.id = $g2contact.contact_id INNER JOIN $mg ON $g2contact.group_id = $mg.entity_id LEFT JOIN X_$job_id ON $contact.id = X_$job_id.contact_id WHERE $mg.entity_table = '$group' AND $mg.group_type = 'Include' AND $g2contact.status = 'Added' AND $g2contact.email_id IS NOT null AND $contact.do_not_email = 0 AND $contact.is_opt_out = 0 AND ($email.is_bulkmail = 1 OR $email.is_primary = 1) AND $email.on_hold = 0 AND $mg.mailing_id = {$mailing_id} AND X_$job_id.contact_id IS null ORDER BY $email.is_bulkmail"); $results = array(); $eq =& new CRM_Mailing_Event_BAO_Queue(); $eq->query("SELECT contact_id, email_id FROM I_$job_id ORDER BY contact_id, email_id"); /* Delete the temp table */ $mailingGroup->reset(); $mailingGroup->query("DROP TEMPORARY TABLE X_$job_id"); $mailingGroup->query("DROP TEMPORARY TABLE I_$job_id"); return $eq; } private function _getMailingGroupIds( $type = 'Include' ) { $mailingGroup =& new CRM_Mailing_DAO_Group(); $group = CRM_Contact_DAO_Group::getTableName(); if ( ! isset( $this->id ) ) { // we're just testing tokens, so return any group $query = "SELECT id AS entity_id FROM $group ORDER BY id LIMIT 1"; } else { $query = "SELECT entity_id FROM $mg WHERE mailing_id = {$this->id} AND group_type = '$type' AND entity_table = '$group'"; } $mailingGroup->query( $query ); $groupIds = array( ); while ( $mailingGroup->fetch( ) ) { $groupIds[] = $mailingGroup->entity_id; } return $groupIds; } /** * * Returns the regex patterns that are used for preparing the text and html templates * * @access private * **/ private function &getPatterns($onlyHrefs = false) { $patterns = array(); $protos = '(https?|ftp)'; $letters = '\w'; $gunk = '\{\}/#~:.?+=&;%@!\-'; $punc = '.:?\-'; $any = "{$letters}{$gunk}{$punc}"; if ( $onlyHrefs ) { $pattern = "\\bhref[ ]*=[ ]*([\"'])?(($protos:[$any]+?(?=[$punc]*[^$any]|$)))([\"'])?"; } else { $pattern = "\\b($protos:[$any]+?(?=[$punc]*[^$any]|$))"; } $patterns[] = $pattern; $patterns[] = '\\\\\{\w+\.\w+\\\\\}|\{\{\w+\.\w+\}\}'; $patterns[] = '\{\w+\.\w+\}'; $patterns = '{'.join('|',$patterns).'}im'; return $patterns; } /** * returns an array that denotes the type of token that we are dealing with * we use the type later on when we are doing a token replcement lookup * * @param string $token The token for which we will be doing adata lookup * * @return array $funcStruct An array that holds the token itself and the type. * the type will tell us which function to use for the data lookup * if we need to do a lookup at all */ function &getDataFunc($token) { $funcStruct = array('type' => null,'token' => $token); $matches = array(); if ( ( preg_match('/^href/i',$token) || preg_match('/^http/i',$token) ) && $this->url_tracking ) { // it is a url so we need to check to see if there are any tokens embedded // if so then call this function again to get the token dataFunc // and assign the type 'embedded' so that the data retrieving function // will know what how to handle this token. if ( preg_match_all('/(\{\w+\.\w+\})/', $token, $matches) ) { $funcStruct['type'] = 'embedded_url'; $funcStruct['embed_parts'] = $funcStruct['token'] = array( ); foreach ( $matches[1] as $match ) { $preg_token = '/'.preg_quote($match,'/').'/'; $list = preg_split($preg_token,$token,2); $funcStruct['embed_parts'][] = $list[0]; $token = $list[1]; $funcStruct['token'][] = $this->getDataFunc($match); } } else { $funcStruct['type'] = 'url'; } } else if ( preg_match('/^\{(domain)\.(\w+)\}$/',$token, $matches) ) { $funcStruct['type'] = $matches[1]; $funcStruct['token'] = $matches[2]; } else if ( preg_match('/^\{(action)\.(\w+)\}$/',$token, $matches) ) { $funcStruct['type'] = $matches[1]; $funcStruct['token'] = $matches[2]; } else if ( preg_match('/^\{(mailing)\.(\w+)\}$/',$token,$matches) ) { $funcStruct['type'] = $matches[1]; $funcStruct['token'] = $matches[2]; } else if ( preg_match('/^\{(contact)\.(\w+)\}$/',$token, $matches) ) { $funcStruct['type'] = $matches[1]; $funcStruct['token'] = $matches[2]; } else if(preg_match('/\\\\\{(\w+\.\w+)\\\\\}|\{\{(\w+\.\w+)\}\}/', $token, $matches) ) { // we are an escaped token // so remove the escape chars $unescaped_token = preg_replace('/\{\{|\}\}|\\\\\{|\\\\\}/','',$matches[0]); $funcStruct['token'] = '{'.$unescaped_token.'}'; } return $funcStruct; } /** * * Prepares the text and html templates * for generating the emails and returns a copy of the * prepared templates * * @access private * **/ private function getPreparedTemplates( ) { if ( !$this->preparedTemplates ) { $patterns['html'] = $this->getPatterns(true); $patterns['text'] = $this->getPatterns(); $templates = $this->getTemplates(); $this->preparedTemplates = array(); foreach (array('html','text') as $key) { if (!isset($templates[$key])) { continue; } $matches = array(); $tokens = array(); $split_template = array(); $email = $templates[$key]; preg_match_all($patterns[$key],$email,$matches,PREG_PATTERN_ORDER); foreach ($matches[0] as $idx => $token) { $preg_token = '/'.preg_quote($token,'/').'/im'; list($split_template[],$email) = preg_split($preg_token,$email,2); array_push($tokens, $this->getDataFunc($token)); } if ($email) { $split_template[] = $email; } $this->preparedTemplates[$key]['template'] = $split_template; $this->preparedTemplates[$key]['tokens'] = $tokens; } } return($this->preparedTemplates); } /** * * Retrieve a ref to an array that holds the email and text templates for this email * assembles the complete template including the header and footer * that the user has uploaded or declared (if they have dome that) * * * @return array reference to an assoc array * @access private * **/ private function &getTemplates( ) { require_once('CRM/Utils/String.php'); if (!$this->templates) { $this->getHeaderFooter(); $this->templates = array( ); if ( $this->body_text ) { $template = array(); if ( $this->header ) { $template[] = $this->header->body_text; } $template[] = $this->body_text; if ( $this->footer ) { $template[] = $this->footer->body_text; } $this->templates['text'] = join("\n",$template); } if ( $this->body_html ) { $template = array(); if ( $this->header ) { $template[] = $this->header->body_html; } $template[] = $this->body_html; if ( $this->footer ) { $template[] = $this->footer->body_html; } $this->templates['html'] = join("\n",$template); // this is where we create a text tepalte from the html template if the texttempalte did not exist // this way we ensure that every recipient will receive n email even if the pref is set to text and the // user uploads an html email only if ( !$this->body_text ) { $this->templates['text'] = CRM_Utils_String::htmlToText( $this->templates['html'] ); } } } return $this->templates; } /** * * Retrieve a ref to an array that holds all of the tokens in the email body * where the keys are the type of token and the values are ordinal arrays * that hold the token names (even repeated tokens) in the order in which * they appear in the body of the email. * * note: the real work is done in the _getTokens() function * * this function needs to have some sort of a body assigned * either text or html for this to have any meaningful impact * * @return array reference to an assoc array * @access public * **/ public function &getTokens( ) { if (!$this->tokens) { $this->tokens = array( 'html' => array(), 'text' => array() ); if ($this->body_html) { $this->_getTokens('html'); } if ($this->body_text) { $this->_getTokens('text'); } } return $this->tokens; } /** * * _getTokens parses out all of the tokens that have been * included in the html and text bodies of the email * we get the tokens and then separate them into an * internal structure named tokens that has the same * form as the static tokens property(?) of the CRM_Utils_Token class. * The difference is that there might be repeated token names as we want the * structures to represent the order in which tokens were found from left to right, top to bottom. * * * @param str $prop name of the property that holds the text that we want to scan for tokens (html, text) * @access private * @return void */ private function _getTokens( $prop ) { $templates = $this->getTemplates(); $matches = array(); preg_match_all( '/(?<!\{|\\\\)\{(\w+\.\w+)\}(?!\})/', $templates[$prop], $matches, PREG_PATTERN_ORDER); if ( $matches[1] ) { foreach ( $matches[1] as $token ) { list($type,$name) = split( '\.', $token, 2 ); if ( $name ) { if ( ! isset( $this->tokens[$prop][$type] ) ) { $this->tokens[$prop][$type] = array( ); } $this->tokens[$prop][$type][] = $name; } } } } /** * Generate an event queue for a test job * * @params array $params contains form values * @return void * @access public */ public function getTestRecipients($testParams) { $session =& CRM_Core_Session::singleton(); if ($testParams['test_email']) { /* First, find out if the contact already exists */ $query = " SELECT DISTINCT contact_a.id as contact_id FROM civicrm_contact contact_a LEFT JOIN civicrm_email ON contact_a.id = civicrm_email.contact_id WHERE LOWER(civicrm_email.email) = %1"; $params = array( 1 => array( $testParams['test_email'], 'String' ) ); $dao =& CRM_Core_DAO::executeQuery( $query, $params ); $id = array( ); // lets just use the first contact id we got if ( $dao->fetch( ) ) { $contact_id = $dao->contact_id; } $dao->free( ); $userID = $session->get('userID'); $params = array( 1 => array($testParams['test_email'], 'String' ) ); if ( ! $contact_id ) { $query = "INSERT INTO civicrm_email (contact_id, email) values ($userID,%1)"; CRM_Core_DAO::executeQuery( $query, $params ); $contact_id = $userID; } $query = "SELECT civicrm_email.id FROM civicrm_email WHERE civicrm_email.email = %1"; $dao =& CRM_Core_DAO::executeQuery( $query, $params); if ($dao->fetch( ) ) { $email_id = $dao->id; } $dao->free( ); $params = array( 'job_id' => $testParams['job_id'], 'email_id' => $email_id, 'contact_id' => $contact_id ); CRM_Mailing_Event_BAO_Queue::create($params); } if (array_key_exists($testParams['test_group'], CRM_Core_PseudoConstant::group())) { $group =& new CRM_Contact_DAO_Group(); $group->id = $testParams['test_group']; $contacts = CRM_Contact_BAO_GroupContact::getGroupContacts($group); foreach ($contacts as $contact) { $query = "SELECT DISTINCT civicrm_email.id AS email_id, civicrm_email.is_primary as is_primary, civicrm_email.is_bulkmail as is_bulkmailFROM civicrm_emailINNER JOIN civicrm_contact ON civicrm_email.contact_id = civicrm_contact.idWHERE civicrm_email.is_bulkmail = 1AND civicrm_contact.id = {$contact->contact_id}AND civicrm_contact.do_not_email =0AND civicrm_email.on_hold = 0AND civicrm_contact.is_opt_out =0"; $dao =& CRM_Core_DAO::executeQuery( $query, CRM_Core_DAO::$_nullArray); if ($dao->fetch( ) ) { $params = array( 'job_id' => $testParams['job_id'], 'email_id' => $dao->email_id, 'contact_id' => $contact->contact_id ); $queue = CRM_Mailing_Event_BAO_Queue::create($params); } else { $query = "SELECT DISTINCT civicrm_email.id AS email_id, civicrm_email.is_primary as is_primary, civicrm_email.is_bulkmail as is_bulkmailFROM civicrm_emailINNER JOIN civicrm_contact ON civicrm_email.contact_id = civicrm_contact.idWHERE civicrm_email.is_primary = 1AND civicrm_contact.id = {$contact->contact_id}AND civicrm_contact.do_not_email =0AND civicrm_email.on_hold = 0AND civicrm_contact.is_opt_out =0"; $dao =& CRM_Core_DAO::executeQuery( $query, CRM_Core_DAO::$_nullArray); if ($dao->fetch( ) ) { $params = array( 'job_id' => $testParams['job_id'], 'email_id' => $dao->email_id, 'contact_id' => $contact->contact_id ); $queue = CRM_Mailing_Event_BAO_Queue::create($params); } } } } } /** * Retrieve the header and footer for this mailing * * @param void * @return void * @access private */ private function getHeaderFooter() { if (!$this->header and $this->header_id) { $this->header =& new CRM_Mailing_BAO_Component(); $this->header->id = $this->header_id; $this->header->find(true); $this->header->free( ); } if (!$this->footer and $this->footer_id) { $this->footer =& new CRM_Mailing_BAO_Component(); $this->footer->id = $this->footer_id; $this->footer->find(true); $this->footer->free( ); } } /** * static wrapper for getting verp and urls * * @param int $job_id ID of the Job associated with this message * @param int $event_queue_id ID of the EventQueue * @param string $hash Hash of the EventQueue * @param string $email Destination address * @return (reference) array array ref that hold array refs to the verp info and urls */ static function getVerpAndUrls($job_id, $event_queue_id, $hash, $email){ // create a skeleton object and set its properties that are required by getVerpAndUrlsAndHeaders() require_once 'CRM/Core/BAO/Domain.php'; $config =& CRM_Core_Config::singleton(); $bao =& new CRM_Mailing_BAO_Mailing(); $bao->domain_id = $config->domainID(); $bao->_domain =& CRM_Core_BAO_Domain::getDomainByID($bao->domain_id); $bao->from_name = $bao->from_email = $bao->subject = ''; // use $bao's instance method to get verp and urls list($verp, $urls, $_) = $bao->getVerpAndUrlsAndHeaders($job_id, $event_queue_id, $hash, $email); return array($verp, $urls); } /** * get verp, urls and headers * * @param int $job_id ID of the Job associated with this message * @param int $event_queue_id ID of the EventQueue * @param string $hash Hash of the EventQueue * @param string $email Destination address * @return (reference) array array ref that hold array refs to the verp info, urls, and headers * @access private */ private function getVerpAndUrlsAndHeaders( $job_id, $event_queue_id, $hash, $email ) { $config =& CRM_Core_Config::singleton( ); /** * Inbound VERP keys: * reply: user replied to mailing * bounce: email address bounced * unsubscribe: contact opts out of all target lists for the mailing * resubscribe: contact opts back into all target lists for the mailing * optOut: contact unsubscribes from the domain */ $verp = array( ); foreach (array('reply', 'bounce', 'unsubscribe', 'resubscribe', 'optOut') as $key) { $verp[$key] = implode($config->verpSeparator, array( $key, $this->domain_id, $job_id, $event_queue_id, $hash ) ) . '@' . $this->_domain->email_domain; } $urls = array( 'forward' => CRM_Utils_System::url('civicrm/mailing/forward', "reset=1&jid={$job_id}&qid={$event_queue_id}&h={$hash}", true, null, true, true), 'unsubscribeUrl' => CRM_Utils_System::url('civicrm/mailing/unsubscribe', "reset=1&jid={$job_id}&qid={$event_queue_id}&h={$hash}", true, null, true, true), 'resubscribeUrl' => CRM_Utils_System::url('civicrm/mailing/resubscribe', "reset=1&jid={$job_id}&qid={$event_queue_id}&h={$hash}", true, null, true, true), 'optOutUrl' => CRM_Utils_System::url('civicrm/mailing/optout', "reset=1&jid={$job_id}&qid={$event_queue_id}&h={$hash}", true, null, true, true), ); $headers = array( 'Reply-To' => CRM_Utils_Verp::encode($verp['reply'], $email), 'Return-Path' => CRM_Utils_Verp::encode($verp['bounce'], $email), 'From' => "\"{$this->from_name}\" <{$this->from_email}>", 'Subject' => $this->subject, ); return array( &$verp, &$urls, &$headers ); } /** * Compose a message * * @param int $job_id ID of the Job associated with this message * @param int $event_queue_id ID of the EventQueue * @param string $hash Hash of the EventQueue * @param string $contactId ID of the Contact * @param string $email Destination address * @param string $recipient To: of the recipient * @param boolean $test Is this mailing a test? * @return object The mail object * @access public */ public function &compose($job_id, $event_queue_id, $hash, $contactId, $email, &$recipient, $test = false, $contactDetails = null ) { require_once 'api/v2/Contact.php'; require_once 'CRM/Utils/Token.php'; $config =& CRM_Core_Config::singleton( ); $knownTokens = $this->getTokens(); if ($this->_domain == null) { require_once 'CRM/Core/BAO/Domain.php'; $this->_domain =& CRM_Core_BAO_Domain::getDomainByID($this->domain_id); } list( $verp, $urls, $headers) = $this->getVerpAndUrlsAndHeaders($job_id, $event_queue_id, $hash, $email); if ( $contactDetails ) { $contact = $contactDetails; } else { $params = array( 'contact_id' => $contactId ); $contact =& civicrm_contact_get( $params ); if ( is_a( $contact, 'CRM_Core_Error' ) ) { return null; } } $pTemplates = $this->getPreparedTemplates(); $pEmails = array( ); foreach( $pTemplates as $type => $pTemplate ) { $html = ($type == 'html') ? true : false; $pEmails[$type] = array( ); $pEmail =& $pEmails[$type]; $template =& $pTemplates[$type]['template']; $tokens =& $pTemplates[$type]['tokens']; $idx = 0; if ( !empty( $tokens ) ) { foreach ($tokens as $idx => $token) { $token_data = $this->getTokenData($token, $html, $contact, $verp, $urls, $event_queue_id); array_push($pEmail, $template[$idx]); array_push($pEmail, $token_data); } } else { array_push($pEmail, $template[$idx]); } if ( isset( $template[($idx + 1)] ) ) { array_push($pEmail, $template[($idx + 1)]); } } $html = null; if ( isset( $pEmails['html'] ) && is_array( $pEmails['html'] ) && count( $pEmails['html'] ) ) { $html = &$pEmails['html']; } $text = null; if ( isset( $pEmails['text'] ) && is_array( $pEmails['text'] ) && count( $pEmails['text'] ) ){ $text = &$pEmails['text']; } // push the tracking url on to the html email if necessary if ($this->open_tracking && $html ) { array_push($html,"\n".'<img src="' . $config->userFrameworkResourceURL . "extern/open.php?q=$event_queue_id\" width='1' height='1' alt='' border='0'>"); } $message =& new Mail_Mime("\n"); if ($text && ( $test || $contact['preferred_mail_format'] == 'Text' || $contact['preferred_mail_format'] == 'Both' || ( $contact['preferred_mail_format'] == 'HTML' && !array_key_exists('html',$pEmails) ) ) ) { $message->setTxtBody( wordwrap(join( '', $text ),200) ); } if ( $html && ( $test || ( $contact['preferred_mail_format'] == 'HTML' || $contact['preferred_mail_format'] == 'Both') ) ) { $message->setHTMLBody( wordwrap(join( '', $html ),200) ); } $recipient = "\"{$contact['display_name']}\" <$email>"; $headers['To'] = $recipient; $mailMimeParams = array( 'text_encoding' => '8bit', 'html_encoding' => '8bit', 'head_charset' => 'utf-8', 'text_charset' => 'utf-8', 'html_charset' => 'utf-8', ); $message->get($mailMimeParams); $message->headers($headers); // make sure we unset a lot of stuff unset( $verp ); unset( $urls ); unset( $params ); unset( $contact ); unset( $ids ); return $message; } /** * * get mailing object and replaces subscribeInvite, * domain and mailing tokens * */ function tokenReplace( &$mailing ) { require_once 'CRM/Core/BAO/Domain.php'; $domain =& CRM_Core_BAO_Domain::getDomainByID($mailing->domain_id); foreach ( array('text', 'html') as $type ) { require_once 'CRM/Utils/Token.php'; $tokens = $mailing->getTokens(); $mailing->templates[$type] = CRM_Utils_Token::replaceSubscribeInviteTokens($mailing->templates[$type]); $mailing->templates[$type] = CRM_Utils_Token::replaceDomainTokens($mailing->templates[$type], $domain, null, $tokens[$type]); $mailing->templates[$type] = CRM_Utils_Token::replaceMailingTokens($mailing->templates[$type], $mailing, null, $tokens[$type]); } } /** * * getTokenData receives a token from an email * and returns the appropriate data for the token * */ private function getTokenData(&$token_a, $html = false, &$contact, &$verp, &$urls, $event_queue_id) { $type = $token_a['type']; $token = $token_a['token']; $data = $token; if ($type == 'embedded_url') { $embed_data = array( ); foreach ( $token as $t ) { $embed_data[] = $this->getTokenData($t, $html = false, $contact, $verp, $urls, $event_queue_id); } $numSlices = count( $embed_data ); $url = ''; for ( $i = 0; $i < $numSlices; $i++ ) { $url .= "{$token_a['embed_parts'][$i]}{$embed_data[$i]}"; } if ( isset( $token_a['embed_parts'][$numSlices] ) ) { $url .= $token_a['embed_parts'][$numSlices]; } $data = CRM_Mailing_BAO_TrackableURL::getTrackerURL($url, $this->id, $event_queue_id); } else if ( $type == 'url' ) { $data = CRM_Mailing_BAO_TrackableURL::getTrackerURL($token, $this->id, $event_queue_id); } else if ( $type == 'contact' ) { $data = CRM_Utils_Token::getContactTokenReplacement($token, $contact); } else if ( $type == 'action' ) { $data = CRM_Utils_Token::getActionTokenReplacement($token, $verp, $urls, $html); } return $data; } /** * Return a list of group names for this mailing. Does not work with * prior-mailing targets. * * @return array Names of groups receiving this mailing * @access public */ public function &getGroupNames() { if (! isset($this->id)) { return array(); } $mg =& new CRM_Mailing_DAO_Group(); $mgtable = CRM_Mailing_DAO_Group::getTableName(); $group = CRM_Contact_BAO_Group::getTableName(); $mg->query("SELECT $group.name as name FROM $mgtable INNER JOIN $group ON $mgtable.entity_id = $group.id WHERE $mgtable.mailing_id = {$this->id} AND $mgtable.entity_table = '$group' AND $mgtable.group_type = 'Include' ORDER BY $group.name"); $groups = array(); while ($mg->fetch()) { $groups[] = $mg->name; } return $groups; } /** * function to add the mailings * * @param array $params reference array contains the values submitted by the form * @param array $ids reference array contains the id * * @access public * @static * @return object */ static function add( &$params, &$ids ) { require_once 'CRM/Utils/Hook.php'; if ( CRM_Utils_Array::value( 'mailing', $ids ) ) { CRM_Utils_Hook::pre( 'edit', 'Mailing', $ids['mailing_id'], $params ); } else { CRM_Utils_Hook::pre( 'create', 'Mailing', null, $params ); } $mailing =& new CRM_Mailing_DAO_Mailing( ); $mailing->domain_id = CRM_Core_Config::domainID( ); $mailing->id = CRM_Utils_Array::value( 'mailing_id', $ids ); if ( ! isset( $params['replyto_email'] ) && isset( $params['from_email'] ) ) { $params['replyto_email'] = $params['from_email']; } $mailing->copyValues( $params ); $result = $mailing->save( ); if ( CRM_Utils_Array::value( 'mailing', $ids ) ) { CRM_Utils_Hook::post( 'edit', 'Mailing', $mailing->id, $mailing ); } else { CRM_Utils_Hook::post( 'create', 'Mailing', $mailing->id, $mailing ); } return $result; } /** * Construct a new mailing object, along with job and mailing_group * objects, from the form values of the create mailing wizard. * * @params array $params Form values * @return object $mailing The new mailing object * @access public * @static */ public static function create( &$params, &$ids ) { require_once 'CRM/Core/Transaction.php'; $transaction = new CRM_Core_Transaction( ); $mailing = self::add($params, $ids); if( is_a( $mailing, 'CRM_Core_Error') ) { $transaction->rollback( ); return $mailing; } require_once 'CRM/Contact/BAO/Group.php'; /* Create the mailing group record */ $mg =& new CRM_Mailing_DAO_Group(); foreach( array( 'groups', 'mailings' ) as $entity ) { foreach( array( 'include', 'exclude' ) as $type ) { if( is_array( $params[$entity][$type] ) ) { foreach( $params[$entity][$type] as $entityId ) { $mg->reset( ); $mg->mailing_id = $mailing->id; $mg->entity_table = ( $entity == 'groups' ) ? CRM_Contact_BAO_Group::getTableName( ) : CRM_Mailing_BAO_Mailing::getTableName( ); $mg->entity_id = $entityId; $mg->group_type = $type; $mg->save( ); } } } } $transaction->commit( ); return $mailing; } /** * Generate a report. Fetch event count information, mailing data, and job * status. * * @param int $id The mailing id to report * @return array Associative array of reporting data * @access public * @static */ public static function &report($id) { $mailing_id = CRM_Utils_Type::escape($id, 'Integer'); $mailing =& new CRM_Mailing_BAO_Mailing(); require_once 'CRM/Mailing/Event/BAO/Opened.php'; require_once 'CRM/Mailing/Event/BAO/Reply.php'; require_once 'CRM/Mailing/Event/BAO/Unsubscribe.php'; require_once 'CRM/Mailing/Event/BAO/Forward.php'; require_once 'CRM/Mailing/Event/BAO/TrackableURLOpen.php'; require_once 'CRM/Mailing/BAO/Spool.php'; $t = array( 'mailing' => self::getTableName(), 'mailing_group' => CRM_Mailing_DAO_Group::getTableName(), 'group' => CRM_Contact_BAO_Group::getTableName(), 'job' => CRM_Mailing_BAO_Job::getTableName(), 'queue' => CRM_Mailing_Event_BAO_Queue::getTableName(), 'delivered' => CRM_Mailing_Event_BAO_Delivered::getTableName(), 'opened' => CRM_Mailing_Event_BAO_Opened::getTableName(), 'reply' => CRM_Mailing_Event_BAO_Reply::getTableName(), 'unsubscribe' => CRM_Mailing_Event_BAO_Unsubscribe::getTableName(), 'bounce' => CRM_Mailing_Event_BAO_Bounce::getTableName(), 'forward' => CRM_Mailing_Event_BAO_Forward::getTableName(), 'url' => CRM_Mailing_BAO_TrackableURL::getTableName(), 'urlopen' => CRM_Mailing_Event_BAO_TrackableURLOpen::getTableName(), 'component' => CRM_Mailing_BAO_Component::getTableName(), 'spool' => CRM_Mailing_BAO_Spool::getTableName() ); $report = array(); /* FIXME: put some permissioning in here */ /* Get the mailing info */ $mailing->query(" SELECT {$t['mailing']}.* FROM {$t['mailing']} WHERE {$t['mailing']}.id = $mailing_id"); $mailing->fetch(); $report['mailing'] = array(); foreach (array_keys(self::fields()) as $field) { $report['mailing'][$field] = $mailing->$field; } /* Get the component info */ $query = array(); $components = array( 'header' => ts('Header'), 'footer' => ts('Footer'), 'reply' => ts('Reply'), 'unsubscribe' => ts('Unsubscribe'), 'optout' => ts('Opt-Out') ); foreach(array_keys($components) as $type) { $query[] = "SELECT {$t['component']}.name as name, '$type' as type, {$t['component']}.id as id FROM {$t['component']} INNER JOIN {$t['mailing']} ON {$t['mailing']}.{$type}_id = {$t['component']}.id WHERE {$t['mailing']}.id = $mailing_id"; } $q = '(' . implode(') UNION (', $query) . ')'; $mailing->query($q); $report['component'] = array(); while ($mailing->fetch()) { $report['component'][] = array( 'type' => $components[$mailing->type], 'name' => $mailing->name, 'link' => CRM_Utils_System::url('civicrm/mailing/component', "reset=1&action=update&id={$mailing->id}"), ); } /* Get the recipient group info */ $mailing->query(" SELECT {$t['mailing_group']}.group_type as group_type, {$t['group']}.id as group_id, {$t['group']}.title as group_title, {$t['mailing']}.id as mailing_id, {$t['mailing']}.name as mailing_name FROM {$t['mailing_group']} LEFT JOIN {$t['group']} ON {$t['mailing_group']}.entity_id = {$t['group']}.id AND {$t['mailing_group']}.entity_table = '{$t['group']}' LEFT JOIN {$t['mailing']} ON {$t['mailing_group']}.entity_id = {$t['mailing']}.id AND {$t['mailing_group']}.entity_table = '{$t['mailing']}' WHERE {$t['mailing_group']}.mailing_id = $mailing_id "); $report['group'] = array('include' => array(), 'exclude' => array()); while ($mailing->fetch()) { $row = array(); if (isset($mailing->group_id)) { $row['id'] = $mailing->group_id; $row['name'] = $mailing->group_title; $row['link'] = CRM_Utils_System::url('civicrm/group/search', "reset=1&force=1&context=smog&gid={$row['id']}"); } else { $row['id'] = $mailing->mailing_id; $row['name'] = $mailing->mailing_name; $row['mailing'] = true; $row['link'] = CRM_Utils_System::url('civicrm/mailing/report', "mid={$row['id']}"); } if ($mailing->group_type == 'Include') { $report['group']['include'][] = $row; } else { $report['group']['exclude'][] = $row; } } /* Get the event totals, grouped by job (retries) */ $mailing->query(" SELECT {$t['job']}.*, COUNT(DISTINCT {$t['queue']}.id) as queue, COUNT(DISTINCT {$t['delivered']}.id) as delivered, COUNT(DISTINCT {$t['reply']}.id) as reply, COUNT(DISTINCT {$t['forward']}.id) as forward, COUNT(DISTINCT {$t['bounce']}.id) as bounce, COUNT(DISTINCT {$t['urlopen']}.id) as url, COUNT(DISTINCT {$t['spool']}.id) as spool FROM {$t['job']} LEFT JOIN {$t['queue']} ON {$t['queue']}.job_id = {$t['job']}.id LEFT JOIN {$t['reply']} ON {$t['reply']}.event_queue_id = {$t['queue']}.id LEFT JOIN {$t['forward']} ON {$t['forward']}.event_queue_id = {$t['queue']}.id LEFT JOIN {$t['bounce']} ON {$t['bounce']}.event_queue_id = {$t['queue']}.id LEFT JOIN {$t['delivered']} ON {$t['delivered']}.event_queue_id = {$t['queue']}.id AND {$t['bounce']}.id IS null LEFT JOIN {$t['urlopen']} ON {$t['urlopen']}.event_queue_id = {$t['queue']}.id LEFT JOIN {$t['spool']} ON {$t['spool']}.job_id = {$t['job']}.id WHERE {$t['job']}.mailing_id = $mailing_id AND {$t['job']}.is_test = 0 GROUP BY {$t['job']}.id"); $report['jobs'] = array(); $report['event_totals'] = array(); $elements = array( 'queue', 'delivered', 'url', 'forward', 'reply', 'unsubscribe', 'bounce', 'spool' ); // initialize various counters foreach ( $elements as $field ) { $report['event_totals'][$field] = 0; } $report['event_totals']['opened'] = $report['event_totals']['unsubscribe'] = 0; while ($mailing->fetch()) { $row = array(); foreach ( $elements as $field ) { if ( isset( $mailing->$field ) ) { $row[$field] = $mailing->$field; $report['event_totals'][$field] += $mailing->$field; } } // compute open total separately to discount duplicates // CRM-1258 $row['opened'] = CRM_Mailing_Event_BAO_Opened::getTotalCount( $mailing_id, $mailing->id, true ); $report['event_totals']['opened'] += $row['opened']; // compute unsub total separately to discount duplicates // CRM-1783 $row['unsubscribe'] = CRM_Mailing_Event_BAO_Unsubscribe::getTotalCount( $mailing_id, $mailing->id, true ); $report['event_totals']['unsubscribe'] += $row['unsubscribe']; foreach ( array_keys(CRM_Mailing_BAO_Job::fields( ) ) as $field ) { $row[$field] = $mailing->$field; } if ($mailing->queue) { $row['delivered_rate'] = (100.0 * $mailing->delivered ) / $mailing->queue; $row['bounce_rate'] = (100.0 * $mailing->bounce ) / $mailing->queue; $row['unsubscribe_rate'] = (100.0 * $row['unsubscribe'] ) / $mailing->queue; } else { $row['delivered_rate'] = 0; $row['bounce_rate'] = 0; $row['unsubscribe_rate'] = 0; } $row['links'] = array( 'clicks' => CRM_Utils_System::url( 'civicrm/mailing/report/event', "reset=1&event=click&mid=$mailing_id&jid={$mailing->id}" ), 'queue' => CRM_Utils_System::url( 'civicrm/mailing/report/event', "reset=1&event=queue&mid=$mailing_id&jid={$mailing->id}" ), 'delivered' => CRM_Utils_System::url( 'civicrm/mailing/report/event', "reset=1&event=delivered&mid=$mailing_id&jid={$mailing->id}" ), 'bounce' => CRM_Utils_System::url( 'civicrm/mailing/report/event', "reset=1&event=bounce&mid=$mailing_id&jid={$mailing->id}" ), 'unsubscribe' => CRM_Utils_System::url( 'civicrm/mailing/report/event', "reset=1&event=unsubscribe&mid=$mailing_id&jid={$mailing->id}" ), 'forward' => CRM_Utils_System::url( 'civicrm/mailing/report/event', "reset=1&event=forward&mid=$mailing_id&jid={$mailing->id}" ), 'reply' => CRM_Utils_System::url( 'civicrm/mailing/report/event', "reset=1&event=reply&mid=$mailing_id&jid={$mailing->id}" ), 'opened' => CRM_Utils_System::url( 'civicrm/mailing/report/event', "reset=1&event=opened&mid=$mailing_id&jid={$mailing->id}" ), ); foreach (array('scheduled_date', 'start_date', 'end_date') as $key) { $row[$key] = CRM_Utils_Date::customFormat($row[$key]); } $report['jobs'][] = $row; } if (CRM_Utils_Array::value('queue',$report['event_totals'] )) { $report['event_totals']['delivered_rate'] = (100.0 * $report['event_totals']['delivered']) / $report['event_totals']['queue']; $report['event_totals']['bounce_rate'] = (100.0 * $report['event_totals']['bounce']) / $report['event_totals']['queue']; $report['event_totals']['unsubscribe_rate'] = (100.0 * $report['event_totals']['unsubscribe']) / $report['event_totals']['queue']; } else { $report['event_totals']['delivered_rate'] = 0; $report['event_totals']['bounce_rate'] = 0; $report['event_totals']['unsubscribe_rate'] = 0; } /* Get the click-through totals, grouped by URL */ $mailing->query(" SELECT {$t['url']}.url, {$t['url']}.id, COUNT({$t['urlopen']}.id) as clicks, COUNT(DISTINCT {$t['queue']}.id) as unique_clicks FROM {$t['url']} LEFT JOIN {$t['urlopen']} ON {$t['urlopen']}.trackable_url_id = {$t['url']}.id LEFT JOIN {$t['queue']} ON {$t['urlopen']}.event_queue_id = {$t['queue']}.id LEFT JOIN {$t['job']} ON {$t['queue']}.job_id = {$t['job']}.id WHERE {$t['url']}.mailing_id = $mailing_id AND {$t['job']}.is_test = 0 GROUP BY {$t['url']}.id"); $report['click_through'] = array(); while ($mailing->fetch()) { $report['click_through'][] = array( 'url' => $mailing->url, 'link' => CRM_Utils_System::url( 'civicrm/mailing/report/event', "reset=1&event=click&mid=$mailing_id&uid={$mailing->id}"), 'link_unique' => CRM_Utils_System::url( 'civicrm/mailing/report/event', "reset=1&event=click&mid=$mailing_id&uid={$mailing->id}&distinct=1"), 'clicks' => $mailing->clicks, 'unique' => $mailing->unique_clicks, 'rate' => CRM_Utils_Array::value('delivered',$report['event_totals']) ? (100.0 * $mailing->unique_clicks) / $report['event_totals']['delivered'] : 0 ); } $report['event_totals']['links'] = array( 'clicks' => CRM_Utils_System::url( 'civicrm/mailing/report/event', "reset=1&event=click&mid=$mailing_id" ), 'clicks_unique' => CRM_Utils_System::url( 'civicrm/mailing/report/event', "reset=1&event=click&mid=$mailing_id&distinct=1" ), 'queue' => CRM_Utils_System::url( 'civicrm/mailing/report/event', "reset=1&event=queue&mid=$mailing_id" ), 'delivered' => CRM_Utils_System::url( 'civicrm/mailing/report/event', "reset=1&event=delivered&mid=$mailing_id" ), 'bounce' => CRM_Utils_System::url( 'civicrm/mailing/report/event', "reset=1&event=bounce&mid=$mailing_id" ), 'unsubscribe' => CRM_Utils_System::url( 'civicrm/mailing/report/event', "reset=1&event=unsubscribe&mid=$mailing_id" ), 'forward' => CRM_Utils_System::url( 'civicrm/mailing/report/event', "reset=1&event=forward&mid=$mailing_id" ), 'reply' => CRM_Utils_System::url( 'civicrm/mailing/report/event', "reset=1&event=reply&mid=$mailing_id" ), 'opened' => CRM_Utils_System::url( 'civicrm/mailing/report/event', "reset=1&event=opened&mid=$mailing_id" ), ); return $report; } /** * Get the count of mailings * * @param * @return int Count * @access public */ public function getCount() { $this->selectAdd(); $this->selectAdd('COUNT(id) as count'); $session =& CRM_Core_Session::singleton(); $this->domain_id = $session->get('domainID'); $this->find(true); return $this->count; } static function checkPermission( $id ) { if ( ! $id ) { return; } $mailingIDs =& CRM_Mailing_BAO_Mailing::mailingACLIDs( ); if ( ! in_array( $id, $mailingIDs ) ) { CRM_Core_Error::fatal( ts( 'You do not have permission to access this mailing report' ) ); } return; } static function mailingACL( ) { $mailingACL = " ( 0 ) "; $mailingIDs =& self::mailingACLIDs( ); if ( ! empty( $mailingIDs ) ) { $mailingIDs = implode( ',', $mailingIDs ); $mailingACL = " civicrm_mailing.id IN ( $mailingIDs ) "; } return $mailingACL; } static function &mailingACLIDs( ) { $mailingIDs = array( ); // get all the groups that this user can access // if they dont have universal access $groups = CRM_Core_PseudoConstant::group( ); if ( ! empty( $groups ) ) { $groupIDs = implode( ',', array_keys( $groups ) ); // get all the mailings that are in this subset of groups $query = "SELECT DISTINCT( m.id ) as id FROM civicrm_mailing m, civicrm_mailing_group g WHERE g.mailing_id = m.id AND g.entity_table = 'civicrm_group' AND g.entity_id IN ( $groupIDs )"; $dao = CRM_Core_DAO::executeQuery( $query, CRM_Core_DAO::$_nullArray ); $mailingIDs = array( ); while ( $dao->fetch( ) ) { $mailingIDs[] = $dao->id; } } return $mailingIDs; } /** * Get the rows for a browse operation * * @param int $offset The row number to start from * @param int $rowCount The nmber of rows to return * @param string $sort The sql string that describes the sort order * * @return array The rows * @access public */ public function &getRows($offset, $rowCount, $sort, $additionalClause = null, $additionalParams = null ) { $mailing = self::getTableName(); $job = CRM_Mailing_BAO_Job::getTableName(); $group = CRM_Mailing_DAO_Group::getTableName( ); $session =& CRM_Core_Session::singleton(); $domain_id = $session->get('domainID'); $mailingACL = self::mailingACL( ); $query = " SELECT $mailing.id, $mailing.name, $job.status, MIN($job.scheduled_date) as scheduled_date, MIN($job.start_date) as start_date, MAX($job.end_date) as end_date, from_email, from_name FROM $mailing LEFT JOIN $job ON ( $job.mailing_id = $mailing.id AND $job.is_test = 0) WHERE $mailing.domain_id = $domain_id AND $mailingACL $additionalClause GROUP BY $mailing.id "; if ($sort) { $orderBy = trim( $sort->orderBy() ); if ( ! empty( $orderBy ) ) { $query .= " ORDER BY $orderBy"; } } if ($rowCount) { $query .= " LIMIT $offset, $rowCount "; } if ( ! $additionalParams ) { $additionalParams = array( ); } $dao = CRM_Core_DAO::executeQuery( $query, $additionalParams ); $rows = array(); while ($dao->fetch()) { $rows[] = array( 'id' => $dao->id, 'name' => $dao->name, 'status' => CRM_Mailing_BAO_Job::status($dao->status), 'scheduled' => CRM_Utils_Date::customFormat($dao->scheduled_date), 'scheduled_iso' => $dao->scheduled_date, 'start' => CRM_Utils_Date::customFormat($dao->start_date), 'end' => CRM_Utils_Date::customFormat($dao->end_date), 'from_email' => $dao->from_email, 'from_name' => $dao->from_name, ); } return $rows; } /** * Function to show detail Mailing report * * @param int $id * * @static * @access public */ static function showEmailDetails( $id ) { return CRM_Utils_System::url('civicrm/mailing/report', "mid=$id"); } /** * Delete Mails and all its associated records * * @param int $id id of the mail to delete * * @return void * @access public * @static */ public static function del($id) { if ( empty( $id ) ) { CRM_Core_Error::fatal( ); } $dao = & new CRM_Mailing_DAO_Mailing(); $dao->id = $id; $dao->delete( ); CRM_Core_Session::setStatus(ts('Selected mailing has been deleted.')); } /** * Delete Jobss and all its associated records * related to test Mailings * * @param int $id id of the Job to delete * * @return void * @access public * @static */ public static function delJob($id) { if ( empty( $id ) ) { CRM_Core_Error::fatal( ); } $dao = new CRM_Mailing_BAO_Job(); $dao->id = $id; $dao->delete(); } function getReturnProperties( ) { $tokens =& $this->getTokens( ); $properties = array( ); if ( isset( $tokens['html'] ) && isset( $tokens['html']['contact'] ) ) { $properties = array_merge( $properties, $tokens['html']['contact'] ); } if ( isset( $tokens['text'] ) && isset( $tokens['text']['contact'] ) ) { $properties = array_merge( $properties, $tokens['text']['contact'] ); } $returnProperties = array( ); $returnProperties['display_name'] = $returnProperties['contact_id'] = $returnProperties['preferred_mail_format'] = 1; foreach ( $properties as $p ) { $returnProperties[$p] = 1; } return $returnProperties; } /** * gives required details of contacts * * @param array $contactIds of conatcts * @param array $returnProperties of required properties * * @return array * @access public */ function getDetails($contactIds, $returnProperties) { $params = array( ); foreach ( $contactIds as $key => $contactID ) { $params[] = array( CRM_Core_Form::CB_PREFIX . $contactID, '=', 1, 0, 1); } $custom = array( ); foreach ( $returnProperties as $name => $dontCare ) { $cfID = CRM_Core_BAO_CustomField::getKeyID( $name ); if ( $cfID ) { $custom[] = $cfID; } } //get the total number of contacts to fetch from database. $numberofContacts = count( $contactIds ); require_once 'CRM/Contact/BAO/Query.php'; $query =& new CRM_Contact_BAO_Query( $params, $returnProperties ); $details = $query->apiQuery( $params, $returnProperties, NULL, NULL, 0, $numberofContacts ); $contactDetails =& $details[0]; foreach ( $contactIds as $key => $contactID ) { if ( CRM_Utils_Array::value('preferred_communication_method',$returnProperties) == 1 ) { require_once 'CRM/Core/PseudoConstant.php'; $pcm = CRM_Core_PseudoConstant::pcm(); // communication Prefferance require_once 'CRM/Core/BAO/CustomOption.php'; $contactPcm = explode(CRM_Core_BAO_CustomOption::VALUE_SEPERATOR,$contactDetails[$contactID]['preferred_communication_method']); foreach ( $contactPcm as $key => $val) { if ($val) { $result[$val] = $pcm[$val]; } } $contactDetails[$contactID]['preferred_communication_method'] = implode(', ',$result); unset($result); } foreach ( $custom as $cfID ) { if ( isset ( $contactDetails[$contactID]["custom_{$cfID}"] ) ) { $contactDetails[$contactID]["custom_{$cfID}"] = CRM_Core_BAO_CustomField::getDisplayValue( $contactDetails[$contactID]["custom_{$cfID}"],$cfID, $details[1] ); } } } return $details; }}?>