CiviCRM Entity - Using Drupal Search and Facet APIs with CiviCRM Data

Publicat
2016-03-29 05:57
Written by

There are two powerful modules used in the Drupal world for creating fast custom searches. Search API is a framework which provides an interface for site builders to create custom searches on any entity known to Drupal. It supports several search backends, including Apache Solr and native database search. It has a flexible API so developers can easily extend, customize, and alter aspects of the search process. Many additional contrib modules are available. Using these techniques, searching millions of records becomes fast and efficient.

The Facet API module allows site builders to easily create and manage faceted search interfaces. In addition to the UI components that standard, themers and module developers can build their own widgets, or alter the out-of-the-box widgets.

This one-two punch of powerful modules brings extremely powerful, flexible, and as you will see, easy to use custom search functionality to Drupal. Oftentimes all that is required is configuration through the admin interface, although the development API is extensive and the imagination is the limit for what can be done.

Creating custom searches for CiviCRM has always been a developer task, and the facilities are limited from both a site builder and a developer perspective. Wouldn't it be great to use Drupal's powerful search modules with CiviCRM data? Well folks, you can, with a little help from CiviCRM Entity.

CiviCRM Entity is a Drupal module which exposes many CiviCRM entities as true Drupal entities. That means that almost any module that can use Drupal entities, can access and manipulate CiviCRM data, Drupal style. This includes many commonly used modules such as Views, Rules, Entity ReferenceEntityqueue, and many more.

There is a sub module that ships with CiviCRM Entity, called CiviCRM Entity Search API.  This supports advanced index update operations for Contacts and Memberships currently, and more will be added in the future.

Create a Custom Search and Display

In this article I'll outline the basic instructions and methods that can be used create custom searches on nearly 20 different CiviCRM entities. As an example, we'll build a custom Contact search, with a faceted block interface for Contact Type. This is the simplest example of what can be done. There are tons of options and configurations -- too many to outline fully in one blog article.

We'll be using native database search indexing in this article, but this methods applies to Apache Solr as well as several other available backend service classes.

The interface for the search will be created using blocks and a view, which will integrate into your theme. If your theme is responsive, then your custom search will be, too!

Step-by-Step

The full step by step instructions are detailed on Skvare's blog.

  1. Install and Configure System Requirements
  2. Create Search Server Instance
  3. Create a Contact Search Index Instance
  4. Select Fields to Index
  5. Configure Filters
  6. Facets
  7. Index the Contacts
  8. Create the Search View
  9. Configure View fields and Filters
  10. Contact Type Facet Block
  11. The Results

Conclusion

You can have multiple facets per view, and using one of the many contrib modules that extend these modules, there is hardly a limit to what you can achieve. All of this can be achieved with zero additional code, pure site building. There is a strong developer api for customizing and extending this functionality even further.

Also, there are no CiviCRM permissions stopping users from visiting the view. You can control permissions with standard Views permissions. If you want to expose CiviCRM data to users, but not give those users any permission to access the CiviCRM backend, then it can be so. If your theme is responsive, then your search view can be, too.

This is a very simple example of what is possible, and I hope you can see the vast potential involved with these modules and techniques. Really the limit is your imagination.

Have fun building your own specific implementations!

Skvare is a leader in Drupal and CiviCRM integration. Contact us to get questions answered and for consultations to make the most of your Drupal and CiviCRM installation.

 

Comments

Nicely documented and great initiative. Will give it a go as we continue with our work to out do NationBuilder via Drupal+CiviCRM ;-)

AWESOME! Thanks for putting this together. This is going to be super helpful for getting the information we need more quickly!

Had a couple of reasons to give this a work through. Had used FacetAPI before so only the CiviCRM Entity side of things is new. What I am finding is that my custom 'select' fields are not coming through with Label, just the 'value' as the label shows in the Facet block.

For example Gender. On both systems this is coming through eg 0 (789) | 2 (133) | 1 (118)

I have trawled through lots of FacetAPI extra modules to see if they let me instruct it to show the Name or Label, rather than the Value

Have you found a solution?

Checkout the Facet API Bonus module.

Enable and then 'configure filters' on one of your Facets of an index.

Check the "Rewrite facet items via callback function" option

Enabling that filter lets you implement a hook in a custom module with some code like so:

/**
 * Implements hook_facet_items_alter().
 */
function YOUR_MODULE_NAME_facet_items_alter(&$build, &$settings) {
  // name of your facet goes below, use dsm($settings) to discover
  if ($settings->facet == "gender_id") {
    if (!civicrm_initialize()){
      return;
    }
    $result = civicrm_api3('Contact', 'getoptions', array(
      'sequential' => 1,
      'field' => "gender_id",
    ));
    $genders = array();
    if (!$result['is_error'] && count($result['values'])){
      foreach ($result['values'] as $gender){
        $genders[$gender['key']] = $gender['value'];
      }
    }
    foreach ($build as $key => $item) {
      if (isset($genders[$key])) {
        $build[$key]["#markup"] = $genders[$key];
      }
      elseif ($key == 0) {
        $build[$key]["#markup"] = 'Not specified';
      }
    }
  }
}

Going to take a look at the above but see if we can deliver it better upstream via Search API and CiviCRM Entities - which may also be required for my next question ....

If we want to offer a Search based on Contact, but pull in Email, State etc, then in 'drupal sense' I would be using Related Fields, but I only see options for Current Employer ID, and for Household Primary Contact ID.

Any thoughts?

Ok, there's a number of ways to approach this.

First approach:

First, lets say you want address information with contact, indexed, in a search.  What you need to do here is create an Index for the Address Entity.

When you go to the Fields tab of the Address Index, at the very bottom, there is a "Related Fields" fieldset.

Open that up and Select 'Contact ID', then click the "Add Fields" button. This will actually allow you to index contact data along with the address data.

That's great, you can have an index containing address and contact data. Doesn't help you if you want to add the phone in there, although you can follow the same procedure for indexing Phone entities with contact data.

You'll notice a pattern.  Out of the box, the relationships that are created are reverse relationships, meaning you can reference back to the Contact from an Address, but you can't reference forward from a Contact to and Address.

However, this could be made possible, with some bit of further development on CiviCRM Entity.

Some hints are to be found here: http://drupal.stackexchange.com/questions/150026/search-api-referencing-entity-relations

2nd approach:

You could make a custom Views field handler, and configure it to display a phone number for the contact, on the view...

This comment section is maybe not the place for describing how to do this, but I'd be happy to write another article explaining it, although there are many guides one can find on the internet. This may at first seem difficult, but like many things, once you know how to add a custom field handler, its pretty much the same, and not hard to do at all.

See this for hints: http://drupal.stackexchange.com/questions/80203/custom-views-handler-without-table

Thanks for this brilliant post - and the blog it refers to! 

In case it's helpful for others - I spent quite some time working out how to do a search across multiple entities and eventually found that it's really simple. There are various methods, but the easiest seems to be to make an Index based on the 'Multiple types' option: Config > Search and Metadata > Search API > Add index > Item type: multiple types (at the bottom). This is as mentioned here.

Thanks again!