party.module in Party 8.2
Same filename and directory in other branches
Provides a generic CRM party entity.
File
party.moduleView source
<?php
/**
* @file
* Provides a generic CRM party entity.
*/
/**
* Implements hook_help().
*/
function party_help($path, $arg) {
switch ($path) {
case 'admin/help#party':
return t("TODO: Create admin help text.");
case 'admin/config/party/labels':
return t("Party name label generators save a label whenever a party is created or updated. This lets you form the party's label or name in a variety of methods.");
case 'admin/config/party/piece-order':
return t("The tabs that display below each party can be dragged into the desired order below.");
case 'admin/config/party/primary-fields':
return t('Primary fields allow you to store key information quickly and accessibly for use in bulk and automated operations. For each type, select where you want to pull this information from.');
}
}
/**
* Implements hook_entity_info().
*
* Declare our party entity to the entity system.
*/
function party_entity_info() {
$party_info['party'] = array(
'label' => t('Party'),
'plural label' => t('Parties'),
'entity class' => 'Party',
'controller class' => 'PartyController',
// We define this so entity module provides us with basic Views data, while
// allowing us to define more of our own.
// See http://drupal.org/node/1307760.
'views controller class' => 'EntityDefaultViewsController',
'base table' => 'party',
//'uri callback' => 'party_uri',
'fieldable' => TRUE,
'module' => 'party',
'entity keys' => array(
'id' => 'pid',
'label' => 'label',
),
'access callback' => 'party_entity_access',
'uri callback' => 'party_uri',
// Entity API admin UI.
'admin ui' => array(
'controller class' => 'PartyUIController',
'path' => 'admin/community',
// Urgh. Our admin UI is split between admin.inc and pages.inc!
// @todo untangle and fix.
'file' => 'party.pages.inc',
),
//'static cache' => TRUE,
'bundles' => array(
'party' => array(
'label' => t('Party'),
'admin' => array(
'path' => 'admin/community/party',
'access arguments' => array(
'administer parties',
),
),
),
),
'view modes' => array(
'full' => array(
'label' => t('Full Contact'),
'custom settings' => FALSE,
),
),
);
return $party_info;
}
/**
* Implements hook_entity_info_alter().
*
* Make standard alterations to entities that declare they work with Parties
* via hook_party_data_set_info().
*
* @see PartyDefaultDataSet::hook_entity_info_alter()
*/
function party_entity_info_alter(&$entity_info) {
$sets = party_get_data_set_info();
foreach ($sets as $set) {
$entity_info[$set['entity type']]['crm controller class'] = $set['class'];
// Pass this onto the class to make changes.
call_user_func_array(array(
$set['class'],
'hook_entity_info_alter',
), array(
&$entity_info[$set['entity type']],
));
}
}
/**
* Implements hook_menu().
*/
function party_menu() {
// CRM settings.
// Making up a new config category.
// Alternative is to put this all under top-level admin.
// But all this structure is rough anyway.
$items['admin/config/party'] = array(
'title' => 'Party',
'description' => 'Party Settings',
'position' => 'left',
'weight' => -10,
'page callback' => 'system_admin_menu_block_page',
'access arguments' => array(
'access administration pages',
),
'file' => 'system.admin.inc',
'file path' => drupal_get_path('module', 'system'),
);
$items['admin/config/party/labels'] = array(
'title' => 'Label Plugins',
'description' => 'Determine how labels for parties are generated.',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'party_settings_label_plugins_form',
),
'access arguments' => array(
'administer crm settings',
),
'file' => 'party.admin.inc',
);
$items['admin/config/party/primary-fields'] = array(
'title' => 'Primary Fields',
'description' => 'Specify where to take primary fields from.',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'party_settings_primary_fields_form',
),
'access arguments' => array(
'administer crm settings',
),
'file' => 'party.admin.inc',
);
$items['admin/config/party/labels/%'] = array(
'title' => 'Configure Plugin',
'description' => 'Configure the Chosen Label Plugin',
'page callback' => 'party_settings_label_plugin_config_page',
'page arguments' => array(
4,
),
'access arguments' => array(
'administer crm settings',
),
'file' => 'party.admin.inc',
);
$items['admin/config/party/piece-order'] = array(
'title' => 'Piece order',
'description' => 'Rearrange the order of pieces within a party.',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'party_settings_pieces_order_form',
),
'access arguments' => array(
'administer crm settings',
),
'file' => 'party.admin.inc',
);
$items['admin/community/datasets'] = array(
'title' => 'Manage data sets',
'page callback' => 'party_data_set_admin',
'access arguments' => array(
'administer parties',
),
'file' => 'party.admin.inc',
'type' => MENU_LOCAL_TASK,
);
$items['admin/community/party'] = array(
'title' => 'Manage parties',
'description' => 'Manage contact information',
'page callback' => 'party_info',
'access arguments' => array(
'administer parties',
),
'file' => 'party.admin.inc',
'type' => MENU_LOCAL_TASK,
);
$items['party/%party'] = array(
'title callback' => 'party_page_title',
'title arguments' => array(
1,
),
'page callback' => 'party_page_view',
'page arguments' => array(
1,
),
'file' => 'party.pages.inc',
'access callback' => 'party_access',
'access arguments' => array(
'view',
1,
),
'type' => MENU_NORMAL_ITEM,
);
// Build the party view first-level tabs.
// @todo: Write a contrib module to turn a set of tabs into ajax tabs,
// probably using or as part of quicktabs module.
$pieces = party_get_party_piece_info();
// These come sorted by weight so we know which to make the default tab.
foreach ($pieces as $path => $piece) {
if (!isset($seen_first_piece)) {
$seen_first_piece = TRUE;
$piece['type'] = MENU_DEFAULT_LOCAL_TASK;
}
// Add in some defaults for convenience.
// @todo: once these stabilize, document them in the API file.
$piece += array(
'type' => MENU_LOCAL_TASK,
'page arguments' => array(
1,
2,
),
// Make this explicit so it overrides the parent.
'access callback' => 'party_access',
'access arguments' => array(
'view',
1,
2,
),
);
$items["party/%party/{$path}"] = $piece;
}
$items['party/%party/party'] = array(
'title' => 'Overview',
'type' => MENU_DEFAULT_LOCAL_TASK,
'access callback' => 'party_access',
'access arguments' => array(
'view',
1,
),
'page callback' => 'party_page_view',
'page arguments' => array(
1,
),
'file' => 'party.pages.inc',
'weight' => -20,
);
// This is temporary until I figure out a neat way to do tabs below pieces.
$items['party/%party/party/view'] = array(
'title' => 'View',
'page callback' => 'party_page_view',
'page arguments' => array(
1,
),
'file' => 'party.pages.inc',
'type' => MENU_DEFAULT_LOCAL_TASK,
'weight' => -10,
);
$items['party/%party/party/edit'] = array(
'title' => 'Edit',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'party_form',
1,
),
'access callback' => 'party_access',
'access arguments' => array(
'edit',
1,
),
'file' => 'party.pages.inc',
'type' => MENU_LOCAL_TASK,
'weight' => -5,
);
// End temporary.
$items['party/%party/party/delete'] = array(
'title' => 'Delete',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'party_delete_form',
1,
),
'access callback' => 'party_access',
'access arguments' => array(
'delete',
1,
),
'file' => 'party.pages.inc',
'type' => MENU_LOCAL_TASK,
'weight' => 10,
);
// Attached entity menu items
// Edit an attached entity
$items['party/%party/%party_data_set/edit/%'] = array(
'page callback' => 'drupal_get_form',
'page arguments' => array(
'party_attached_entity_edit_form',
1,
2,
4,
),
'access callback' => 'party_access',
'access arguments' => array(
'edit',
1,
2,
),
'file' => 'party.pages.inc',
);
// Detach an attached entity
$items['party/%party/%party_data_set/remove/%'] = array(
'page callback' => 'drupal_get_form',
'page arguments' => array(
'party_attached_entity_remove_confirm',
1,
2,
4,
),
'access callback' => 'party_access',
'access arguments' => array(
'detach',
1,
2,
),
'file' => 'party.pages.inc',
);
// Add an attached entity
$items['party/%party/%party_data_set/add'] = array(
'page callback' => 'drupal_get_form',
'page arguments' => array(
'party_attached_entity_action_form',
1,
2,
'add',
),
'access callback' => 'party_access',
'access arguments' => array(
'add',
1,
2,
),
'file' => 'party.pages.inc',
);
// Attach an existing entity.
$items['party/%party/%party_data_set/attach'] = array(
'page callback' => 'drupal_get_form',
'page arguments' => array(
'party_attached_entity_action_form',
1,
2,
'attach',
),
'access callback' => 'party_access',
'access arguments' => array(
'attach',
1,
2,
),
'file' => 'party.pages.inc',
);
$items['party/add'] = array(
'title' => 'Add party',
'page callback' => 'party_add',
'file' => 'party.pages.inc',
'access arguments' => array(
'create parties',
),
);
// Provide useful information for developers.
// This may eventually move to a devel_party module if there's more of it.
if (module_exists('devel')) {
$items['devel/crm/info'] = array(
'title' => 'CRM info',
'description' => 'View CRM data.',
'page callback' => 'party_devel_info_page',
'access arguments' => array(
'access devel information',
),
'file' => 'party.admin.inc',
'menu_name' => 'devel',
'weight' => 10,
);
}
return $items;
}
/**
* Implements hook_menu_local_tasks_alter().
*
* Adds local tasks in the following places:
* - to add a party from the party list admin page
* - to add/import a new data set (ie entity bundle) from the data sets admin page
* - to add new entities on a party piece that's based on a data set
*/
function party_menu_local_tasks_alter(&$data, $router_item, $root_path) {
// Add action link to 'party/add' on 'admin/community/list' page.
if ($root_path == 'admin/community/list' || $root_path == 'admin/community') {
$item = menu_get_item('party/add');
if ($item['access']) {
$data['actions']['output'][] = array(
'#theme' => 'menu_local_action',
'#link' => $item,
);
}
}
// Add action links to 'admin/community/datasets' page.
if ($root_path == 'admin/community/datasets') {
$data_sets = party_get_data_set_info();
$attached_entity_types = array();
foreach ($data_sets as $data_set) {
$attached_entity_types[$data_set['entity type']] = $data_set['admin'];
}
foreach ($attached_entity_types as $type => $admin) {
$type = entity_get_info($type);
if (isset($admin['create'])) {
$item = menu_get_item($admin['create']);
if ($item['access']) {
$item['title'] = 'Add ' . $type['label'] . ' data set';
$item['localized_options'] = array(
'query' => array(
'destination' => 'admin/community/datasets',
),
);
$data['actions']['output'][] = array(
'#theme' => 'menu_local_action',
'#link' => $item,
);
}
}
if (isset($admin['import'])) {
$item = menu_get_item($admin['import']);
$item['localized_options'] = array(
'query' => array(
'destination' => 'admin/community/datasets',
),
);
$item['title'] = 'Import ' . $type['label'] . ' data set';
if ($item['access']) {
$data['actions']['output'][] = array(
'#theme' => 'menu_local_action',
'#link' => $item,
);
}
}
}
}
// Add action links for attaching new entities on party pieces that are built
// from data sets.
if (substr($root_path, 0, 8) == 'party/%/') {
if (!isset($router_item['original_map'][3])) {
$piece_subpath = $router_item['original_map'][2];
$pieces = party_get_party_piece_info();
if (!isset($pieces[$piece_subpath])) {
return;
}
$piece = $pieces[$piece_subpath];
if (isset($piece['data_set'])) {
$data_set_base_path = implode('/', $router_item['original_map']);
$data_set = party_get_data_set_info($piece['data_set']);
foreach ($data_set['actions'] as $action => $action_info) {
$item = menu_get_item($data_set_base_path . '/' . $action);
// Menu access checks party_access(), which checks whether actions are
// allowed by the data set definition.
if ($item['access']) {
$data['actions']['output'][] = array(
'#theme' => 'menu_local_action',
'#link' => array(
'title' => t($action_info['action label'], array(
'@data-set' => $data_set['label'],
)),
'href' => $data_set_base_path . '/' . $action,
),
);
}
}
}
}
}
}
/**
* Menu loader for data sets. First check against pieces, and if nothings found
* check against the $data_set_names themselves.
*
* @param $data_set_url_string
* The url-form of a data set name, ie with hyphens instead of underscores.
*
* @return
* A loaded data set definition.
*/
function party_data_set_load($data_set_url_string) {
foreach (party_get_data_set_info() as $data_set => $info) {
// Match the path string we've been given with the one that's defined in
// data sets and return the data set we find.
if (isset($info['path element']) && $info['path element'] == $data_set_url_string) {
return $info;
}
}
// If nothings been found yet, check up the data set names
return party_get_data_set_info($data_set_url_string);
}
/**
* Wrap around party_access() for the entity api 'access callback'.
*
* @param $op
* The operation being performed.
* @param $party
* A party to check access for.
* @param $account
* (optional) The user to check access for. Omit to check for the global user.
*
* @return
* Boolean; TRUE to grant access, FALSE to deny it.
*
* @see party_access
*/
function party_entity_access($op, $party = NULL, $account = NULL) {
return party_access($op, $party, NULL, $account);
}
/**
* Determines whether operations are allowed on a Party and attached entities.
*
* @param $op
* The operation being performed.
* Currently one of:
* - 'view': Whether the user may view the given party or data set.
* - 'edit': Whether the user may edit the given party or data set.
* - 'add': Whether the user may create a new entity the given data set to
* the party.
* - 'attach': Whether the user may attach an existing entity in the given
* data set to the party.
* - 'detach': Whether the user may detach the given data set from the
* party.
* - 'create': Whether the user may create a party of the type given by
* $party->type.
* @todo: consider distinguishing $op values for solo party vs attached
* entity, eg 'view attached' / 'view', so that we don't have to keep mucking
* about testing isset($attached_entity).
* @param $party
* A party to check access for.
* @param $data_set
* (optional) A dataset name or full definition to check access for. If
* nothing is given, access for just the party itself is determined.
* @param $account
* (optional) The user to check for. Omit to check for the global user.
*
* @return boolean
* Whether access is allowed or not.
*
* @see hook_party_access()
* @see party_party_access()
*/
function party_access($op, $party = NULL, $data_set = NULL, $account = NULL) {
// Let the admin through when there's no attached entity being considered.
if (!isset($data_set) && user_access('administer parties', $account)) {
return TRUE;
}
// If we've been passed a data set name we change it into an array.
if (isset($data_set) && is_string($data_set)) {
$data_set = party_get_data_set_info($data_set);
}
if (!isset($account)) {
$account = $GLOBALS['user'];
}
// Allow modules to grant / deny access.
// Keep track of which modules grant / deny access. This allows for easier
// debugging and may be helpful in the future.
foreach (module_implements('party_access') as $module) {
$access[$module] = module_invoke($module, 'party_access', $op, $party, $data_set, $account);
}
// Only grant access if at least one module granted access and no one denied
// access.
if (in_array(FALSE, $access, TRUE)) {
return FALSE;
}
elseif (in_array(TRUE, $access, TRUE)) {
return TRUE;
}
return FALSE;
}
/**
* Implements hook_party_access().
*
* Handles basic access to parties:
* - user permissions
* - data set cardinality settings
*/
function party_party_access($op, $party = NULL, $data_set = NULL, $account = NULL) {
// Set the data_set_name
if (isset($data_set)) {
$data_set_name = $data_set['set_name'];
}
// If we're looking at permission for a particular data set we check these.
if (isset($data_set_name)) {
// Determine what the Core permissions system has to say about this.
switch ($op) {
case 'view':
$permission_string = 'view party attached ' . $data_set_name;
break;
case 'edit':
$permission_string = 'edit party attached ' . $data_set_name;
break;
case 'detach':
$permission_string = 'detach party attached ' . $data_set_name;
break;
case 'attach':
case 'add':
$permission_string = 'attach party ' . $data_set_name;
break;
}
if (isset($permission_string)) {
$permission_access = user_access($permission_string, $account);
}
// Determine what data set info has to say about this.
// Data set actions in hook_party_data_set_info() are defined to match with
// values of $op here.
// Build an array of forced allowed actions.
// @TODO: remove this when we re-work permissions.
$allowed_ops = array(
'view',
'edit',
'detach',
);
// Other ops depend on the data set defining the action.
if (isset($data_set['actions'][$op]) || in_array($op, $allowed_ops)) {
$data_access = TRUE;
// TEMPORARY until we handle all actions here.
// see http://drupal.org/node/1673608, http://drupal.org/node/1673606
if ($op == 'add' || $op == 'attach') {
// Operations 'add' and 'attach' additionally need a check on data set
// cardinality.
// TODO: store the information about which ops need this elsewhere?
if (isset($data_set['max cardinality'])) {
$data_set_controller = party_get_crm_controller($party, $data_set_name);
$ids = $data_set_controller
->getEntityIds();
if (count($ids) >= $data_set['max cardinality']) {
$data_access = FALSE;
}
}
}
}
else {
$data_access = FALSE;
}
}
else {
// If we're not being asked about attachments, just use plain permissions.
switch ($op) {
case 'view':
$permission_string = 'view parties';
break;
case 'edit':
$permission_string = 'edit parties';
break;
case 'delete':
$permission_string = 'delete parties';
break;
}
if (isset($permission_string)) {
$permission_access = user_access($permission_string, $account);
}
}
// A data access deny is global.
if (isset($data_access) && $data_access == FALSE) {
return FALSE;
}
// Otherwise, permission access returns allow or ignore.
return !empty($permission_access) ? TRUE : NULL;
}
/**
* Implements hook_admin_paths().
*/
function party_admin_paths() {
$paths = array(
'party/*/*/edit/*' => TRUE,
'party/*/*/remove/*' => TRUE,
'party/*/*/add' => TRUE,
);
return $paths;
}
/**
* Page title callback for party view page.
*
* Has to be in the main module file because it's used by several menu items.
*/
function party_page_title($party) {
return $party->label;
}
// -----------------------------------------------------------------------
// Party pieces: defining extra hook_menu() items according to data structure.
/**
* Get all party piece definitions from hook_party_party_pieces().
*
* This is only used by hook_menu() and an admin page so no need to cache.
*
* @return
* An array of party pieces, keyed by path and sorted by weight.
* Keys in addition to those defined in hook_party_party_pieces():
* - data_set: The id of a data set if this piece is defined from one.
*/
function party_get_party_piece_info() {
$pieces = module_invoke_all('party_party_pieces');
// Add in weights from the admin setting.
$weights = variable_get('party_name_pieces_weights', array());
foreach ($pieces as $path => $piece) {
// The weight setting overrides weights defined in the hook.
if (isset($weights[$path])) {
$pieces[$path]['weight'] = $weights[$path];
}
}
// Sort pieces array by weight for hook_menu() to figure out the default tab
// and the admin UI to show them in the right order.
// drupal_sort_weight() treats a missing weight key as a 0.
uasort($pieces, 'drupal_sort_weight');
return $pieces;
}
/**
* Implements hook_party_party_pieces().
*
* Defines:
* - the basic piece for showing a party itself
* - pieces that data sets provide
* - pieces provided by Views as display plugins.
*/
function party_party_party_pieces() {
$pieces = array(
// The main party piece.
// By default this is the default tab, but the MENU_DEFAULT_LOCAL_TASK
// is supplied in hook_menu() to allow the piece order setting to change
// the default tab accordingly.
'party' => array(
'title' => 'Party',
'page callback' => 'party_page_view',
'page arguments' => array(
1,
),
'file' => 'party.pages.inc',
'access arguments' => array(
'view contacts',
),
'weight' => -10,
),
);
// Party data sets may provide a piece each. Here we handle those of type
// 'callback'; type 'views' is handled by our party_views_default_views()
// and our Views display plugin.
$sets = party_get_data_set_info();
//dsm($sets);
foreach ($sets as $set_name => $set) {
if (isset($set['piece']) && in_array($set['piece']['maker'], array(
'callback',
'core',
))) {
if ($set['piece']['maker'] == 'core') {
// 'core' is a special case of 'callback' where we supply the details.
$set['piece'] += array(
'title' => $set['label'],
'page callback' => 'party_view_data_set',
'page arguments' => array(
1,
$set_name,
),
'access callback' => 'party_access',
'access arguments' => array(
'view',
1,
$set_name,
),
'file' => 'party.pages.inc',
);
}
// The path becomes the piece's key.
$path = $set['piece']['path'];
unset($set['piece']['path']);
// Add a key to say we came from a dataset.
$set['piece']['data_set'] = $set_name;
$pieces[$path] = $set['piece'];
}
}
// Custom pieces can be created as Views plugins.
if (module_exists('views')) {
// Get all views displays that implement our hook.
// There's no need to cache: views_menu() doesn't cache for page displays.
$views = views_get_all_views();
foreach ($views as $view) {
// Disabled views get nothing.
if (!empty($view->disabled)) {
continue;
}
$view
->init_display();
foreach ($view->display as $display_id => $display) {
if (isset($display->handler) && !empty($display->handler->definition['uses hook party_party_pieces'])) {
$result = $display->handler
->execute_hook_party_party_pieces();
if (is_array($result)) {
// Add in access properties.
foreach ($result as $path => $piece) {
$result[$path] += array(
'access callback' => 'party_access',
'access arguments' => array(
'view',
1,
$piece['data_set'],
),
);
}
$pieces = array_merge($pieces, $result);
}
}
}
}
}
return $pieces;
}
// -----------------------------------------------------------------------
// API for getting and changing data sets.
/**
* Get the attached entity controller for a party.
*
* @param Party $party
* The party to get the data set for.
* @param $data_set_name
* The name of a data set.
*
* @return
* The controller class, without attached entities loaded yet.
*/
function party_get_crm_controller(Party $party, $data_set_name) {
// If we don't already have our data set, load it.
if (!isset($party->data_set_controllers[$data_set_name])) {
$sets = party_get_data_set_info();
// @todo: error handling
$class = $sets[$data_set_name]['class'];
$party->data_set_controllers[$data_set_name] = new $class($data_set_name, $party);
}
return $party->data_set_controllers[$data_set_name];
}
/**
* Get the data set definition associated with a given entity and bundle.
*
* @param $entity_type
* The entity type e.g profile2 etc.
* @param $entity
* The entity object or id.
*
* @return
* A data set name if one exists, NULL otherwise.
*/
function party_get_entity_data_set($entity_type, $entity) {
$data_set_info = party_get_data_set_info();
// Get bundle.
$info = entity_get_info($entity_type);
$bundle_key = empty($info['entity keys']['bundle']) ? FALSE : $info['entity keys']['bundle'];
if (!$bundle_key) {
$bundle = $entity_type;
}
else {
$bundle = $entity->{$bundle_key};
}
foreach ($data_set_info as $data_set_name => $data_set) {
if ($data_set['entity type'] == $entity_type && (!isset($data_set['entity bundle']) || $data_set['entity bundle'] == $bundle)) {
return $data_set_name;
}
}
return NULL;
}
/**
* Get all data sets from hook_party_data_set_info().
*
* @todo: cache this, either in the DB or using DrupalCacheArray.
*
* @param $data_set_name
* (optional) The name of the data set to return. If
* omitted, all are returned.
* @param $reset
* (optional) If set to true this will rebuild the data
* info, ignoring any cached version.
*
* @return
* Either a single data set, or an array of data sets keyed by set name.
* Each set is an array whose keys are as returned by
* hook_party_data_set_info(), with in addition:
* - 'module': The module defining this set.
* - 'table': The table in which this set's data is stored.
*/
function party_get_data_set_info($data_set_name = NULL, $reset = FALSE) {
$sets =& drupal_static(__FUNCTION__);
if (!isset($sets) || $reset) {
if (($cache = cache()
->get('party:data_set_info', 'cache')) && !$reset) {
$sets = $cache->data;
}
else {
$sets = array();
foreach (module_implements('party_data_set_info') as $module) {
// Due to http://drupal.org/node/890660 we can't use module_invoke_all()
// because we need to know the provenance of each set.
$sets_module = module_invoke($module, 'party_data_set_info');
foreach ($sets_module as $set_name => $set) {
// Add in some essential data we need, but allow modules to set this too.
if (isset($set['piece'])) {
$path_element = $set['piece']['path'];
}
else {
// @todo: fix this, as it's pretty weak and certainly in the case of
// the user data set, relies on the piece happening to define its
// path the same way.
$path_element = str_replace('_', '-', $set_name);
}
$set += array(
'set_name' => $set_name,
'module' => $module,
'singleton' => FALSE,
'view mode' => 'party',
'form callback' => 'party_default_attached_entity_form',
// Singleton entities have no bundle; use the entity type.
'entity bundle' => $set['entity type'],
'path element' => $path_element,
);
// Translate 'singleton' to max cardinality of 1.
// TODO: remove the singleton property? remove the cardinality
// property? Which one actually gets used?
if ($set['singleton']) {
$set['max cardinality'] = 1;
}
$sets[$set_name] = $set;
}
}
// Alter the data sets with hook_party_data_set_info_alter().
drupal_alter('party_data_set_info', $sets);
cache()
->set('party:data_set_info', $sets);
}
}
if (isset($data_set_name)) {
// @todo: Throw a big error if the $data_set_name doesn't exist
return isset($sets[$data_set_name]) ? $sets[$data_set_name] : FALSE;
}
else {
return $sets;
}
}
/**
* Get the data sets expected for a party.
*
* @todo: rename this function; the name is ambiguous.
*
* @param $party
* The party object in question.
*
* @return
* An array of data set names.
*
* @todo: Consider caching against the set of hats rather than the party id.
*/
function party_get_party_data_sets($party) {
$party_data_sets =& drupal_static(__FUNCTION__);
// If the sets have already been worked out return the cached list.
if (isset($party->pid) && !empty($party_data_sets[$party->pid])) {
return $party_data_sets[$party->pid];
}
$data_sets = array_keys(party_get_data_set_info());
// Allow modules to alter the party data sets.
drupal_alter('party_data_sets', $data_sets, $party);
// If a pid is set cache the result.
if (isset($party->pid)) {
$party_data_sets[$party->pid] = $data_sets;
}
return $data_sets;
}
// -----------------------------------------------------------------------
// API for relating and unrelating entities to a party.
/**
* Attach an entity to a party according to a given data set.
*
* @param $party
* The party to assign the entity to.
* @param $entity
* The entity to relate to.
* @param $data_set
* The name of the data set.
* DX WTF: can we sniff this out given the entity type and the entity object?
* DX WTF: Lots of sniffing now done BUT do we want the $data_set instance made elsewhere. If so where?
*/
function party_attach_entity($party, $entity, $data_set_name) {
$data_set_controller = party_get_crm_controller($party, $data_set_name);
$data_set_controller
->attachEntity($entity);
$data_set_controller
->save();
}
/**
* Detach an entity from a party according to a given data set.
*
* @param $party
* The party to detach the entity from.
* @param $entity
* The entity to detach. This may also be just the entity id.
* @param $data_set
* The name of the data set.
* DX WTF: can we sniff this out given the entity type and the entity object?
*/
function party_detach_entity($party, $entity, $data_set_name) {
/* To Test */
$data_set_controller = party_get_crm_controller($party, $data_set_name);
$data_set_controller
->detachEntity($entity);
$data_set_controller
->save();
}
// -----------------------------------------------------------------------
// API for loading data about a party.
/**
* Return a Data Set object containing all the attached entities in a given
* data set for a particular party.
*
* @param $party
* The party object of the party we're concerned with.
* @param $set_name
* The set type as defined in hook_party_data_set_info().
* @param $create
* Choose to create an entity if there isn't already at least one.
*
* @return
* A party data set object with attached entities available
*/
function party_get_data_set($party, $data_set_name, $create = FALSE) {
if (!$party) {
drupal_set_message(t('Party not set, unable to load attached entities.'), 'error');
return array();
}
$data_set_controller = party_get_crm_controller($party, $data_set_name);
$entity_ids = $data_set_controller
->getEntityIds();
if ($create && empty($entity_ids)) {
$entity = $data_set_controller
->createEntity();
$data_set_controller
->attachEntity($entity);
}
return $data_set_controller;
}
/**
* Return all attached entities of a particular set.
*
* @param $party
* The party object of the party we're concerned with.
* @param $set_name
* The set type as defined in hook_party_data_set_info().
* @param $create
* Choose to create an entity if there isn't already at least one.
*
* @return
* An array of the attached entity controllers for the entities attached to the
* party in the given data set, keyed by attached entity delta.
*/
function party_get_attached_entities($party, $data_set_name, $create = FALSE) {
$data_set_controller = party_get_data_set($party, $data_set_name, $create);
return $data_set_controller
->getEntities();
}
/**
* Get the form for a data set (more to the point get a set of fields for the data set
* might need to work on this). This function checks the edit party attached data set
* permission.
*
* @param $party
* The party object of the party we're concerned with.
* @param $data_set_name
* The data set name as defined in hook_data_set_info().
* @param $set_id
* The set id as stored in the related table
*
* @return
* A form array.
*
* @todo: On adding a party work well.
*/
function party_data_set_form($party, $data_set_name, $set_id = FALSE) {
// Check that the user has access to this form
if (!party_access('edit', $party, $data_set_name)) {
return FALSE;
}
$set = party_get_data_set_info($data_set_name);
$function = $set['form callback'];
if (function_exists($function)) {
$result = call_user_func($function, $party, $set_type, $set_id);
}
else {
return FALSE;
}
return $result;
}
/**
* Implements hook_permission().
*/
function party_permission() {
$permissions = array(
'administer crm settings' => array(
'title' => t('Administer party settings'),
'restrict access' => TRUE,
),
'administer parties' => array(
'title' => t('Administer parties'),
'restrict access' => TRUE,
),
'view parties' => array(
'title' => t('View parties'),
),
'create parties' => array(
'title' => t('Create parties'),
),
'edit parties' => array(
'title' => t('Edit parties'),
),
'delete parties' => array(
'title' => t('Delete parties'),
),
);
// Add permissions for each data set.
foreach (party_get_data_set_info() as $data_set_name => $data_set) {
// Build an array of default overrides.
$overrides = array_fill_keys(array(
'view',
'attach',
'edit',
'detach',
), array());
// Get the overrides from the data set if applicable.
if (isset($data_set['permissions'])) {
$overrides = array_merge_recursive($overrides, $data_set['permissions']);
}
$permissions['view party attached ' . $data_set_name] = $overrides['view'] + array(
'title' => t('View party attached %name', array(
'%name' => $data_set['label'],
)),
);
$permissions['attach party ' . $data_set_name] = $overrides['attach'] + array(
'title' => t('Add party attached %name', array(
'%name' => $data_set['label'],
)),
);
$permissions['edit party attached ' . $data_set_name] = $overrides['edit'] + array(
'title' => t('Edit party attached %name', array(
'%name' => $data_set['label'],
)),
);
$permissions['detach party attached ' . $data_set_name] = $overrides['detach'] + array(
'title' => t('Remove party attached %name', array(
'%name' => $data_set['label'],
)),
);
}
return $permissions;
}
/**
* URI callback for contacts.
*/
function party_uri($party) {
return array(
'path' => 'party/' . $party->pid,
);
}
/**
* Implements hook_theme().
*/
function party_theme() {
return array(
'party_settings_pieces_order_form' => array(
'render element' => 'form',
),
'party_settings_label_plugins_form' => array(
'render element' => 'form',
),
'entity__all__party' => array(
'render element' => 'elements',
'template' => 'entity--all--party',
'path' => drupal_get_path('module', 'party') . '/theme',
),
);
}
/**
* Implements hook_preprocess_HOOK().
*
* Add our own template for party display.
*/
function party_preprocess_entity(&$variables) {
if ($variables['view_mode'] == 'party') {
$entity_type = $variables['entity_type'];
$entity = $variables['elements']['#entity'];
list($eid, ) = entity_extract_ids($entity_type, $entity);
$party_id = $entity->party_attaching_party;
// @todo: clean this up -- having to load up the controller all over
// again when we probably had it at some earlier point is just messy.
$data_set_name = party_get_entity_data_set($entity_type, $entity);
$data_set_controller = party_get_crm_controller(party_load($party_id), $data_set_name);
// Load the entities.
$data_set_controller
->getEntities();
//$attached_entity->setAttachedEntity($eid);
// Add the attached entity actions to the build content.
// @todo: change these to contextual links?
// Links broken: http://drupal.org/node/1600816
$variables['content']['party_actions'] = array(
'#theme' => 'links',
'#links' => $data_set_controller
->getActions($party_id, $eid),
'#attributes' => array(
'class' => array(
'links inline crm-set-action-links',
),
),
'#weight' => 100,
);
// @todo This would be better off as a new feature in Entity API
$variables['theme_hook_suggestions'][] = 'entity__all__party';
// @todo Hmmmm how do we let hook_theme() know about this?
$variables['theme_hook_suggestions'][] = 'entity__' . $entity_type . '__all__party';
}
}
/**
* Load a party entity from the database.
*
* @param $pid
* The party ID.
* @param $reset
* Whether to reset the party_load_multiple cache.
*
* @return
* A party object.
*/
function party_load($pid = NULL, $reset = FALSE) {
$pids = !empty($pid) ? array(
$pid,
) : array();
$party = party_load_multiple($pids, $reset);
return $party ? reset($party) : FALSE;
}
/**
* Load party entities from the database.
*
* @param $pids
* An array of party IDs.
* @param $conditions
* (deprecated) An associative array of conditions on the {party}
* table, where the keys are the database fields and the values are the
* values those fields must have. Instead, it is preferable to use
* EntityFieldQuery to retrieve a list of entity IDs loadable by
* this function.
* @param $reset
* Whether to reset the cache.
*
* @return
* An array of party objects indexed by nid.
*/
function party_load_multiple($pids = array(), $conditions = array(), $reset = FALSE) {
return entity_load('party', $pids, $conditions, $reset);
}
/**
* Delete multiple parties.
*
* @param $pids
* An array of party IDs.
*
* @return
* The return value from entity_delete_multiple().
*/
function party_delete_multiple($pids = array()) {
return entity_delete_multiple('party', $pids);
}
/**
* Delete a party.
*
* @param $party
* A party object.
*/
function party_delete(Party $party) {
$party
->delete();
}
/**
* Save a party.
*
* @param $party
* A party object.
*/
function party_save(&$party) {
return entity_get_controller('party')
->save($party);
}
/**
* Create a party object ready for saving to the database.
*
* @param $info
* An array carrying all the important information.
*
* @return
* A party object that can be passed to party_save(), or FALSE if the array
* was not suitable for creating a party.
*/
function party_create($info = array()) {
return entity_create('party', $info);
}
/**
* Implements hook_party_operations.
*/
function party_party_operations() {
$operations = array(
'merge' => array(
'label' => t('Merge parties'),
'callback' => 'party_party_operations_merge',
),
);
return $operations;
}
/**
* Merge multiple parties.
*
* @todo: move this to an inc file; add file inclusion to hook_party_operations().
*/
function party_party_operations_merge($parties = array()) {
if (count($parties) < 2) {
drupal_set_message(t("You muset select two or more parties to merge"));
return FALSE;
}
// the first party out of the array.
$first = array_shift($parties);
foreach ($parties as $party) {
party_merge($first, $party);
}
// @todo: write me!
}
// -----------------------------------------------------------------------
// Views hook implementations.
/**
* Implements hook_views_api().
*/
function party_views_api() {
return array(
'api' => '3.0-alpha1',
'path' => drupal_get_path('module', 'party') . '/includes/views',
);
}
// -----------------------------------------------------------------------
// CTools hook implementations.
/**
* Implements hook_ctools_plugin_type().
*
* Declare the plugin types we invent.
*/
function party_ctools_plugin_type() {
// Party name label plugins provide ways to generate a party name label
// from a party.
$plugins['party_name_label'] = array();
return $plugins;
}
/**
* Implements hook_ctools_plugin_directory().
*/
function party_ctools_plugin_directory($owner, $plugin_type) {
if ($owner == 'party' || $owner == 'page_manager' && $plugin_type == 'tasks' || $owner == 'ctools' && $plugin_type == 'relationships' || $owner == 'ctools' && $plugin_type == 'content_types') {
return "plugins/{$plugin_type}";
}
}
// --------------------------------------------------------------------------
// Party Attached Entity Form API
/**
* Get the form callback for attached entities.
*
* @param $data_set_name
* The name of a data set.
*/
function party_attached_entity_form_callback($data_set_name) {
$data_set_info = party_get_data_set_info($data_set_name);
return $data_set_info['form callback'];
}
/**
* Attach attached entity forms to a form.
*
* This takes all attached entities in the $form_state['#attached_entity'] array, runs
* their form callback and puts it in $form[$attached_entity->hash()]
*
* @param $standalone
* Whether this is being used as a form to edit just the one attached entity.
* If true, the fieldset is not shown around the entity form.
*/
function party_data_set_attach_form(&$form, &$form_state, $data_set, $deltas = FALSE, $create = TRUE) {
// Get the form callback.
$callback = party_attached_entity_form_callback($data_set
->getDataInfo('name'));
// Create an array of the $deltas we are working with:
// If no deltas are specified assume we're using all the deltas.
if (empty($deltas) && count($data_set
->getEntityIds()) > 0) {
$deltas = array_keys($data_set
->getEntityIds());
}
elseif (empty($deltas)) {
$deltas = array(
0,
);
}
foreach ($deltas as $delta) {
$entity = $data_set
->getEntity($delta, $create);
// It is possible $entity is false as if $create was false and $delta was
// unset there would be no entity.
if (!$entity) {
continue;
}
$form_key = $data_set
->getDataInfo('name') . ':' . $delta;
$form[$form_key] = array(
'#party' => $data_set
->getParty(),
'#data_set_name' => $data_set
->getDataInfo('name'),
'#data_set' => $data_set,
'#delta' => $delta,
'#entity' => $entity,
'#parents' => array(
$form_key,
),
'#tree' => TRUE,
'#type' => 'fieldset',
'#title' => check_plain(entity_label($data_set
->getDataInfo('entity type'), $entity)),
);
$callback($form[$form_key], $form_state, $data_set, $delta, $data_set
->getParty());
}
// Save the data set in the array.
$form['#data_set_controllers'][$data_set
->getDataInfo('name')] = $data_set;
$form['#submit'][] = 'party_data_set_attach_form_submit';
$form['#validate'][] = 'party_data_set_attach_form_validate';
}
/**
* Validate attached entity forms.
*/
function party_data_set_attach_form_validate(&$form, &$form_state) {
return TRUE;
}
/**
* Submit attached entity forms
*/
function party_data_set_attach_form_submit(&$form, &$form_state) {
// Collect which controllers we need to save.
$controllers = array();
foreach (element_children($form) as $form_key) {
$element =& $form[$form_key];
// Only act if we are confident this is an attached entity form element.
if (empty($element['#data_set_name']) || !party_get_data_set_info($element['#data_set_name'])) {
continue;
}
// Get the form callback.
$callback = party_attached_entity_form_callback($element['#data_set_name']) . '_submit';
// Execute the form callback.
$return = $callback($element, $form_state, $element['#data_set'], $element['#delta'], $element['#data_set']
->getParty());
$controllers[$element['#data_set_name']] = $element['#data_set'];
}
foreach ($controllers as $controller) {
$controller
->save();
}
}
/**
* The default data set form callback.
* This returns a $form array for the entity in $attached_entity
*
* @param $form
* The form we're attaching to. This may be the whole form or a sub-section
* of the form with the #parents key set.
* @param $form_state
* The form state
* @param $attached_entity
* The attached entity this form is for
* @param $party
* The party the $attached entity is attached to
*/
function party_default_attached_entity_form(&$form, &$form_state, $data_set, $delta, $party) {
field_attach_form($data_set
->getDataInfo('entity type'), $data_set
->getEntity($delta), $form, $form_state);
}
/**
* The default attached entity form validate callback.
*
* @param $form
* The whole form so far
* @param $form_state
* The form state
* @param $attached_entity
* The attached entity this form is for
* @param $party
* The party the $attached entity is attached to
*/
function party_default_attached_entity_form_validate($form, &$form_state, &$attached_entity, $party) {
// Validate fields.
$pseudo_entity = (object) $form_state['values'][$attached_entity
->hash()];
$psuedo_entity->type = $attached_entity
->getEntityBundle();
field_attach_form_validate($attached_entity
->getEntityType(), $pseudo_entity, $form[$attached_entity
->hash()], $form_state);
}
/**
* The default attached entity form submit callback.
*
* @param $form
* The whole form so far
* @param $form_state
* The form state
* @param $attached_entity
* The attached entity this form is for
* @param $party
* The party the $attached entity is attached to
*/
function party_default_attached_entity_form_submit($element, &$form_state, $data_set, $delta, $party) {
// Submit fields.
$data_set_info = party_get_data_set_info($data_set
->getDataInfo('name'));
field_attach_submit($data_set
->getDataInfo('entity type'), $data_set
->getEntity($delta), $element, $form_state);
entity_save($data_set
->getDataInfo('entity type'), $data_set
->getEntity($delta));
}
// --------------------------------------------------------------------------------------------------------------
// Party Actions & Processes
/**
* Merge two parties.
*
* @TODO: this is not at all functional!
* @see http://drupal.org/node/1669708.
*
* When running this function, the first party gets all of the second party's attached entities and the second party
* becomes a 'ghost' party that points to the first.
*
* @param $first the first party.
* @param $second the second party
*/
function party_merge($first, $second) {
// @todo: Clever logic to work out which data sets to delete and which to keep
// @todo: Transfer hats.
// @todo: Work out what to do with party fields.
// If the field is empty in $first and full in $second copy the value in
// If the field has unlimited cardinality or there is space for the values in $first
// then copy the values in.
// Make the other party a ghost party
$second->merged = 1;
$second->merged_party = $first->pid;
$second
->save();
}
// --------------------------------------------------------------------------------------------
// React to entity changes
/**
* Implements hook_entity_update($entity, $type);
*
* Trigger rules and update party label if an attached entity has been saved.
*/
function party_entity_update($entity, $type) {
if ($type == "party" && module_exists('rules')) {
rules_invoke_event('party_update', $entity);
}
// Get necessary entity info.
$wrapper = entity_metadata_wrapper($type, $entity);
// Get data sets.
$data_sets = party_get_data_set_info();
// Is this entity party of a data set?
$data_set_name = FALSE;
foreach ($data_sets as $name => $def) {
if ($def['entity type'] == $type && $def['entity bundle'] == $wrapper
->getBundle()) {
$data_set_name = $name;
break;
}
}
// If it's not part of a data set do nothing else
if (!$data_set_name) {
return;
}
// Find the party or parties this entity is attached to.
$party_ids = db_select('party_attached_entity', 'pae')
->fields('pae', array(
'pid',
))
->condition('data_set', $data_set_name)
->condition('eid', $wrapper
->getIdentifier())
->execute()
->fetchCol();
// Update the label
foreach ($party_ids as $pid) {
$controller = entity_get_controller('party');
$party = party_load($pid);
$controller
->setLabel($party);
$controller
->setPrimaryFields($party);
}
}
/**
* Implements hook_party_delete().
*/
function party_party_delete($party) {
foreach (party_get_data_set_info() as $data_set) {
$controller = party_get_crm_controller($party, $data_set['set_name']);
$controller
->hook_party_delete();
}
}
/**
* Implements hook_entity_property_info_alter().
*
* Register our attached entities as entity properties so that other modules
* can build items from it, e.g. Search API.
*/
function party_entity_property_info_alter(&$property_info) {
$properties =& $property_info['party']['properties'];
foreach (party_get_data_set_info() as $data_set_name => $set_info) {
$properties[$data_set_name] = array(
'label' => t('@label (Attached Entities)', array(
'@label' => $set_info['label'],
)),
'description' => t('The attached entities that are party of the @label data set.', array(
'@label' => $set_info['label'],
)),
'type' => $set_info['entity type'],
'bundle' => $set_info['entity bundle'],
'computed' => TRUE,
'getter callback' => 'party_property_dataset_get',
);
}
}
/**
* Callback for getting attached entity property values.
*
* @see entity_metadata_field_property_get().
*/
function party_property_dataset_get($party, array $options, $data_set_name, $entity_type, $info) {
$controller = party_get_crm_controller($party, $data_set_name);
$entities = $controller
->getEntityIds();
// @TODO: Fix this to handle multiple entities when that's available.
return $entities ? reset($entities) : NULL;
}
/**
* Returns a new SelectQuery extended by PartyQuery for the active database.
*
* @param $options
* An array of options to control how the query operates.
*
* @return SelectQuery
* A new SelectQuery object for this connection.
*
* @see db_select()
*/
function party_query($options = array()) {
return db_select('party', 'party', $options)
->extend('PartyQuery');
}
/**
* Find all columns of particular types on parties and their data sets.
*
* @param array|string $types
* Either a single or an array of possible schema types.
* @param bool $reset
* Whether to rebuild the information.
*
* @return array
* Nested arrays of possible columns suitable for #options. The top level key
* is the data set label and the child arrays are of the format:
* - keys: data_set_name:field_name:column where field_name is empty for
* properties of an entity.
* - values: depending on whether a property or field
* - property_label (column)
* - field_label (field_name:column)
*
* @see http://api.drupal.org/api/drupal/includes!database!schema.inc/group/schemaapi/7
*/
function party_find_fields_of_types($types, $reset = FALSE) {
// Get hold of our cached data.
$types = drupal_map_assoc((array) $types);
$hash_key = md5(serialize($types));
$cache = cache_get('party:fields_of_types');
// Check whether we need to build the information.
if ($reset || empty($cache->data[$hash_key])) {
// Make sure we have an empty array to add to.
$cache->data[$hash_key] = array();
$options =& $cache->data[$hash_key];
// Iterate over our data sets finding all the fields that are relevant.
foreach (party_get_data_set_info() as $data_set_name => $set_info) {
// Get our set key which is the label for the option group.
$set_key = format_string('@label (@name)', array(
'@label' => $set_info['label'],
'@name' => $data_set_name,
));
$options[$set_key] = array();
// Add all of the properties of this entity.
$entity_info = entity_get_info($set_info['entity type']);
$schema = drupal_get_schema($entity_info['base table']);
$property_info = entity_get_all_property_info($set_info['entity type']);
foreach ($schema['fields'] as $column => $definition) {
// Check whether this matches our allowed types.
if (in_array($definition['type'], $types)) {
// Build our key - data_set_name:field_name:column.
$property_key = $set_info['set_name'] . '::' . $column;
$options[$set_key][$property_key] = format_string('@label (@column)', array(
'@label' => isset($property_info[$column]['label']) ? $property_info[$column]['label'] : $column,
'@column' => $column,
));
}
}
// Get hold of our fields and iterate over them adding them to our options.
$fields = field_info_instances($set_info['entity type'], $set_info['entity bundle']);
foreach ($fields as $field) {
// Get hold of field info so we can check out the columns.
$field_info = field_info_field($field['field_name']);
foreach ($field_info['columns'] as $column => $definition) {
// Check whether this matches our allowed types.
if (in_array($definition['type'], $types)) {
// Build our key - data_set_name:field_name:column.
$field_key = $set_info['set_name'] . ':' . $field['field_name'] . ':' . $column;
$options[$set_key][$field_key] = format_string('@label (@name:@column)', array(
'@label' => $field['label'],
'@name' => $field['field_name'],
'@column' => $column,
));
}
}
}
}
}
// Set our cache and return.
cache_set('party:fields_of_types', $cache->data);
return $cache->data[$hash_key];
}
/**
* Implements hook_forms().
*/
function party_forms($form_id, $args) {
$forms = array();
if (substr($form_id, 0, 36) == 'party_attached_entity_edit_form_form') {
$forms[$form_id] = array(
'callback' => 'party_attached_entity_edit_form_form',
);
}
return $forms;
}
/**
* Implements hook_search_api_alter_callback_info().
*/
function party_search_api_alter_callback_info() {
$callbacks['party_alter_status_filter'] = array(
'name' => t('Status filter'),
'description' => t('Exclude items from indexing based on their status and merging.'),
'class' => 'PartyAlterStatusFilter',
// Filters should be executed first.
'weight' => -10,
);
return $callbacks;
}
Functions
Name | Description |
---|---|
party_access | Determines whether operations are allowed on a Party and attached entities. |
party_admin_paths | Implements hook_admin_paths(). |
party_attached_entity_form_callback | Get the form callback for attached entities. |
party_attach_entity | Attach an entity to a party according to a given data set. |
party_create | Create a party object ready for saving to the database. |
party_ctools_plugin_directory | Implements hook_ctools_plugin_directory(). |
party_ctools_plugin_type | Implements hook_ctools_plugin_type(). |
party_data_set_attach_form | Attach attached entity forms to a form. |
party_data_set_attach_form_submit | Submit attached entity forms |
party_data_set_attach_form_validate | Validate attached entity forms. |
party_data_set_form | Get the form for a data set (more to the point get a set of fields for the data set might need to work on this). This function checks the edit party attached data set permission. |
party_data_set_load | Menu loader for data sets. First check against pieces, and if nothings found check against the $data_set_names themselves. |
party_default_attached_entity_form | The default data set form callback. This returns a $form array for the entity in $attached_entity |
party_default_attached_entity_form_submit | The default attached entity form submit callback. |
party_default_attached_entity_form_validate | The default attached entity form validate callback. |
party_delete | Delete a party. |
party_delete_multiple | Delete multiple parties. |
party_detach_entity | Detach an entity from a party according to a given data set. |
party_entity_access | Wrap around party_access() for the entity api 'access callback'. |
party_entity_info | Implements hook_entity_info(). |
party_entity_info_alter | Implements hook_entity_info_alter(). |
party_entity_property_info_alter | Implements hook_entity_property_info_alter(). |
party_entity_update | Implements hook_entity_update($entity, $type); |
party_find_fields_of_types | Find all columns of particular types on parties and their data sets. |
party_forms | Implements hook_forms(). |
party_get_attached_entities | Return all attached entities of a particular set. |
party_get_crm_controller | Get the attached entity controller for a party. |
party_get_data_set | Return a Data Set object containing all the attached entities in a given data set for a particular party. |
party_get_data_set_info | Get all data sets from hook_party_data_set_info(). |
party_get_entity_data_set | Get the data set definition associated with a given entity and bundle. |
party_get_party_data_sets | Get the data sets expected for a party. |
party_get_party_piece_info | Get all party piece definitions from hook_party_party_pieces(). |
party_help | Implements hook_help(). |
party_load | Load a party entity from the database. |
party_load_multiple | Load party entities from the database. |
party_menu | Implements hook_menu(). |
party_menu_local_tasks_alter | Implements hook_menu_local_tasks_alter(). |
party_merge | Merge two parties. |
party_page_title | Page title callback for party view page. |
party_party_access | Implements hook_party_access(). |
party_party_delete | Implements hook_party_delete(). |
party_party_operations | Implements hook_party_operations. |
party_party_operations_merge | Merge multiple parties. |
party_party_party_pieces | Implements hook_party_party_pieces(). |
party_permission | Implements hook_permission(). |
party_preprocess_entity | Implements hook_preprocess_HOOK(). |
party_property_dataset_get | Callback for getting attached entity property values. |
party_query | Returns a new SelectQuery extended by PartyQuery for the active database. |
party_save | Save a party. |
party_search_api_alter_callback_info | Implements hook_search_api_alter_callback_info(). |
party_theme | Implements hook_theme(). |
party_uri | URI callback for contacts. |
party_views_api | Implements hook_views_api(). |