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 (Moderator: Donald Lobo) »
  • Cross domain realtime updates (IMBA <-> CAMBr)
Pages: [1]

Author Topic: Cross domain realtime updates (IMBA <-> CAMBr)  (Read 1791 times)

konadave

  • I’m new here
  • *
  • Posts: 19
  • Karma: 0
  • CiviCRM version: 4.2.6
  • CMS version: Drupal 7.17
  • MySQL version: 5.1.66
  • PHP version: 5.3.19
Cross domain realtime updates (IMBA <-> CAMBr)
November 09, 2012, 02:53:20 pm
The Chicago Area Mountain Bikers (CAMBr) are in the process of becoming an IMBA chapter. As part of this arrangement, IMBA will be handling membership on CAMBr's behalf; joining CAMBr will no longer take place on the CAMBr site. Since there are several areas of the CAMBr site that are directly tied to membership, CAMBr needs to be updated in realtime whenever somebody joins or renews their membership, lets their membership expire, or updates their profile. I have been tasked with implementing this, and preferably in such a manner that it can be used by other IMBA chapters.

IMBA is Drupal/CiviCRM. The current CAMBr site is a highly customized SMF installation. A new CAMBr site is under construction, 100% custom.

I am posting here for several reasons. First, I would like to know if there is an existing module or extension that can handle this task. Jason at IMBA suggested that YASS might be useful. Having looked at it's readme and design notes, it appears that it may be overly complex and/or overkill.

I have perused the CiviCRM developer resources and have an idea on how to implement this. I would like your input on if this is a sound approach, if you have any suggestions, or can point out any pitfalls I may encounter along the way.

It will be implemented as a CiviCRM extension. Most of the work would take place in hook_civicrm_post. I believe a create for Contribution would catch any new or renewing members, and an edit on Membership could be used to capture an IMBA member with no chapter affiliation selecting CAMBr after the fact. I would also watch for edit on Individual/Household/Organization/Membership to push any changes in member data. I do not know if expiring memberships can be captured here.

When a suitable event is detected, calls will be made to the API to collect all the relevent data. The data will be packaged up in a REST or XML-RPC request and sent CAMBr's way. CAMBr will need to be able to specify the URL endpoint for the request in their profile. I believe this can be handled with a custom data field and smarty template.

On the CAMBr side of things, it would create/update the user account and send off emails, etc. If the CAMBr web or MySQL server happens to be down at the time of the call results in failure. I see two ways to handle this. If IMBA receives an error status code on return, the collected data is placed in a custom database table, and then using some cron facility, retry the request until it successfully goes through. This would be similar to how a PayPal IPN works.

The easier way to handle failure would be a "I joined IMBA but didn't get a CAMBr email" page on CAMBr's end. After the user supplies the email address they joined IMBA with, the REST API would be used to query the user's membership and contact information to confirm and set things up.

If there is no other way, I would probably run a daily cron on CAMBr's end that uses the REST API to locate expired memberships. It could also check for failed realtime updates.

If it is desired, updates made on CAMBr will be applied to IMBA using the REST API.

I appreciate you taking the time to read this and look forward to your comments.

Thanks

Dave

totten

  • Administrator
  • Ask me questions
  • *****
  • Posts: 695
  • Karma: 64
Re: Cross domain realtime updates (IMBA <-> CAMBr)
November 09, 2012, 04:25:38 pm
I agree that YASS is overkill for a lot of situations -- it's designed to sync multiple entities in a distributed, multi-master topologies (which introduces complications like disconnections, merge-propagation, conflicts, etc); and it has a couple small Drupal dependencies. These points are resolvable but not worth the effort unless you really need a multi-master topology.

I like the idea of combining REST requests and cron-tasks as elements of a basic notification system. A lot of platforms have introduced similar features under the label "Webhooks", and one could definitely add this to Civi by writing an extension. In making an extension that's sharable/re-usable for different orgs, the main trick will be storing the configuration (eg the URL/credentials for CAMBr site).

The webhook design seems best if you're doing a one-way sync. When you get into bidirectional sync, then you're at risk of going down the slippery slope to multi-master.

jbertolacci

  • I post occasionally
  • **
  • Posts: 54
  • Karma: 1
Re: Cross domain realtime updates (IMBA <-> CAMBr)
November 14, 2012, 09:18:28 am
A few thoughts:

  • Do you only want members to be pushed or non-member contacts as well? If the later, you will also want to watch for contact creation.
  • Latest versions of CiviCRM run a consolidated cron. Even though we will need to upgrade to take advantage, this should be our target for cron tasks: http://wiki.civicrm.org/confluence/display/CRM/Consolidated+CiviCRM+Cron
  • Membership status updates are processed as part of cron using the api.job.processMembership API call which should help with the membership expiration question
  • IMBA marks both contacts and contributions with chapter using a custom field. If either is marked the contact belongs to a chapter so this should be the filter of which to push.

