Extending APIv3

Published
2011-09-28 18:31
Written by

CiviCRM 3.4.x and 4.0.x introduced API v3, a more consistent set of interfaces for integrating with CiviCRM using PHP, Smarty, Javascript, and REST. Building on this consistent core API, recent CiviCRM updates have introduced even more ways to manipulate your data -- such as chaining and CSV batch importing.

Thus, functions implemented according to the API v3 conventions can be invoked several different ways. If you would like to leverage this infrastructure for use with a new or customized API call, then download the latest release. With 3.4.6/4.0.6, external developers can expose API functions for new entities, new actions, and even generic actions.

This would, for instance, allow you to create an API that returns the top donations of a person, grouped by contribution type... or any consolidated data. Instead of having to call a lot of APIs and consolidate the result yourself, you can write you own api.contribution.top, either by doing directly the right SQL queries or by using existing simpler APIs. Your new API is then automatically available to AJAX, Smarty, the REST interface and PHP.

Preliminaries: PHP Include Path

To define new APIs, you will need somewhere to place the new PHP files. This directory must be part of the PHP include path. There are a couple ways to do this:

  • Put the new files in a Custom PHP directory
  • Put the new files in a Drupal module and add the module to the include path, e.g.
    <?php
    // FILE: sites/all/modules/example/example.module
    
    /**
     * Implementation of hook_civicrm_config
     */
    function example_civicrm_config(&$config) {
      $path = drupal_get_path('module', 'example');
      set_include_path(get_include_path() . PATH_SEPARATOR . $path);
    }
    

In the rest of this document, file paths are relative to your chosen directory. Thus, if your directory is "/var/www/sites/all/modules/example", and if the relative path is "api/v3/Phone/Get.php", then the full path is "/var/www/sites/all/modules/example/api/v3/Phone/Get.php"

Define a new action for an existing entity

Suppose you want to implement an action, "get", for an entity called "Phone." You would need to create a new file with a new function

* File (Example): api/v3/Phone/Get.php * Function (Example): civicrm_api3_phone_get($params) * File (Formula): api/v${version}/${CamelCaseEntity}/${CamelCaseAction}.php * Function (Formula): civicrm_api3_${lower_case_entity}_${lower_case_action}($params)

Define a generic action for all entities

Sometimes it's useful to define generic actions which build on top of existing actions. For example, the "create" action can be used to modify records, but it's not always user-friendly -- in some scenarios, if you forget to pass in a field for an existing record, you might inadvertently set the field to blank. To work around this, you might first "get" the full entity, then merge-in your changes, and finally call "create" to save the changes. This sequence of steps ("get"->"merge"->"create") can be a little tedious -- it's more convenient to define a new action, "update", which handles all these steps. "update" is a generic action:

* File (Example): api/v3/Generic/Update.php * Function (Example): civicrm_api3_generic_update($apiRequest) * File (Formula): api/v${version}/Generic/${CamelCaseAction}.php * Function (Formula): civicrm_api3_generic_${lower_case_action}($apiRequest)

Define a new entity with several actions

As with previous releases, you can also create an API for a new entity which includes several actions, e.g.

<?php
// FILE: sites/all/modules/example/api/v3/MyEntity.php

/**
 * Implement the "get" action for "MyEntity"
 */
function civicrm_api3_my_entity_get($params) {
    ...your logic...
}

/**
 * Implement the "create" action for "MyEntity"
 */
function civicrm_api3_my_entity_create($params) {
    ...your logic...
}

Available Helpers

API v3 currently includes some helper functions which checking inputs and formatting outputs. Many API functions are implemented with this idiom:

<?php

/**
 * Implement the "myaction" action for "myentity"
 */
function civicrm_api3_myentity_myaction($params) {
    civicrm_api3_verify_mandatory($params, null,
        array('field_a', 'field_b', ...));
    $values = array();
    // ... run your logic, populating $values ...
    if (...logic hits error...) {
        return civicrm_api3_create_error('Error message...');
    } else {
        return civicrm_api3_create_success($values, $params);
    }
}
Filed under

Comments

Hi there,

I'm writing to you here because I'm only an indirect user of CiviCRM and I wasn't able to answer all the questions required in order to post a bug to a forum.

I'm trying to use this iCalendar feed from an CiviCRM system:

http://www.hannahgrimes.com/civicrm/event/ical?reset=1&page=1

It fails because of improper line folding: there's an erroneous \n at the beginning of every line where there should only be space. Seems like an easy fix.

Thanks,

Jon Udell

http://elmcity.cloudapp.net
http://icalvalid.cloudapp.net

Thanks for putting it all together in a nice blogpost Tim! Very useful.