CiviCRM Community Forums (archive)

*

News:

Have a question about CiviCRM?
Get it answered quickly at the new
CiviCRM Stack Exchange Q+A site

This forum was archived on 25 November 2017. Learn more.
How to get involved.
What to do if you think you've found a bug.



  • CiviCRM Community Forums (archive) »
  • Old sections (read-only, deprecated) »
  • Developer Discussion »
  • APIs and Hooks (Moderator: Donald Lobo) »
  • Some custom CiviMail token hooks for contribution data
Pages: [1]

Author Topic: Some custom CiviMail token hooks for contribution data  (Read 1193 times)

Micah Lee

  • I post occasionally
  • **
  • Posts: 31
  • Karma: 4
  • CiviCRM version: 4.1.0
  • CMS version: Drupal 7
  • MySQL version: 5.1.49
  • PHP version: 5.3.3
Some custom CiviMail token hooks for contribution data
November 29, 2011, 04:01:42 pm
Hi! I just wrote some hooks to add custom tokens for our website and I thought I'd share. Here is a collection of contribution-related tokens:

Code: [Select]
function hook_civicrm_tokens( &$tokens ) {
    $tokens['contribution'] = array(
        'contribution.lifetime_amount' => 'Total contributions from this contact',
        'contribution.recent_amount' => 'Amount of most recent contribution',
        'contribution.recent_date' => 'Date of most recent contribution',
        'contribution.recent_year' => 'Year of most recent contribution',
        'contribution.soft_lifetime_amount' => 'Total soft credit contributions from this contact',
        'contribution.soft_recent_amount' => 'Amount of most recent soft credit contribution',
        'contribution.soft_recent_date' => 'Date of most recent soft credit contribution',
        'contribution.soft_recent_year' => 'Year of most recent soft credit contribution',
        'contribution.hard_soft_lifetime_amount' => 'Total hard and soft contributions from this contact'
    );
}