konadave

  • I’m new here
  • *
  • Posts: 19
  • Karma: 0
  • CiviCRM version: 4.2.6
  • CMS version: Drupal 7.17
  • MySQL version: 5.1.66
  • PHP version: 5.3.19
Re: Cross domain realtime updates (IMBA <-> CAMBr)
November 17, 2012, 11:48:25 am
CAMBr only needs notification of member events.

I am going to take the fact that people haven't jumped in and said my idea is the wrong way, to mean that it's probably the best way to go about it.

Eileen

  • Forum Godess / God
  • I’m (like) Lobo ;)
  • *****
  • Posts: 4195
  • Karma: 218
    • Fuzion
Re: Cross domain realtime updates (IMBA <-> CAMBr)
November 23, 2012, 12:14:22 am
Hi,

I meant to reply earlier. My impression is that you are on the right track. Using the API class from your post hook is probably the easiest way to use REST with the API. (the api class file has quite a lot of notes on how to use it & is in the api folder - I think it's documented in the booki too now)

The membership post hook should be fine for capturing membership creations and updates (including expirations).

I'm guessing you would store the IMBA contact_id in the CAMBY DB as the external_id? You might also store the IMBA membership id as a custom field on the membership

Assuming failures are fairly infrequent just sending emails to your site admin might be an option when an error happens?

Adding to Jason's comments about the cron - if you make a custom api function this can be called by the consolidated cron
Make today the day you step up to support CiviCRM and all the amazing organisations that are using it to improve our world - http://civicrm.org/contribute

xavier

  • Forum Godess / God
  • I’m (like) Lobo ;)
  • *****
  • Posts: 4453
  • Karma: 161
    • Tech To The People
  • CiviCRM version: yes probably
  • CMS version: drupal
Re: Cross domain realtime updates (IMBA <-> CAMBr)
November 23, 2012, 12:37:27 am
Please tell if I wasn't clear in the api/class.api.php, the top are the examples.

It has been improved steadily, probably worthwhile updating to the latest 4.2 version if you haven't already.

The easiest is to call the external directly when saving. If you don't have a lot of these and if you don't mind the users waiting an extra second or two, that's plenty good enough.

If you need something that scales more, you should probably queue the requests to update the remote crm and batch process them.

X+
-Hackathon and data journalism about the European parliament 24-26 jan. Watch out the result

konadave

  • I’m new here
  • *
  • Posts: 19
  • Karma: 0
  • CiviCRM version: 4.2.6
  • CMS version: Drupal 7.17
  • MySQL version: 5.1.66
  • PHP version: 5.3.19
Re: Cross domain realtime updates (IMBA <-> CAMBr)
December 01, 2012, 06:34:44 pm
I've found that the best way to capture a join/renew is to wait for a create of MembershipPayment. At that point, the contact, contribution, and membership all exist. A few API calls from there and I have all the info I need.

As far as CAMBr is concerned, the failure rate on updates should be very low as they happen to be on a very reliable server. If other chapters end up using this extension, their failure rate may be higher. At any rate, there needs to be a way to queue failed updates for retry later during cron. I was thinking of storing the required info in a separate table; would need the chapter's contact_id, original event time (to give up after some time has passed), and the urlencoded POST data. Maybe I've missed it in the developer resources, but is there some proper/documented way to do custom tables?

By the way, the comments in api/class.api.php say "To make it easier, the Actions can either take for input an associative array $params, or simply an id". When I tried just using an id, I got PHP warnings that a scalar cannot be used in place of an array.

Eileen

  • Forum Godess / God
  • I’m (like) Lobo ;)
  • *****
  • Posts: 4195
  • Karma: 218
    • Fuzion
Re: Cross domain realtime updates (IMBA <-> CAMBr)
December 02, 2012, 12:48:40 pm
The new extension framework does allow you to create tables when you install your extension (you definitely want to be using a 4.2 or trunk dev environment if developing extensions as they progressed rapidly over the 4.2 cycle.)

I'm not 100% sure where the documentation is but I presume if you google civix & extensions...
Make today the day you step up to support CiviCRM and all the amazing organisations that are using it to improve our world - http://civicrm.org/contribute

konadave

  • I’m new here
  • *
  • Posts: 19
  • Karma: 0
  • CiviCRM version: 4.2.6
  • CMS version: Drupal 7.17
  • MySQL version: 5.1.66
  • PHP version: 5.3.19
Re: Cross domain realtime updates (IMBA <-> CAMBr)
December 02, 2012, 03:14:39 pm
Pretty easy to add/drop table with install/uninstall.

