civicrm_entity.module in CiviCRM Entity 7
Same filename and directory in other branches
Implement CiviCRM entities as a Drupal Entity.
File
civicrm_entity.moduleView source
<?php
/**
* @file
* Implement CiviCRM entities as a Drupal Entity.
*/
/**
* Implements hook_menu_later().
*
* Entity API creates all the fields page links but the basic 'manage' page is missing
* so we use the /fields page at that url
*/
function civicrm_entity_menu_alter(&$items) {
foreach (entity_get_info() as $entity_name => $entity_info) {
if (!empty($entity_info['module']) && $entity_info['module'] == 'civicrm_entity') {
foreach ($entity_info['bundles'] as $file_type => $bundle_info) {
if (isset($bundle_info['admin'])) {
// Get the base path and access.
$path = $bundle_info['admin']['path'];
$items[$path] = $items[$path . '/fields'];
$items[$path]['type'] = MENU_NORMAL_ITEM;
$items[$path]['title'] = $entity_info['label'];
$items[$path]['description'] = t('CiviCRM @entity entity', array(
'@entity' => $entity_name,
));
$items[$path . '/fields']['type'] = MENU_DEFAULT_LOCAL_TASK;
}
}
}
}
}
/**
* Implements hook_permission().
*/
function civicrm_entity_permission() {
return array(
'civicrm_entity.rules.administer' => array(
'title' => t('Administer CiviCRM rule configurations'),
'restrict access' => TRUE,
),
);
}
/**
* Entity access callback.
*
* @param $op
* @param $entity
* @param $account
* @param $entity_type
*
* @return bool
*/
function civicrm_entity_access($op, $entity, $account, $entity_type) {
if ($op == 'view' && $entity_type == 'civicrm_event') {
return user_access('view event info');
}
elseif ($op == 'view' && $entity_type == 'civicrm_participant') {
return user_access('view event participants');
}
else {
return user_access('administer CiviCRM');
}
}
/**
* Implements hook_views_data_alter().
*/
/*
function civicrm_entity_views_data_alter($data) { }
*/
/**
* Implements hook_schema_alter().
*
* Note we are just doing this in a very simple form relationship type
* which is not defined by views at this stage. We have the problem
* that the CiviCRM views integration uses the _data hook & would need
* to use _data_alter hook to be compatible with entity views
* integration
*
* @param $schema
*/
function civicrm_entity_schema_alter(&$schema) {
$schema_entities = _civicrm_entity_enabled_entities();
foreach ($schema_entities as $drupal_entity => $civicrm_entity) {
$schema[$drupal_entity] = civicrm_entity_get_schema($drupal_entity);
}
}
/**
* Get schema for entities.
*
* This approach may not be required as using the schema_alter hook
* (as opposed to schema_hook) seems to get around a bunch of the
* reasons I used a separate schema.
*
* @param $table
*
* @return array
*/
function civicrm_entity_get_schema($table) {
if (!civicrm_initialize(TRUE)) {
return;
}
$schema = array();
$schema[$table] = array(
'description' => 'The base table for ' . $table,
'primary key' => array(
'id',
),
'fields' => array(),
);
$civicrm_entity = substr($table, 8);
$fields = civicrm_api($civicrm_entity, 'getfields', array(
'version' => 3,
));
$fields = $fields['values'];
foreach ($fields as $fieldname => $field_spec) {
if (empty($field_spec['name'])) {
continue;
}
$unique_name = empty($field_spec['uniqueName']) ? $fieldname : $field_spec['uniqueName'];
$schema[$table]['fields'][$unique_name] = array(
'real_field' => $field_spec['name'],
'description' => _civicrm_entity_get_title($field_spec),
'unsigned' => TRUE,
'not null' => TRUE,
) + civicrm_entity_get_field_type($field_spec);
}
return empty($schema[$table]) ? array() : $schema[$table];
}
/**
* Please document this function.
*
* @param $field_spec
*
* @return array
*/
function civicrm_entity_get_field_type($field_spec) {
if ($field_spec['name'] == 'id') {
return array(
'type' => 'serial',
);
}
switch ($field_spec['type']) {
case CRM_Utils_Type::T_INT:
case CRM_Utils_Type::T_BOOLEAN:
return array(
'type' => 'integer',
);
case CRM_Utils_Type::T_MONEY:
case CRM_Utils_Type::T_FLOAT:
return array(
'type' => 'float',
);
case CRM_Utils_Type::T_TEXT:
case CRM_Utils_Type::T_STRING:
case CRM_Utils_Type::T_LONGTEXT:
case CRM_Utils_Type::T_CCNUM:
case CRM_Utils_Type::T_EMAIL:
case CRM_Utils_Type::T_URL:
return array(
'type' => 'text',
);
case CRM_Utils_Type::T_DATE:
case CRM_Utils_Type::T_TIME:
return array(
'type' => 'varchar',
'mysql_type' => 'datetime',
);
case CRM_Utils_Type::T_ENUM:
return array(
'type' => 'varchar',
'mysql_type' => 'enum',
);
case CRM_Utils_Type::T_BLOB:
case CRM_Utils_Type::T_MEDIUMBLOB:
return array(
'type' => 'blob',
);
case CRM_Utils_Type::T_TIMESTAMP:
return array(
'type' => 'varchar',
'mysql_type' => 'timestamp',
);
}
return array(
'type' => $field_spec['type'],
);
}
/**
* Here we declare selected CiviCRM entities to Drupal.
*
* This is necessary for entity module to pick them up.
*/
function civicrm_entity_entity_info() {
$entities = _civicrm_entity_enabled_entities();
foreach ($entities as $drupal_entity => $civicrm_entity) {
$info[$drupal_entity] = array(
'description' => $civicrm_entity,
'optional' => TRUE,
'label' => "CiviCRM " . ucwords($civicrm_entity),
'module' => 'civicrm_entity',
'controller class' => 'CivicrmEntityController',
'metadata controller class' => 'CivicrmEntityMetadataController',
'views controller class' => 'CiviCRMEntityDefaultViewsController',
'ui class' => 'RulesDataUIEntity',
'fieldable' => TRUE,
'extra fields controller class' => 'EntityDefaultExtraFieldsController',
'access callback' => 'civicrm_entity_access',
'admin ui' => array(
'path' => $drupal_entity,
'controller class' => 'CivicrmEntityUIController',
'file' => 'civicrm_entity_controller.inc',
),
'bundles' => array(
$drupal_entity => array(
'label' => t('CiviCRM @entity', array(
'@entity' => ucwords($civicrm_entity),
)),
'admin' => array(
'path' => 'admin/structure/types/manage/' . $drupal_entity,
'access arguments' => array(
'administer CiviCRM',
),
),
),
),
'view modes' => array(
'full' => array(
'label' => t('Default'),
'custom settings' => TRUE,
),
),
'entity keys' => array(
'id' => 'id',
'label' => _civicrm_entity_labels($drupal_entity),
),
'base table' => $drupal_entity,
);
$label_callback = 'civicrm_entity_' . $drupal_entity . '_label_callback';
if (function_exists($label_callback)) {
$info[$drupal_entity]['label callback'] = $label_callback;
}
}
// OK - so we are not doing this for the ones declared in views
// until more testing has been done.
$info['civicrm_relationship_type']['views controller class'] = 'CiviCRMEntityDefaultViewsController';
return $info;
}
/**
* Here we declare Selected CiviCRM entities fields to Drupal.
*
* Some trickiness here as declaring the 'schema' via our special civi
* schema function seems to cause fields to be declared twice if we us
* property_info rather than property_info_alter.
*
* At the moment civicrm_relationship_type is the only entity being
* managed through 'our' schema.
*
* @param $info
*
* @return
*/
function civicrm_entity_entity_property_info_alter(&$info) {
if (!civicrm_initialize(TRUE)) {
return;
}
// We'll start with a few basic entities but we could get them the
// same way the API explorer does.
$entities = _civicrm_entity_enabled_entities();
foreach ($entities as $drupal_entity => $civicrm_entity) {
$info[$drupal_entity]['properties'] = _civicrm_entity_getproperties($civicrm_entity, 'property_info');
// $info[$drupal_entity]['bundles'] = array();
}
// This makes the drupal user available when chaining from a rule.
$info['civicrm_contact']['properties']['civicrm_user'] = array(
'label' => 'Drupal User',
'description' => 'Drupal User for contact',
'type' => 'user',
);
// Attach a CiviCRM Contact property to drupal users.
$info['user']['properties']['civicrm_contact'] = array(
'label' => 'CiviCRM Contact',
'description' => 'CiviCRM Contact for user',
'type' => 'civicrm_contact',
'field' => FALSE,
'translatable' => FALSE,
'getter callback' => 'civicrm_entity_user_contact_get',
);
return $info;
}
/**
* Whitelist of enabled entities. We don't have a compelling reason for not including all entities
* but some entities are fairly non-standard and of course the rule hook would instantiate rules
* more often if all were enabled.
*
* The whitelist approach is mostly out of caution
*
* @return array of enabled entities keyed by the drupal entity name
*/
function _civicrm_entity_enabled_entities() {
$whitelist = array(
'civicrm_address' => 'address',
'civicrm_event' => 'event',
'civicrm_contact' => 'contact',
'civicrm_contribution' => 'contribution',
'civicrm_participant' => 'participant',
'civicrm_relationship' => 'relationship',
'civicrm_relationship_type' => 'relationship_type',
'civicrm_activity' => 'activity',
'civicrm_entity_tag' => 'entity_tag',
'civicrm_membership' => 'membership',
'civicrm_membership_type' => 'membership_type',
'civicrm_group' => 'group',
'civicrm_grant' => 'grant',
'civicrm_tag' => 'tag',
);
//dirty check for whether financialType exists
if (!method_exists('CRM_Contribute_PseudoConstant', 'contributionType')) {
$whitelist['civicrm_financial_type'] = 'financial_type';
}
return $whitelist;
}
/**
* Please document this function.
*/
function _civicrm_entity_chained_fks() {
return array(
'CRM_Contact_DAO_Contact' => 'contact',
'CRM_Event_DAO_Event' => 'event',
);
}
/**
* Provide label (column) for each entity types.
*
* @TODO Use the CiviCRM 4.5 getlist function - possibly ported into this module to support 4.4
*
* @see http://api.drupal.org/api/drupal/modules!system!system.api.php/function/hook_entity_info/7
*
* @param $entity
*
* @return
*/
function _civicrm_entity_labels($entity) {
$labels = array(
'civicrm_activity' => 'subject',
'civicrm_address' => 'address_name',
'civicrm_contact' => 'display_name',
'civicrm_contribution' => 'source',
'civicrm_event' => 'title',
'civicrm_participant' => 'source',
'civicrm_relationship' => 'description',
'civicrm_relationship_type' => 'description',
// OK, I'm just putting in something that won't error for now.
'civicrm_entity_tag' => 'tag_id',
'civicrm_financial_type' => 'description',
// Ditto.
'civicrm_membership' => 'id',
'civicrm_membership_type' => 'name',
'civicrm_group' => 'name',
'civicrm_grant' => 'id',
'civicrm_tag' => 'name',
);
return $labels[$entity];
}
function _civicrm_entity_get_title($field_specs, $entity_type = '') {
if (!empty($entity_type)) {
$label_field = _civicrm_entity_labels($entity_type);
}
else {
$label_field = 'title';
}
if (empty($field_specs[$label_field])) {
if (array_key_exists('label', $field_specs)) {
$label_field = 'label';
}
else {
if (array_key_exists('name', $field_specs)) {
$label_field = 'name';
}
}
}
$title = empty($field_specs[$label_field]) ? 'Title not defined in schema' : $field_specs[$label_field];
return $title;
}
/**
* Label callback for civicrm_contact entity type.
*
* drupal_alter('civicrm_entity_' . $entity, $, $alterable2, $context);
*
* @param $entity
* @param $entity_type
*
* @return null|string
*/
function civicrm_entity_civicrm_contact_label_callback($entity, $entity_type) {
$label = isset($entity->display_name) ? $entity->display_name : '';
// drupal_alter('civicrm_entity_contact_label', $label, $entity);
if (isset($entity->email) && !empty($entity->email)) {
$label = t('!label <!email>', array(
'!label' => $label,
'!email' => $entity->email,
));
}
elseif (isset($entity->phone) && !empty($entity->phone)) {
$label = t('!label <!phone>', array(
'!label' => $label,
'!phone' => $entity->phone,
));
}
return $label;
}
/**
* Calculate fields for entities
*
* @param $civicrm_entity
* @param string $context
*
* @return array
*/
function _civicrm_entity_getproperties($civicrm_entity, $context = '') {
$info = array();
if ($civicrm_entity == 'contact') {
$info['civi_user'] = array(
'label' => 'Drupal User',
'type' => 'user',
);
}
$fields = civicrm_api($civicrm_entity, 'getfields', array(
'version' => 3,
'action' => 'create',
));
foreach ($fields['values'] as $fieldname => $field_specs) {
// Type is empty for custom fields - we should sort that out but
// skipping for now we are only doing 'integers' at this stage.
$types = array(
1 => 'integer',
2 => 'text',
32 => 'text',
16 => 'integer',
);
if (!empty($field_specs['type']) && array_key_exists($field_specs['type'], $types)) {
$info[$fieldname] = array(
'label' => _civicrm_entity_get_title($field_specs),
'type' => $types[$field_specs['type']],
'sanitize' => 'check_plain',
'setter callback' => 'entity_property_verbatim_set',
);
if (!empty($field_specs['api.required'])) {
$info[$fieldname]['required'] = TRUE;
}
if ($field_specs['type'] == 16) {
$info[$fieldname]['size'] = 'tiny';
}
// This is a semi-reliable way of distinguishing 'real' fields
// from pseudo fields and custom fields and impacts on views
// (which is only implemented in a very minor way at this stage
// because it is 'blocked' by the default views install using
// hook_views_data rather than hook_views_data_alter.
if (!empty($field_specs['name'])) {
$info[$fieldname]['schema field'] = $field_specs['name'];
}
// We will add contact as a related entity for FK references to
// contact. This could be expanded to all FKs e.g event_id in
// Participant. Could load the event at the moment we are being
// cautious.
if (CRM_Utils_Array::value('FKClassName', $field_specs)) {
$fks = _civicrm_entity_chained_fks();
if (array_key_exists($field_specs['FKClassName'], $fks)) {
$fks_entity = $fks[$field_specs['FKClassName']];
$info[$fieldname . '_' . $fks_entity] = array(
'label' => _civicrm_entity_get_title($field_specs),
'type' => 'civicrm_' . $fks_entity,
'property_info' => array(
'field' => $fieldname,
'entity' => $fks_entity,
),
'getter callback' => 'civicrm_entity_metadata_civicrm_entity_get_properties',
);
}
}
// @TODO We are treating contact as the only possible entity
// which is not great - need to figure out better approach - can
// we have more than one? Define 'civicrm_entity'?
if ($fieldname == 'entity_id') {
$fks_entity = 'contact';
$info[$fieldname . '_' . $fks_entity] = array(
'label' => _civicrm_entity_get_title($field_specs),
'type' => 'civicrm_' . $fks_entity,
'property_info' => array(
'field' => $fieldname,
'entity' => $fks_entity,
),
'getter callback' => 'civicrm_entity_metadata_civicrm_entity_get_properties',
);
}
if (!empty($field_specs['options'])) {
// $info[$fieldname]['type'] = 'list<integer>';
$info[$fieldname]['options list'] = '_civicrm_entity_rules_attach_options';
$info[$fieldname]['options data'] = $field_specs['options'];
if ($context == 'property_info') {
$info[$fieldname]['property defaults']['options list'] = $field_specs['options'];
}
}
$info['type'] = array(
'label' => t('Type'),
'description' => t('Dummy field for bundle key'),
'type' => 'token',
'setter callback' => 'entity_property_verbatim_set',
'required' => FALSE,
'property defaults' => array(
'civicrm_' . strtolower($civicrm_entity),
),
);
}
}
return $info;
}
function civicrm_entity_form($form, &$form_state, $entity, $op, $entity_type) {
// Add the field related form elements.
$form_state['entity'] = new CivicrmEntity((array) $entity, $entity_type);
field_attach_form($entity_type, $entity, $form, $form_state);
//not quite sure why these are not being added but ....
$wrapper = entity_metadata_wrapper($entity_type);
foreach ($wrapper as $name => $child) {
$info = $child
->info();
$form[$name] = array(
'#type' => $info['type'],
'#title' => $info['label'],
'#description' => !empty($info['description']) ? $info['description'] : '',
);
}
$form['actions'] = array(
'#type' => 'container',
'#attributes' => array(
'class' => array(
'form-actions',
),
),
'#weight' => 400,
);
$form['#validate'] = array();
$form['#submit'] = array();
$form['#validate'][] = 'civicrm_entity_form_validate';
$form['#submit'][] = 'civicrm_entity_form_submit';
// We add the form's #submit array to this button along with the actual submit
// handler to preserve any submit handlers added by a form callback_wrapper.
$submit = array();
if (!empty($form['#submit'])) {
$submit += $form['#submit'];
}
$form['actions']['submit'] = array(
'#type' => 'submit',
'#value' => t('Save'),
'#submit' => $submit + array(),
);
return $form;
}
/**
* Form API validate callback for the entity form
*/
function civicrm_entity_form_validate(&$form, &$form_state) {
$entity = $form_state['entity'];
$entity_type = $form_state['entity_type'];
// Notify field widgets to validate their data.
field_attach_form_validate($entity_type, $entity, $form, $form_state);
}
/**
* Form API submit callback for the entity form.
*
*/
function civicrm_entity_form_submit(&$form, &$form_state) {
$entity_type = $form_state['entity_type'];
//@todo - what is the correct way to do this - taken from bangpound but then I had to do casting
$entity = entity_ui_controller($entity_type)
->entityFormSubmitBuildEntity($form, $form_state);
$entity = new CivicrmEntity((array) $entity, $entity_type);
// Add in created and changed times.
if ($entity->is_new = isset($entity->is_new) ? $entity->is_new : 0) {
$entity->created = time();
}
$entity->changed = time();
$entity
->save();
$t_args = array(
'%label' => entity_label($entity_type, $entity),
);
drupal_set_message(t('Drupal fields on %label have been updated.', $t_args));
}
/**
* Implement getter callback.
*
* NB this is in a separate file called callbacks.inc in entity module
* - I couldn't see how it was loaded so maybe the name has some
* magic?
*
* @param $data
* @param $options
* @param $name
* @param $type
* @param $info
*
* @return object
*/
function civicrm_entity_metadata_civicrm_entity_get_properties($data, $options, $name, $type, $info) {
$entity = civicrm_api($info['property_info']['entity'], 'get', array(
'version' => 3,
'id' => $data->{$info}['property_info']['field'],
'sequential' => 1,
));
return (object) $entity['values'][0];
}
/**
* Condition Drupal User Account exists for contact.
*
* @param array $contact
* Contact array.
*
* @return object
* Drupal user object if success, FALSE on fail.
*/
function civicrm_entity_user_exists($contact) {
return civicrm_entity_action_load_user($contact);
}
/**
* Condition Drupal User Account can be created for contact (creates contact).
*
* @param array $contact
* contact array
*
* @return object
* Drupal user object if success, FALSE on Fail
*/
function civicrm_entity_user_creatable($contact) {
return civicrm_entity_action_create_user($contact, TRUE);
}
/**
* Condition Drupal User Account can be created or exists for contact.
*
* Ccreates contact if appropriate.
*
* @param array $contact
* contact array
*
* @return mixed
* Drupal user object if success, FALSE on fail.
*/
function civicrm_entity_user_exists_or_creatable($contact) {
return civicrm_entity_action_load_create_user($contact);
}
/**
* Given a contact object return the Drupal user.
*
* @param StdClass $entity
* Contact Std Object
*
* @return object
* Drupal user object.
*/
function civicrm_entity_action_load_user($entity) {
$domain_id = civicrm_api('domain', 'getvalue', array(
'version' => 3,
'return' => 'id',
'current_domain' => TRUE,
));
$params = array(
'version' => 3,
'contact_id' => $entity->id,
'return' => 'uf_id',
'domain_id' => $domain_id,
);
$contact = civicrm_api('uf_match', 'getsingle', $params);
if (empty($contact['is_error'])) {
return array(
'civicrm_user' => user_load($contact['uf_id']),
);
}
}
/**
* Given a contact object, load or create then return a drupal user.
*
* @param object $contact
* CiviCRM Contact Object
*
* @param $is_active
* @param bool $notify
* @param bool $signin
*
* @throws Exception
* @return object
* $user Drupal user object or FALSE.
*/
function civicrm_entity_action_create_user($contact, $is_active, $notify = FALSE, $signin = FALSE) {
if (!is_array($contact)) {
// Perhaps we should be accepting object rather than array here?
$contact = (array) $contact;
}
// We'll use the civicrm sync mechanism to see if Civi can match the
// contact to an existing user.
//
// Don't think this is a great approach but will use for now - could
// just create the user but no great support for that yet.
if (empty($contact['display_name']) || empty($contact['email'])) {
$contact = civicrm_api('contact', 'getsingle', array(
'version' => 3,
'id' => $contact['id'],
'sequential' => 1,
'return' => 'email,display_name',
));
}
if (!is_string($contact['email']) && isset($contact['email'][0]->email)) {
$contact['email'] = $contact['email'][0]->email;
}
// @TODO What happens if they don't have an email at this point?
// An email is a pre-requisite for a Drupal account, so the action
// fails if they don't have an email.
$params = array(
'name' => $contact['display_name'],
'mail' => $contact['email'],
'email' => $contact['email'],
'init' => $contact['email'],
);
// Check if the requested username is available.
$errors = array();
$config = CRM_Core_Config::singleton();
$config->userSystem
->checkUserNameEmailExists($params, $errors);
if (!empty($errors)) {
foreach ($errors as $error) {
drupal_set_message(t($error), 'error');
}
return FALSE;
}
$params['cms_name'] = $params['name'] = $user['name'] = !empty($contact['display_name']) ? $contact['display_name'] : $params['mail'];
$params['cms_pass'] = $user['pass'] = substr(str_shuffle("abcefghijklmnopqrstuvwxyz"), 0, 8);
$params['status'] = $is_active;
if ($notify) {
$params['notify'] = TRUE;
}
$params['roles'] = array(
DRUPAL_AUTHENTICATED_RID => 'authenticated user',
);
// Set $config->inCiviCRM = TRUE to prevent creating a duplicate
// contact from user_save().
$config = CRM_Core_Config::singleton();
$config->inCiviCRM = TRUE;
$user_object = user_save('', $params);
$user_object->password = $user['pass'];
$config->inCiviCRM = FALSE;
// If selected in action configuration, notify the newly created
// user & send registration link. Does not contain password in D7.
if ($notify) {
drupal_mail('user', 'register_no_approval_required', $params['mail'], NULL, array(
'account' => $user_object,
), variable_get('site_mail', 'noreply@example..com'));
}
// CiviCRM doesn't do this when created off CiviCRM Form.
//
// Note that we 'pretend' to be logging in to make it do a ufmatch
// on just the email.
CRM_Core_BAO_UFMatch::synchronizeUFMatch($user_object, $user_object->uid, $contact['email'], 'drupal', NULL, NULL, TRUE);
// If selected in action configuration, automatically sign in the
// current user.
if ($signin) {
global $user;
$user = user_load($user_object->uid);
watchdog('civicrm_entity', 'User %name logged in via CiviCRM Entity rule execution.', array(
'%name' => $user->name,
), WATCHDOG_INFO);
$form_values = array(
'uid' => $user->uid,
);
user_login_finalize($form_values);
}
return array(
'civicrm_user' => $user_object,
);
}
function civicrm_entity_query($type, $property, $value, $limit) {
$return = entity_load($type, $ids = FALSE, array(
$property => $value,
'options' => array(
'limit' => $limit,
),
));
return array(
'entity_fetched' => array_values($return),
);
}
/**
* Info alteration callback for the entity query action.
* @todo this is copy of rules_action_entity_query_info_alter
*
* @param $element_info
* @param RulesAbstractPlugin $element
*/
function civicrm_entity_query_info_alter(&$element_info, RulesAbstractPlugin $element) {
$element->settings += array(
'type' => NULL,
'property' => NULL,
);
if ($element->settings['type']) {
$element_info['parameter']['property']['options list'] = 'rules_action_entity_query_property_options_list';
if ($element->settings['property']) {
$wrapper = rules_get_entity_metadata_wrapper_all_properties($element);
if (isset($wrapper->{$element->settings['property']}) && ($property = $wrapper->{$element->settings['property']})) {
$element_info['parameter']['value']['type'] = $property
->type();
$element_info['parameter']['value']['options list'] = $property
->optionsList() ? 'rules_action_entity_query_value_options_list' : FALSE;
}
}
}
$element_info['provides']['entity_fetched']['type'] = 'list<' . $element->settings['type'] . '>';
}
/**
* Load or create user as appropriate.
*
* @param $entity
* @param int $is_active
* @param int $notify
*
* @return object
*/
function civicrm_entity_action_load_create_user($entity, $is_active = 0, $notify = 0) {
if ($user = civicrm_entity_action_load_user($entity)) {
if ($is_active && !$user['civicrm_user']->status) {
$user['civicrm_user']->status = $is_active;
$user['civicrm_user']->save;
}
return $user;
}
return civicrm_entity_action_create_user((array) $entity, $is_active, $notify);
}
/**
* @param $user
*
* @param null $email
*
* @return mixed
*/
function civicrm_entity_action_load_create_contact($user, $email = NULL) {
try {
return civicrm_entity_action_load_contact($user);
} catch (CiviCRM_API3_Exception $e) {
$ufMatch = CRM_Core_BAO_UFMatch::synchronizeUFMatch($user, $user->uid, $email ? $email : $user->mail, 'Drupal', FALSE, 'Individual');
$entities = entity_load('civicrm_contact', $ufMatch->contact_id);
return array(
'civicrm_contact' => reset($entities),
);
}
}
/**
* @param $user
*
* @return mixed
* @throws CiviCRM_API3_Exception
*/
function civicrm_entity_action_load_contact($user) {
if (!civicrm_initialize()) {
return;
}
$contact_id = civicrm_api3('uf_match', 'getvalue', array(
'uf_id' => $user->uid,
'return' => 'contact_id',
'domain_id' => CRM_Core_Config::domainID(),
));
$entities = entity_load('civicrm_contact', array(
$contact_id,
));
return array(
'civicrm_contact' => reset($entities),
);
}
/**
* Implement the post hook and fire the corresponding rules event.
*
* @param $op
* @param $object_name
* @param $object_id
* @param $object_ref
*/
function civicrm_entity_civicrm_post($op, $object_name, $object_id, &$object_ref) {
if (!module_exists('rules')) {
return;
}
$contact_types = array(
'Individual',
'Household',
'Organization',
);
if (in_array($object_name, $contact_types)) {
$object_name = 'Contact';
}
$valid_objects = _civicrm_entity_enabled_entities();
$entity_name = _civicrm_entity_get_entity_name_from_camel($object_name);
if (!in_array($entity_name, $valid_objects, TRUE)) {
return;
}
$event_name = NULL;
switch ($op) {
case 'create':
case 'edit':
case 'delete':
$event_name = 'civicrm_' . $entity_name . "_{$op}";
break;
default:
break;
}
if ($entity_name == 'entity_tag') {
// Argh entity tag is completely non-standard!!!
// @see CRM-11933
foreach ($object_ref[0] as $entity_tag) {
$object = new CRM_Core_BAO_EntityTag();
$object->entity_id = $entity_tag;
$object->entity_table = 'civicrm_contact';
$object->tag_id = $object_id;
if ($object
->find(TRUE)) {
// This find is probably not necessary but until more testing
// on the tag create is done I will.
rules_invoke_event($event_name, $object);
}
}
}
else {
if ($event_name) {
rules_invoke_event($event_name, $object_ref);
}
}
}
/**
* Convert possibly camel name to underscore separated entity name.
*
* @see _civicrm_api_get_entity_name_from_camel()
*
* @TODO Why don't we just call the above function directly?
* Because the function is officially 'likely' to change as it is an internal api function and calling api functions directly is explicitly not supported
*
* @param string $entity
* Entity name in various formats e.g:
* Contribution => contribution,
* OptionValue => option_value,
* UFJoin => uf_join.
*
* @return string
* $entity entity name in underscore separated format
*/
function _civicrm_entity_get_entity_name_from_camel($entity) {
if ($entity == strtolower($entity)) {
return $entity;
}
else {
$entity = ltrim(strtolower(str_replace('U_F', 'uf', preg_replace('/(?=[A-Z])/', '_$0', $entity))), '_');
}
return $entity;
}
/**
* Load contact entity according to user id.
*
* @param $data
* @param array $options
* @param $name
* @param $type
* @param $info
*
* @return null
*/
function civicrm_entity_user_contact_get($data, array $options, $name, $type, $info) {
if (!module_exists('civicrm') || !function_exists('civicrm_initialize')) {
return;
}
if (!civicrm_initialize()) {
return;
}
$domain_id = civicrm_api('domain', 'getvalue', array(
'version' => 3,
'return' => 'id',
'current_domain' => TRUE,
));
$contact = civicrm_api('uf_match', 'getsingle', array(
'version' => 3,
'return' => 'contact_id',
'uf_id' => $data->uid,
'domain_id' => $domain_id,
));
if (!empty($contact['contact_id'])) {
$entity = entity_load('civicrm_contact', array(
$contact['contact_id'],
));
return $entity[$contact['contact_id']];
}
else {
return NULL;
}
}
/**
* Implements hook_rules_action_info_alter
* I can't seem to get my info_alter function called by hook so am doing this hacky intercept
* to call my function (& then go back to the main function if not a CiviCRM entity
*/
function civicrm_entity_rules_action_info_alter(&$info) {
$info['entity_create']['callbacks']['info_alter'] = 'civicrm_entity_rules_action_entity_create_info_alter';
}
/**
* Info alteration callback for the entity create action.
* Here we add a tonne of fields to civicrm entity create
*/
function civicrm_entity_rules_action_entity_create_info_alter(&$element_info, RulesAbstractPlugin $element) {
if (empty($element->settings['type']) || substr($element->settings['type'], 0, 8) != 'civicrm_') {
module_load_include('inc', 'rules', 'modules/entity.eval');
return rules_action_entity_create_info_alter($element_info, $element);
}
if (!empty($element->settings['type']) && entity_get_info($element->settings['type'])) {
$wrapper = entity_metadata_wrapper($element->settings['type']);
// Add the data type's needed parameter for loading to the parameter info.
foreach ($wrapper as $name => $child) {
$info = $child
->info();
$info += array(
'type' => 'text',
);
// Prefix parameter names to avoid name clashes with existing parameters.
$element_info['parameter']['param_' . $name] = array_intersect_key($info, array_flip(array(
'type',
'label',
'description',
)));
$element_info['parameter']['param_' . $name]['options list'] = $child
->optionsList() ? 'rules_action_entity_parameter_options_list' : FALSE;
$element_info['parameter']['param_' . $name]['optional'] = empty($info['required']);
}
unset($element_info['parameter']['type']);
foreach (civicrm_entity_get_custom_fields('contribution') as $fieldname => $field) {
$element_info['parameter'][$fieldname] = array(
'type' => $field['type'],
'label' => $field['label'],
'optional' => TRUE,
'default mode' => 'selector',
);
}
$element_info['provides']['entity_created']['type'] = $element->settings['type'];
if (($bundleKey = $wrapper
->entityKey('bundle')) && isset($element->settings['param_' . $bundleKey])) {
$element_info['provides']['entity_created']['bundle'] = $element->settings['param_' . $bundleKey];
}
}
}
/**
* @param $entity
*/
function civicrm_entity_get_custom_fields($entity, $types = array(
'Integer' => 'integer',
'String' => 'text',
'Date' => 'date',
)) {
if (!civicrm_initialize()) {
return array();
}
$fields = civicrm_api3($entity, 'getfields', array(
'action' => 'create',
'getoptions' => TRUE,
));
$fields = $fields['values'];
foreach ($fields as $field_name => $field) {
if (substr($field_name, 0, 7) != 'custom_' || !in_array($field['data_type'], array_keys($types))) {
unset($fields[$field_name]);
}
else {
$fields[$field_name]['type'] = $types[$field['data_type']];
}
}
return $fields;
}
Functions
Name | Description |
---|---|
civicrm_entity_access | Entity access callback. |
civicrm_entity_action_create_user | Given a contact object, load or create then return a drupal user. |
civicrm_entity_action_load_contact | |
civicrm_entity_action_load_create_contact | |
civicrm_entity_action_load_create_user | Load or create user as appropriate. |
civicrm_entity_action_load_user | Given a contact object return the Drupal user. |
civicrm_entity_civicrm_contact_label_callback | Label callback for civicrm_contact entity type. |
civicrm_entity_civicrm_post | Implement the post hook and fire the corresponding rules event. |
civicrm_entity_entity_info | Here we declare selected CiviCRM entities to Drupal. |
civicrm_entity_entity_property_info_alter | Here we declare Selected CiviCRM entities fields to Drupal. |
civicrm_entity_form | |
civicrm_entity_form_submit | Form API submit callback for the entity form. |
civicrm_entity_form_validate | Form API validate callback for the entity form |
civicrm_entity_get_custom_fields | |
civicrm_entity_get_field_type | Please document this function. |
civicrm_entity_get_schema | Get schema for entities. |
civicrm_entity_menu_alter | Implements hook_menu_later(). |
civicrm_entity_metadata_civicrm_entity_get_properties | Implement getter callback. |
civicrm_entity_permission | Implements hook_permission(). |
civicrm_entity_query | |
civicrm_entity_query_info_alter | Info alteration callback for the entity query action. @todo this is copy of rules_action_entity_query_info_alter |
civicrm_entity_rules_action_entity_create_info_alter | Info alteration callback for the entity create action. Here we add a tonne of fields to civicrm entity create |
civicrm_entity_rules_action_info_alter | Implements hook_rules_action_info_alter I can't seem to get my info_alter function called by hook so am doing this hacky intercept to call my function (& then go back to the main function if not a CiviCRM entity |
civicrm_entity_schema_alter | Implements hook_schema_alter(). |
civicrm_entity_user_contact_get | Load contact entity according to user id. |
civicrm_entity_user_creatable | Condition Drupal User Account can be created for contact (creates contact). |
civicrm_entity_user_exists | Condition Drupal User Account exists for contact. |
civicrm_entity_user_exists_or_creatable | Condition Drupal User Account can be created or exists for contact. |
_civicrm_entity_chained_fks | Please document this function. |
_civicrm_entity_enabled_entities | Whitelist of enabled entities. We don't have a compelling reason for not including all entities but some entities are fairly non-standard and of course the rule hook would instantiate rules more often if all were enabled. |
_civicrm_entity_getproperties | Calculate fields for entities |
_civicrm_entity_get_entity_name_from_camel | Convert possibly camel name to underscore separated entity name. |
_civicrm_entity_get_title | |
_civicrm_entity_labels | Provide label (column) for each entity types. |