function hook_civicrm_tokenValues( &$values, &$contact_ids ) {
    // build contact_id_string
    if(is_array($contact_ids)) {
        $contact_id_string = implode(',', array_values($contact_ids));
        $single = false;

        // add arrays for each contact, if they don't already exist
        foreach($contact_ids as $contact_id) {
            if(!array_key_exists($contact_id, $values)) {
                $values[$contact_id] = array();
            }
        }
    } else {
        $contact_id_string = "( $contact_ids )";
        $single = true;
    }

    // get lifetime amount
    $lifetime_amount = 0;
    $query = "SELECT contact_id, sum( total_amount ) as lifetime_amount FROM civicrm_contribution WHERE contact_id IN ( $contact_id_string ) AND is_test = 0 GROUP BY contact_id";
    $dao = CRM_Core_DAO::executeQuery($query);
    while($dao->fetch()) {
        $lifetime_amount =  $dao->lifetime_amount;
        if($single) {
            $values['contribution.lifetime_amount'] = $lifetime_amount;
        } else {
            $values[$dao->contact_id]['contribution.lifetime_amount'] = $lifetime_amount;
        }
    }

    // get recent amount and year
    $query = "SELECT tmp_table.contact_id, tmp_table.receive_date as recent_date, civicrm_contribution.total_amount as recent_amount FROM (SELECT contact_id, MAX( receive_date ) as receive_date FROM civicrm_contribution WHERE contact_id IN ( $contact_id_string ) AND is_test = 0 GROUP BY contact_id) as tmp_table, civicrm_contribution WHERE civicrm_contribution.contact_id = tmp_table.contact_id AND civicrm_contribution.receive_date = tmp_table.receive_date";
    $dao = CRM_Core_DAO::executeQuery($query);
    while($dao->fetch()) {
        $recent_amount = sprintf("%.2f", $dao->recent_amount);
        $timestamp = strtotime($dao->recent_date);
        $recent_date = date("F j, Y", $timestamp);
        $recent_year = date("Y", $timestamp);
        if($single) {
            $values['contribution.recent_amount'] = $recent_amount;
            $values['contribution.recent_date'] = $recent_date;
            $values['contribution.recent_year'] = $recent_year;
        } else {
            $values[$dao->contact_id]['contribution.recent_amount'] = $recent_amount;
            $values[$dao->contact_id]['contribution.recent_date'] = $recent_date;
            $values[$dao->contact_id]['contribution.recent_year'] = $recent_year;
        }
    }

    // get soft credit lifetime amount
    $soft_lifetime_amount = 0;
    $query = "SELECT contact_id, sum( amount ) as soft_lifetime_amount FROM civicrm_contribution_soft WHERE contact_id IN ( $contact_id_string ) GROUP BY contact_id";
    $dao = CRM_Core_DAO::executeQuery($query);
    while($dao->fetch()) {
        $soft_lifetime_amount = $dao->soft_lifetime_amount;
        if($single) {
            $values['contribution.soft_lifetime_amount'] = $soft_lifetime_amount;
        } else {
            $values[$dao->contact_id]['contribution.soft_lifetime_amount'] = $soft_lifetime_amount;
        }
    }

    // get soft credit recent amount and year
    $query = "SELECT tmp_table.contact_id, tmp_table.receive_date as soft_recent_date, civicrm_contribution_soft.amount as soft_recent_amount FROM (SELECT civicrm_contribution_soft.contact_id, MAX( civicrm_contribution.receive_date ) as receive_date FROM civicrm_contribution, civicrm_contribution_soft WHERE civicrm_contribution.id = civicrm_contribution_soft.contribution_id AND civicrm_contribution_soft.contact_id IN ( $contact_id_string ) AND civicrm_contribution.is_test = 0 GROUP BY civicrm_contribution_soft.contact_id) as tmp_table, civicrm_contribution, civicrm_contribution_soft WHERE civicrm_contribution.id = civicrm_contribution_soft.contribution_id AND civicrm_contribution_soft.contact_id = tmp_table.contact_id AND civicrm_contribution.receive_date = tmp_table.receive_date";
    $dao = CRM_Core_DAO::executeQuery($query);
    while($dao->fetch()) {
        $recent_amount = sprintf("%.2f", $dao->soft_recent_amount);
        $timestamp = strtotime($dao->soft_recent_date);
        $recent_date = date("F j, Y", $timestamp);
        $recent_year = date("Y", $timestamp);
        if($single) {
            $values['contribution.soft_recent_amount'] = $recent_amount;
            $values['contribution.soft_recent_date'] = $recent_date;
            $values['contribution.soft_recent_year'] = $recent_year;
        } else {
            $values[$dao->contact_id]['contribution.soft_recent_amount'] = $recent_amount;
            $values[$dao->contact_id]['contribution.soft_recent_date'] = $recent_date;
            $values[$dao->contact_id]['contribution.soft_recent_year'] = $recent_year;
        }
    }

    // hard and soft contributions
    if($single) {
        $hard_soft_lifetime_amount = $values['contribution.lifetime_amount'] + $values['contribution.soft_lifetime_amount'];
        $values['contribution.hard_soft_lifetime_amount'] = sprintf("%.2f", $hard_soft_lifetime_amount);
    } else {
        foreach($contact_ids as $contact_id) {
            $hard_soft_lifetime_amount = $values[$contact_id]['contribution.lifetime_amount'] + $values[$contact_id]['contribution.soft_lifetime_amount'];
            $values[$contact_id]['contribution.hard_soft_lifetime_amount'] = sprintf("%.2f", $hard_soft_lifetime_amount);
        }
    }
   
    // make sure everything has a value
    $default_amount = '0.00';
    $default_date = 'never';
    if($single) {
        if(!isset($values['contribution.lifetime_amount']))
            $values['contribution.lifetime_amount'] = $default_amount;
        if(!isset($values['contribution.recent_amount']))
            $values['contribution.recent_amount'] = $default_amount;
        if(!isset($values['contribution.recent_date']))
            $values['contribution.recent_date'] = $default_date;
        if(!isset($values['contribution.recent_year']))
            $values['contribution.recent_year'] = $default_date;
        if(!isset($values['contribution.soft_lifetime_amount']))
            $values['contribution.soft_lifetime_amount'] = $default_amount;
        if(!isset($values['contribution.soft_recent_amount']))
            $values['contribution.soft_recent_amount'] = $default_amount;
        if(!isset($values['contribution.soft_recent_date']))
            $values['contribution.soft_recent_date'] = $default_date;
        if(!isset($values['contribution.soft_recent_year']))
            $values['contribution.soft_recent_year'] = $default_date;
        if(!isset($values['contribution.hard_soft_lifetime_amount']))
            $values['contribution.hard_soft_lifetime_amount'] = $default_date;
    } else {
        foreach($contact_ids as $contact_id) {
            if(!isset($values[$contact_id]['contribution.lifetime_amount']))
                $values[$contact_id]['contribution.lifetime_amount'] = $default_amount;
            if(!isset($values[$contact_id]['contribution.recent_amount']))
                $values[$contact_id]['contribution.recent_amount'] = $default_amount;
            if(!isset($values[$contact_id]['contribution.recent_date']))
                $values[$contact_id]['contribution.recent_date'] = $default_date;
            if(!isset($values[$contact_id]['contribution.recent_year']))
                $values[$contact_id]['contribution.recent_year'] = $default_date;
            if(!isset($values[$contact_id]['contribution.soft_lifetime_amount']))
                $values[$contact_id]['contribution.soft_lifetime_amount'] = $default_amount;
            if(!isset($values[$contact_id]['contribution.soft_recent_amount']))
                $values[$contact_id]['contribution.soft_recent_amount'] = $default_amount;
            if(!isset($values[$contact_id]['contribution.soft_recent_date']))
                $values[$contact_id]['contribution.soft_recent_date'] = $default_date;
            if(!isset($values[$contact_id]['contribution.soft_recent_year']))
                $values[$contact_id]['contribution.soft_recent_year'] = $default_date;
            if(!isset($values[$contact_id]['contribution.hard_soft_lifetime_amount']))
                $values[$contact_id]['contribution.hard_soft_lifetime_amount'] = $default_amount;
        }
    }
}