The code generated by civix generate:upgrader and in cambr.civix.php when the extension was first created will execute sql/*_install.sql and sql/*_uninstall.sql automatically.


konadave

  • I’m new here
  • *
  • Posts: 19
  • Karma: 0
  • CiviCRM version: 4.2.6
  • CMS version: Drupal 7.17
  • MySQL version: 5.1.66
  • PHP version: 5.3.19
Re: Cross domain realtime updates (IMBA <-> CAMBr)
December 07, 2012, 09:58:44 am
It would appear that neither hook_civicrm_pre or hook_civicrm_post are called when editing a custom field.

After doing much logging, I found I can use hook_civicrm_postProcess to get the before and after values on form submission.

function cambr_civicrm_postProcess($formName, &$form) {
	
ob_start();
	
if (
$formName == 'CRM_Contact_Form_CustomData') {
	
	
foreach(
$form->_submitValues as $k => $after) {
	
	
	
if (
strpos($k, 'custom_') === 0) {
	
	
	
	
list(
$custom, $id, $xtra) = explode('_', $k);
	
	
	
	
$before = $form->_groupTree[$form->_groupID]['fields'][$id]['element_value'];
	
	
	
	
echo 
date('m/d/Y h:i:s'), ": custom_$id\nBefore: $before\nAfter: $after\nfor entity_id {$form->_entityId}\n";
	
	
	
}
	
	
}
	
}
	
file_put_contents(__DIR__ . '/form.log', ob_get_clean(), FILE_APPEND);
}


Is this the way it's meant to be? It seems odd that DB writes for custom fields should be handled differently.

jbertolacci

  • I post occasionally
  • **
  • Posts: 54
  • Karma: 1
Re: Cross domain realtime updates (IMBA <-> CAMBr)
December 07, 2012, 12:26:35 pm
I was wondering about that too when I read the reference for hook_civicrm_custom...

http://wiki.civicrm.org/confluence/display/CRMDOC42/Hook+Reference#HookReference-hook_civicrm_custom

konadave

  • I’m new here
  • *
  • Posts: 19
  • Karma: 0
  • CiviCRM version: 4.2.6
  • CMS version: Drupal 7.17
  • MySQL version: 5.1.66
  • PHP version: 5.3.19
Re: Cross domain realtime updates (IMBA <-> CAMBr)
December 07, 2012, 01:10:35 pm
Quote
This hook is called AFTER the db write on a custom table
When I looked at this earlier, I was thinking the custom table I added for the queue. Having now looked at the prototype and example, I can see it is for custom fields. However, this is an after hook and the $params do not include the previous value, which we need.
« Last Edit: December 07, 2012, 01:12:39 pm by konadave »

konadave

  • I’m new here
  • *
  • Posts: 19
  • Karma: 0
  • CiviCRM version: 4.2.6
  • CMS version: Drupal 7.17
  • MySQL version: 5.1.66
  • PHP version: 5.3.19
Re: Cross domain realtime updates (IMBA <-> CAMBr)
December 07, 2012, 05:42:32 pm
My previously posted function for form postProcess doesn't work with multiple custom field sets. For the sake of anybody searching...

How-to determine before and after values when a custom field is edited. This certainly does not represent best practice. I worked this out by examining var_dumps of the data sent to the hook, and it directly accesses available properties. If there is a better/proper way to accomplish this, I would love to hear it.


function cambr_civicrm_postProcess($formName, &$form) {
	
ob_start();
	
echo 
date('m/d/Y h:i:s'), ": postProcess $formName\n";

	
$before = array();
	
$after = array();
	
foreach(
$form->_submitValues as $name => $value) {
	
	
if (
strpos($name, 'custom_') === 0) {
	
	
	
list(
$custom, $field_id, $custom_id) = explode('_', $name);
	
	
	
$after['custom_' . $field_id] = $value;
	
	
	
foreach(
$form->_groupTree as $group_id => $group) {
	
	
	
	
foreach(
$group['fields'] as $field) {
	
	
	
	
	
if (
$field['element_name'] == $name) {
	
	
	
	
	
	
$before['custom_' . $field_id] = $field['element_value'];
	
	
	
	
	
	
break;
	
	
	
	
	
}
	
	
	
	
}
	
	
	
}
	
	
}
	
}
	
foreach(
$after as $id => $value)
	
	
echo 
"$id was '{$before[$id]}', now it's '$value'.\n";

	
file_put_contents(__DIR__ . '/form.log', ob_get_clean(), FILE_APPEND);
}


This example simply logs the before and after values. Typically you would do a
if (isset($after['custom_???']))
and do what you need to from there.
« Last Edit: December 07, 2012, 05:45:18 pm by konadave »

Pages: [1]
  • CiviCRM Community Forums (archive) »
  • Old sections (read-only, deprecated) »
  • Developer Discussion (Moderator: Donald Lobo) »
  • Cross domain realtime updates (IMBA <-> CAMBr)

This forum was archived on 2017-11-26.