The CiviCRM contact field for CCK provides a link between a node and a CiviCRM contact.

It would be great to be able to traverse this link to expose CiviCRM contact data directly to Views. A specific use case we currently have at CivicSpace: enable gmap views of CCK nodes based on locational data in linked CiviCRM contact.

The basic approach would be the regular Views one: start with a hook_views_tables() implementation. There are particular challenges:

1. The complexity of the CiviCRM data model. Not insurmountable. We would need, however, to do something like join {node} to the CCK node type table; that to {civicrm_contact}; that to {civicrm_location}; and that to {civicrm_accress}.

2. The common practice of having CiviCRM in its own database. This would require joins between databases. That's fine as far as MySQL is concerned (just reference e.g. mydb1.mytablename1) but I don't know if/how it would work in PHP.

Does any of this views support already exist? Is this a direction worth pursuing?

CommentFileSizeAuthor
#3 civinode-load.patch3.51 KBnedjo

Comments

Torenware’s picture

I did a version of this for the Bioneers. There are definite issue with efficiency and memory consumption, but it's absolutely "doable". The technique I devised does not require a cross database join, but does involve creating some pretty funky field handlers for Views. It works well, although again, there are efficiency issues.

Again, the concept of a "subordinate field" in CCK would help me. The master field (which would set and hold the CiviCRM contact_id) could be used to cache the CiviCRM contact object while the CCK node was being rendered. Done like this, it would reduce the memory requirements, since only a single contact object would be needed to render the node.

My suggestion is to do this through CCK, since the due to Views' architecture, there needs to be a node and NID to anchor a table to Views.

I intend to create a related "civinode_views' module for some of this, although it may be better to put it into civicrmdata.module.

djorn’s picture

I've been able to figure out how to set up a CCK type to link to a CiviCRM field, but I'd like to set up a Views table to list contact information for users and allow users to filter by various exposed options (such as proximity, profession, etc) as well as blocking some contacts from appearing (such as those who check a box that says "please hide my profile"). Is there any way to do this?

nedjo’s picture

Status: Active » Needs review
StatusFileSize
new3.51 KB

the concept of a "subordinate field" in CCK would help me

I think what there is here is the 'load' op in CCK's hook_field().

Here's a rough and untested idea of what I imagine we need to do as a first step to get access to CiviCRM data as part of the node.

We follow the traditional Drupal approach of loading into the $node object (instead of loading the CiviCRM data only when we're rendering the node, as we currently do).

This would allow other modules, e.g, gmap, to use CiviCRM data associated with a node, e.g., a location.

But I doubt it would help with views. AFAIK, Views needs SQL information and can't work with what's loaded into a node.

Torenware’s picture

I've been swamped with another project this past two weeks, but the Views problem is pretty solveable.

Here's some example code, which I did for the Bioneers:


//Field handler to link contact_id to CRM fields
function registration_views_contact_view_handler($fieldinfo, $fielddata, $value, $data){
  //I am heavily depending upon node_load being cached.  Hopefully Merlin Our Wizard
  //knows of which he is talking....
  if (!$value)
    return;
  $pattern ="/[\x-\x8\xb-\xc\xe-\x1f]/";
  $contact_field = $fielddata['options'] ? 
    $fielddata['options'] : 'display_name';

  //We special case 'organization', which is pseudo-key
  if ($contact_field == 'organization') {
    if (module_exist('civinode')) {
      //'Volunteer for' is another possible type...
      $rtypes = array('Employee of','Affiliated with');
      //Note: underlying CRM API actually ignores rtypes.
      //Docs no good, UTSL
      $rels = civinode_fetch_relationships($value, $rtypes);
      //for now, return the first we find of that relation
      if ($rels) {
        foreach ($rels as $rid => $vals) {
          if (in_array($vals['relation'], $rtypes))
            return preg_replace($pattern,'',$vals['name']);
        }
      }
    }
  }
  else {
    $contact =  civinode_util_load_cdata($value);
    if (isset($contact[$contact_field])) {
      $filtered = preg_replace($pattern,'',$contact[$contact_field]);
      return $filtered;
    }
  }
  return ''; //best just to leave it empty
}

The filtering stuff was needed to deal with "junk" that was in the client's database (they had migrated from FileMaker Pro, which puts control characters in weird and wonderful places).

The key concept here is that you make use of field options to pass the name of the CiviCRM field you want views to display, and then render the field inside of a field handler, as shown above. You can even create pseudo-keys to cover things like relationships or tags, which are not really fields of a contact, but often are best displayed that way.

Making this work with CCK requires a little additional work, since the CCK field needs to register itself with Views. This takes a bit of doing, but I'm reasonably sure how to do it.

Torenware’s picture

Assigned: Unassigned » Torenware

Nedjo,

This is now in process. I'm updating the CCK support to use the modern (CCK 5.1-1.4+) hooks, and will likely get in the Views related hooks by end of week.

Torenware’s picture

The new module is up as the 5.x version. Details here:

Torenware’s picture

Status: Needs review » Fixed
Anonymous’s picture

Status: Fixed » Closed (fixed)