Luciano S.

  • I post occasionally
  • **
  • Posts: 83
  • Karma: 2
  • iXiam Team Leader
  • CiviCRM version: 4.2+ / 4.3+ / 4.4+
  • CMS version: Drupal
  • MySQL version: 5.1+ / 5.5+
  • PHP version: 5.3+ / 5.4+
Re: Some custom CiviMail token hooks for contribution data
December 09, 2011, 02:26:40 am
Hi Micah, nice work!!
thanks for sharing your code, it's very useful.


My concern in this point,  if i'm not wrong, is that all those queries will be executed in any email / pdf creation, if you use any of those custom tokens or even if you don't.
So can be a very 'expensive' to process all those queries in every mailing / pdf where you don't use some/any of those tokens.

is there any way to avoid that?

cheers!

Micah Lee

  • I post occasionally
  • **
  • Posts: 31
  • Karma: 4
  • CiviCRM version: 4.1.0
  • CMS version: Drupal 7
  • MySQL version: 5.1.49
  • PHP version: 5.3.3
Re: Some custom CiviMail token hooks for contribution data
December 09, 2011, 10:27:49 am
Quote from: sluc23 on December 09, 2011, 02:26:40 am
Hi Micah, nice work!!
thanks for sharing your code, it's very useful.


My concern in this point,  if i'm not wrong, is that all those queries will be executed in any email / pdf creation, if you use any of those custom tokens or even if you don't.
So can be a very 'expensive' to process all those queries in every mailing / pdf where you don't use some/any of those tokens.
. I think you're right, it will run these queries
is there any way to avoid that?

cheers!

That's a good point, I think these queries do get run each time you send an email or generate a PDF.

But it's programmed in a such a way that there aren't any queries inside of loops, so even if you have 150,000 contacts it will only run 4 queries and each query will return 150,000 rows. So it's an extra step that slows things down, but it's not exponentially more and more expensive the more contacts you have.

It probably runs whether or not you use these tokens, but maybe CiviCRM has logic in it to only hook_civicrm_tokenValues() if you're using a token defined in hook_civicrm_tokens()? I doubt it, but that would probably be a good optimization.

Donald Lobo

  • Administrator
  • I’m (like) Lobo ;)
  • *****
  • Posts: 15963
  • Karma: 470
    • CiviCRM site
  • CiviCRM version: 4.2+
  • CMS version: Drupal 7, Joomla 2.5+
  • MySQL version: 5.5.x
  • PHP version: 5.4.x
Re: Some custom CiviMail token hooks for contribution data
December 09, 2011, 11:00:36 am

Note that in 4.1 we are sending the list of tokens that need to be evaluated in the context, so you can optimize when you call the queries

in 4.2 we'll send even more context to the token hook:

http://issues.civicrm.org/jira/browse/CRM-9316

lobo
A new CiviCRM Q&A resource needs YOUR help to get started. Visit our StackExchange proposed site, sign up and vote on 5 questions

Luciano S.

  • I post occasionally
  • **
  • Posts: 83
  • Karma: 2
  • iXiam Team Leader
  • CiviCRM version: 4.2+ / 4.3+ / 4.4+
  • CMS version: Drupal
  • MySQL version: 5.1+ / 5.5+
  • PHP version: 5.3+ / 5.4+
Re: Some custom CiviMail token hooks for contribution data
December 12, 2011, 03:36:42 am
Thanks for the update Lobo!
nice workaround to avoid this issue
Looking forwards anxiously to do my first installation of 4.1 when it becomes stable :)


cheers!

Pages: [1]
  • CiviCRM Community Forums (archive) »
  • Old sections (read-only, deprecated) »
  • Developer Discussion »
  • APIs and Hooks (Moderator: Donald Lobo) »
  • Some custom CiviMail token hooks for contribution data

This forum was archived on 2017-11-26.