You are here

domain_entity.module in Domain Access Entity 7

Same filename and directory in other branches
  1. 8 domain_entity.module

Defines field (e.g. domain_entity) for entities, and access query alter.

File

domain_entity.module
View source
<?php

/**
 * @file
 * Defines field (e.g. domain_entity) for entities,
 * and access query alter.
 */

/**
 * Domain entity Joker domain value, means "Send to all...".
 * @var domain_entity
 */
define('DOMAIN_ENTITY_SEND_TO_ALL', 0);

/**
 * Domain entity behavior widget type, add a hidden field on entity.
 * Entity is automatically assigned to the current domain. (invisible for user)
 * @var domain_entity
 */
define('DOMAIN_ENTITY_BEHAVIOR_AUTO', 'domain_entity_auto_hidden');

/**
 * Domain entity behavior widget type, add a field on entity creation form,
 * allowing user to choose entity affiliation on creation/update form.
 * @var domain_entity
 */
define('DOMAIN_ENTITY_BEHAVIOR_USER', 'domain_entity_user_multiple_choice');

/**
 * Implements hook_menu().
 */
function domain_entity_menu() {
  $items = array();

  // Register the batch actions as menu callbacks.
  $items['admin/structure/domain/entities'] = array(
    'title' => 'Entities',
    'access arguments' => array(
      'administer domains',
    ),
    'type' => MENU_LOCAL_TASK,
    'page arguments' => array(
      'domain_entity_ui',
    ),
    'page callback' => 'drupal_get_form',
    'file' => 'domain_entity.admin.inc',
    'description' => 'Enable or Disable domain on entities / Configure domain entities behavior.',
    'weight' => -5,
  );
  return $items;
}

/**
 * Implements hook_permission().
 *
 * Define domain entity permissions.
 */
function domain_entity_permission() {
  return array(
    'access entities affiliate on assigned domains' => array(
      'title' => t("access and filter entities affiliate on user's assigned domains"),
      'description' => t('Allow an editor of multiple domains to access entities on different domain.'),
      'restrict access' => TRUE,
    ),
    'set domain access status for all entities' => array(
      'title' => t('Set domain access status for all entities'),
      'description' => t('Allow editor to edit & set domain access for all entities type.'),
      'restrict access' => TRUE,
    ),
  );
}

/**
 * Return the list of the domain_entity allowed entity types.
 *
 * @return array
 *   List of entity types. This array is structured as follow:
 *   array(
 *     entity_type => array(
 *       bundle => array(
 *         widget_behaviour => array(
 *           default_value => default_value,
 *         ),
 *       ),
 *       other bundle => etc..
 *     ),
 *     other entity => etc..
 *   );
 *
 *   Example :
 *   array(
 *     'commerce_order' => array(
 *       'commerce_order' => array(
 *         DOMAIN_ENTITY_BEHAVIOR_USER => array(
 *           DOMAIN_ACTIVE => DOMAIN_ACTIVE
 *         ),
 *       ),
 *     ),
 *   );
 */
function domain_entity_allowed_entity_types() {
  $domain_entity_allowed_entity_types = variable_get('domain_entity_allowed_entity_types', array());
  drupal_alter('domain_entity_allowed_entity_types', $domain_entity_allowed_entity_types);
  return $domain_entity_allowed_entity_types;
}

/**
 * Return each base table of the allowed entity type.
 */
function domain_entity_allowed_entity_types_base_tables() {

  // First check the static cache for a domain_entity field instances array.
  $domain_entity_allowed_entity_types_base_tables =& drupal_static(__FUNCTION__);

  // If it did not exist, fetch the types now.
  if (!isset($domain_entity_allowed_entity_types_base_tables)) {
    $domain_entity_allowed_entity_types_base_tables = array();
    $domain_entity_allowed_entity_types = domain_entity_allowed_entity_types();
    foreach ($domain_entity_allowed_entity_types as $entity_type => $bundles) {
      $entity_info = entity_get_info($entity_type);
      $domain_entity_allowed_entity_types_base_tables[$entity_info['base table']] = array(
        'entity key' => $entity_info['entity keys']['id'],
        'entity type' => $entity_type,
      );
    }
  }
  return $domain_entity_allowed_entity_types_base_tables;
}

/**
 * Implements hook_query_alter().
 *
 * Alter the enabled entities select query,
 * add domain access conditions.
 */
function domain_entity_query_alter(&$query) {
  if (!variable_get('domain_entity_bypass_access_conditions', FALSE) && method_exists($query, 'getTables')) {
    $tables = $query
      ->getTables();
    $base_table_alias = key($tables);
    $base_table = $tables[$base_table_alias]['table'];

    // Have we to check access for this entity types.
    $domain_entity_base_tables = domain_entity_allowed_entity_types_base_tables();
    if (!in_array($base_table, array_keys($domain_entity_base_tables))) {
      return;
    }

    // This is an enabled domain entity,
    // prepare our custom access conditions.
    // Get the accessible domain id's by the current user, in the current path.
    $accessible_domain_ids = domain_entity_get_user_available_domains();

    // Show to all user the entities that are assigned to all domains,
    // add the joker domain entity value to the list of the domain id's.
    $accessible_domain_ids[] = DOMAIN_ENTITY_SEND_TO_ALL;

    // Get the entity_type and key for this base_table:
    $entity_type = $domain_entity_base_tables[$base_table]['entity type'];
    $entity_key = $domain_entity_base_tables[$base_table]['entity key'];

    // Get the field name for this entity:
    $field_instance = domain_entity_entity_field_instance($entity_type);
    $field_instance_name = $field_instance['name'];

    // Add our subquery condition:
    $domain_query = db_select('field_data_' . $field_instance_name, 'dom');
    $domain_query
      ->where('dom.entity_id = ' . $base_table_alias . '.' . $entity_key);
    $domain_query
      ->condition('dom.' . $field_instance_name . '_domain_id', $accessible_domain_ids, 'IN');
    $domain_query
      ->fields('dom', array(
      $field_instance_name . '_domain_id',
    ));
    $query
      ->exists($domain_query);
  }
}

/**
 * Return a list of domain id's, accessible by the current user.
 *
 * @param stdClass $user
 *   Drupal user account.
 *
 * @return array
 *   List of domain id's.
 */
function domain_entity_get_user_available_domains($account = NULL) {
  if (!is_object($account)) {
    global $user;
    $account = $user;
  }

  // Get the current user list of granted domain id:
  // the current domain id OR for middle-office editors:
  // the list of assigned domain(s) id.
  $current_domain = domain_get_domain();
  $accessible_domain_ids = array(
    $current_domain['domain_id'],
  );

  // Middle office editors with permission see in administration,
  // entity from her lists of assigned domains.
  if (path_is_admin(current_path()) && user_access('access entities affiliate on assigned domains', $account)) {
    $user_domain = domain_get_user_domains($account);
    $accessible_domain_ids = !empty($user_domain) ? $user_domain : $accessible_domain_ids;
  }
  return $accessible_domain_ids;
}

/**
 * Implements hook_entity_presave().
 */
function domain_entity_entity_presave($entity, $type) {

  // Check if it's an allowed entity types:
  $allowed_entity_types = domain_entity_allowed_entity_types();
  if (!in_array($type, array_keys($allowed_entity_types))) {
    return;
  }

  // Get domain_entity field type instances:
  if ($field_instance = domain_entity_entity_field_instance($type)) {
    $field_instance_name = $field_instance['name'];
  }
  else {
    return FALSE;
  }

  // Get current domain:
  $current_domain = domain_get_domain();
  $entity_info = entity_get_info($type);

  // Get default bundle value
  // e.g (all, current_domain, list(domain_id))
  $bundle_key = $entity_info['entity keys']['bundle'];
  if (isset($allowed_entity_types[$type][$entity->{$bundle_key}])) {
    $default_values = reset($allowed_entity_types[$type][$entity->{$bundle_key}]);
  }
  else {
    $default_values = array();
  }
  if (in_array(DOMAIN_ALL, $default_values)) {
    $values = array();
    $values[] = array(
      'domain_id' => DOMAIN_ENTITY_SEND_TO_ALL,
    );
  }
  elseif (in_array(DOMAIN_ACTIVE, $default_values)) {
    $values = array(
      0 => array(
        'domain_id' => $current_domain['domain_id'],
      ),
    );
  }
  else {
    $values = array();
    foreach ($default_values as $did) {
      $values[] = array(
        'domain_id' => $did,
      );
    }
  }

  // Ensure this entities have almost a default value.
  // Attach it to current domain if the entity is created,
  // by bypassing entity creation form,
  // do not let an unset domain entity saved,
  // (or the entity became inaccessible everywhere).
  if (!isset($entity->{$field_instance_name})) {

    // Populate field instance with the default bundle domain value,
    // if is not already set or unassigned.
    $entity->{$field_instance_name} = array(
      LANGUAGE_NONE => $values,
    );
  }
  else {

    // Populate field instance with the default bundle domain value,
    // if is not already set or unassigned.
    $value = $entity->{$field_instance_name};
    if (empty($value[LANGUAGE_NONE]) || !isset($value[LANGUAGE_NONE][0]['domain_id'])) {
      $entity->{$field_instance_name} = array(
        LANGUAGE_NONE => $values,
      );
    }
  }
  return $entity;
}

/**
 * Implements hook_views_api().
 */
function domain_entity_views_api() {
  list($module, $api) = func_get_args();
  if ($module == "views" && $api == "views_default") {
    return array(
      "version" => 3.0,
    );
  }
}

/**
 * Implements hook_views_data_alter().
 */
function domain_entity_views_data_alter(&$data) {
  if (module_exists('domain_views')) {
    $entity_base_tables = domain_entity_allowed_entity_types_base_tables();
    if (empty($entity_base_tables)) {
      return;
    }
    foreach ($entity_base_tables as $entity_base_table => $entity_infos) {
      $field_instance = domain_entity_entity_field_instance($entity_infos['entity type']);
      $help = t("This field contains the domain's of the !entity_type.", array(
        '!entity_type' => $entity_infos['entity type'],
      ));
      $title = t('Domain (domain entity)');

      // Domain id filtering.
      $data['field_data_' . $field_instance['name']][$field_instance['name'] . '_domain_id']['filter']['handler'] = 'domain_entity_views_handler_filter_domain_domain_id';
      $data['field_data_' . $field_instance['name']][$field_instance['name'] . '_domain_id']['title'] = $title;
      $data['field_data_' . $field_instance['name']][$field_instance['name'] . '_domain_id']['help'] .= $help;
      $data['field_revision_' . $field_instance['name']][$field_instance['name'] . '_domain_id']['filter']['handler'] = 'domain_entity_views_handler_filter_domain_domain_id';
      $data['field_revision_' . $field_instance['name']][$field_instance['name'] . '_domain_id']['title'] = $title;
    }
  }
}

/**
 * Get a keyed list of domain_entity field id and field name.
 * @return array
 *   Array of key(field_id) => field_instance_name.
 */
function domain_entity_field_instances() {

  // First check the static cache for a domain_entity field instances array.
  $domain_entity_field_instances =& drupal_static(__FUNCTION__);

  // If it did not exist, fetch the fields now.
  if (!isset($domain_entity_field_instances)) {
    $query = "SELECT fc.id AS id, fc.field_name AS field_name ";
    $query .= "FROM {field_config} fc WHERE ";
    $query .= "(fc.type = 'domain_entity') AND (fc.active = 1)";
    $domain_entity_field_instances = db_query($query)
      ->fetchAll(PDO::FETCH_KEY_PAIR);
  }
  return $domain_entity_field_instances;
}

/**
 * Get the domain_entity field name and his settings for an entity type.
 * @return String
 *   The entity type.
 */
function domain_entity_entity_field_instance($entity_type) {

  // First check the static cache for a domain_entity field instances array.
  $domain_entity_entity_field_instance =& drupal_static(__FUNCTION__);

  // If it did not exist, init the array.
  if (!isset($domain_entity_entity_field_instance)) {
    $domain_entity_entity_field_instance = array();
  }

  // Look for an instance of this type, if it's not in the static cache.
  if (!isset($domain_entity_entity_field_instance[$entity_type])) {
    $domain_entity_field_instances = domain_entity_field_instances();
    $query = "SELECT fci.field_name AS field_name, fci.data AS data FROM ";
    $query .= "{field_config_instance} fci WHERE ";
    $query .= "(fci.entity_type = :entity_type) AND ";
    $query .= "(fci.field_name IN (:field_instance))";
    $args = array(
      ':entity_type' => $entity_type,
      ':field_instance' => $domain_entity_field_instances,
    );
    $field_instance = db_query($query, $args)
      ->fetchAll();
    if (isset($field_instance[0])) {
      $domain_entity_entity_field_instance[$entity_type] = array(
        'name' => $field_instance[0]->field_name,
        'settings' => unserialize($field_instance[0]->data),
      );
    }
    else {
      return FALSE;
    }
  }
  return $domain_entity_entity_field_instance[$entity_type];
}

/**
 * Implements hook_entity_info_alter().
 *
 * Make sure entities used by domain_entity are fieldable.
 */
function domain_entity_entity_info_alter(&$entity_info) {
  $entities = domain_entity_allowed_entity_types();
  foreach ($entities as $entity_name => $entity_bundles) {
    $entity_info[$entity_name]['fieldable'] = TRUE;

    // Store the default access callback before we change it.
    if (isset($entity_info[$entity_name]['access callback'])) {
      $entity_info[$entity_name]['default access callback'] = $entity_info[$entity_name]['access callback'];
    }
    $entity_info[$entity_name]['access callback'] = 'domain_entity_entity_access_callback';
  }
}

/**
 * Entity access callback.
 * @see domain_entity_entity_info_alter(), hook_entity_info().
 */
function domain_entity_entity_access_callback($op, $entity, $account, $entity_type) {
  $allowed_entity_types = domain_entity_allowed_entity_types();
  if (in_array($entity_type, array_keys($allowed_entity_types))) {
    if (!variable_get('domain_entity_bypass_access_conditions', FALSE)) {
      if (is_object($entity) && !in_array($op, array(
        'create',
        'add',
      ))) {

        // Get accessible domains for the given user.
        $accessible_domain_ids = domain_entity_get_user_available_domains($account);
        $accessible_domain_ids[] = DOMAIN_ENTITY_SEND_TO_ALL;

        // Get the assigned domains for the current entity.
        $field_name = domain_entity_get_entity_field_name($entity_type);
        $items = field_get_items($entity_type, $entity, $field_name);
        $access = FALSE;
        foreach ($items as $item) {
          if (in_array($item['domain_id'], $accessible_domain_ids)) {
            $access = TRUE;
            break;
          }
        }

        // We may restrict access, but will never widen it.
        if (!$access) {
          return FALSE;
        }
      }
    }
  }

  // Fallback to default behavior.
  $info = entity_get_info($entity_type);
  if (isset($info['default access callback'])) {
    $default_callback = $info['default access callback'];
    return $default_callback($op, $entity, $account, $entity_type);
  }
  return TRUE;
}

/**
 * Implements hook_field_info().
 */
function domain_entity_field_info() {
  return array(
    'domain_entity' => array(
      'label' => t('Domain'),
      'description' => t("This field stores the domain ID's."),
      'settings' => array(),
      'instance_settings' => array(),
      'default_widget' => DOMAIN_ENTITY_BEHAVIOR_AUTO,
      'default_formatter' => 'hidden',
      'property_type' => 'domain_entity',
      'property_callbacks' => array(
        'domain_entity_property_info_callback',
      ),
    ),
  );
}

/**
 * Implements hook_field_formatter_info().
 */
function domain_entity_field_formatter_info() {
  return array(
    'domain_entity_sitename' => array(
      'label' => t('Name'),
      'field types' => array(
        'domain_entity',
      ),
    ),
  );
}

/**
 * Implements hook_field_formatter_view().
 */
function domain_entity_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
  $element = array();
  $settings = $display['settings'];
  switch ($display['type']) {
    case 'domain_entity_sitename':
      foreach ($items as $delta => $item) {
        $domain = domain_load($item['domain_id']);
        if ($domain) {
          $element[$delta] = array(
            '#markup' => $domain['sitename'],
          );
        }
        else {
          $element[$delta] = array(
            '#markup' => t('Invalid domain'),
          );
        }
      }
      break;
  }
  return $element;
}

/**
 * Implements of hook_field_is_empty().
 */
function domain_entity_field_is_empty($item, $field) {
  if ($field['type'] == 'domain_entity') {
    return !isset($item['domain_id']) || $item['domain_id'] === NULL;
  }
}

/**
 * Implements hook_field_widget_info().
 */
function domain_entity_field_widget_info() {
  return array(
    DOMAIN_ENTITY_BEHAVIOR_AUTO => array(
      'label' => t('Affiliate automatically created entity to a value (no widget on entity creation form, auto-assignation)'),
      'field types' => array(
        'domain_entity',
      ),
      'behaviors' => array(
        'multiple values' => FIELD_BEHAVIOR_CUSTOM,
        'default value' => FIELD_BEHAVIOR_NONE,
      ),
    ),
    // This widget allow multiple domain attachment.
    DOMAIN_ENTITY_BEHAVIOR_USER => array(
      'label' => t('User choose affiliate, with a default value (form widget on the entity creation form)'),
      'field types' => array(
        'domain_entity',
      ),
      'behaviors' => array(
        'multiple values' => FIELD_BEHAVIOR_CUSTOM,
        'default value' => FIELD_BEHAVIOR_NONE,
      ),
    ),
  );
}

/**
 * Implements hook_field_widget_error().
 */
function domain_entity_field_widget_error($element, $error, $form, &$form_state) {
  if ($error['error'] == 'domain_entity') {
    form_error($element['domain_id'], $error['message']);
  }
}

/**
 * Implements hook_field_widget_form().
 */
function domain_entity_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
  $widget = $instance['widget'];
  $current_domain = domain_get_domain();
  $form_state['domain_entity_field_name'] = $field['field_name'];
  $allowed_entity_types = domain_entity_allowed_entity_types();
  $site_domains = domain_domains();
  $checkboxes = array(
    DOMAIN_ENTITY_SEND_TO_ALL => t('Send to all affiliates'),
  );
  foreach ($site_domains as $site_domain) {
    $checkboxes[$site_domain['domain_id']] = $site_domain['sitename'];
  }

  // Set the domain default value if no value has been set :
  $default_values = array();
  if (!isset($items[0]) || empty($items[0]) || !isset($items[0]['domain_id'])) {

    // Get default bundle value,
    // e.g (all, current_domain, list(domain_id)).
    $default_bundle_values = reset($allowed_entity_types[$instance['entity_type']][$instance['bundle']]);
    if (in_array(DOMAIN_ALL, $default_bundle_values)) {
      $default_values[DOMAIN_ENTITY_SEND_TO_ALL] = DOMAIN_ENTITY_SEND_TO_ALL;
    }
    elseif (in_array(DOMAIN_ACTIVE, $default_bundle_values)) {
      $default_values[$current_domain['domain_id']] = $current_domain['domain_id'];
    }
    else {
      foreach ($default_bundle_values as $did) {
        $default_values[$did] = $did;
      }
    }
  }
  else {
    foreach ($items as $delta => $item) {
      $default_values[$item['domain_id']] = $item['domain_id'];
    }
  }

  // Add a checkboxes for domain id's:
  $element['domain_id'] = array(
    '#type' => 'checkboxes',
    '#options' => $checkboxes,
    '#title' => t('Domain'),
    '#default_value' => $default_values,
    '#required' => TRUE,
    '#element_validate' => array(
      'domain_entity_widget_multiple_values_form_validate',
    ),
    '#entity_type' => $instance['entity_type'],
  );
  if (!user_access('set domain access status for all entities')) {

    // Send to all affiliates should not be accessible.
    $element['domain_id'][DOMAIN_ENTITY_SEND_TO_ALL]['#disabled'] = TRUE;

    // Disable the domain checkbox that the user cannot edit.
    global $user;
    $user_granted_domain_ids = domain_get_user_domains($user);
    $is_editable = FALSE;
    foreach ($site_domains as $domain) {

      // We let the super user override this restriction.
      if (!in_array($domain['domain_id'], $user_granted_domain_ids) && $domain['domain_id'] != 0 && $user->uid != 1) {
        $element['domain_id'][$domain['domain_id']]['#disabled'] = TRUE;
      }
      else {
        $is_editable = TRUE;
      }
    }
    if (!$is_editable) {
      $element['domain_id']['#access'] = FALSE;
    }
  }
  if ($widget['type'] == DOMAIN_ENTITY_BEHAVIOR_AUTO) {
    $element['domain_id']['#access'] = FALSE;
  }
  return $element;
}

/**
 * Widget form validate.
 *
 * Handle checkboxes to save it as multiple field values (delta).
 */
function domain_entity_widget_multiple_values_form_validate($element, &$form_state, $form) {
  global $user;
  $user_granted_domain_ids = domain_get_user_domains($user);
  $entity_type = isset($element['#entity_type']) ? $element['#entity_type'] : FALSE;
  if (!in_array($entity_type, array_keys(domain_entity_allowed_entity_types()))) {
    return;
  }
  $default_values = $element['#default_value'];
  $values = $element['#value'];
  $active_domain = array();
  $domains = domain_domains();
  foreach ($domains as $domain) {
    if (!in_array($domain['domain_id'], $user_granted_domain_ids) && in_array($domain['domain_id'], $default_values)) {
      $active_domain[] = array(
        'domain_id' => $domain['domain_id'],
      );
    }
    elseif (in_array($domain['domain_id'], $user_granted_domain_ids) && in_array($domain['domain_id'], $values)) {
      $active_domain[] = array(
        'domain_id' => $domain['domain_id'],
      );
    }
  }
  $items = array();
  foreach ($active_domain as $domain) {
    $items[] = $domain;
  }

  // Emulate multivalue field. Unset last parent to prevent errors.
  array_pop($element['#parents']);

  // Put the value of DOMAIN_ENTITY_SEND_TO_ALL (e.g. 0) to the end of the array.
  $items = array_reverse($items);
  drupal_alter('domain_entity_widget_multiple_values_form_validate', $items, $form_state, $form, $element);

  // Set the domain values.
  form_set_value($element, $items, $form_state);
}

/**
 * Implements hook_form_FORM_ID_alter().
 */
function domain_entity_form_field_ui_field_edit_form_alter(&$form, &$form_state, $form_id) {
  if ($form['#field']['type'] == 'domain_entity') {
    $form['instance']['required']['#default_value'] = TRUE;
    $form['instance']['required']['#disabled'] = TRUE;
    $form['field']['cardinality']['#value'] = FIELD_CARDINALITY_UNLIMITED;
    $form['field']['cardinality']['#disabled'] = TRUE;
    $form['field']['cardinality']['#description'] = t('This field widget allow only unlimited values (the number of active domain).');
  }
}

/**
 * Callback to alter the property info of domain fields.
 *
 * @see domain_entity_field_info()
 */
function domain_entity_property_info_callback(&$info, $entity_type, $field, $instance, $field_type) {
  $name = $field['field_name'];
  $property =& $info[$entity_type]['bundles'][$instance['bundle']]['properties'][$name];
  $property['type'] = $field['cardinality'] != 1 ? 'list<domain_entity>' : 'domain_entity';
  $property['getter callback'] = 'entity_metadata_field_verbatim_get';
  $property['setter callback'] = 'entity_metadata_field_verbatim_set';
  $property['property info'] = domain_entity_field_data_property_info($name);
  unset($property['query callback']);
  unset($property['auto creation']);
}

/**
 * Defines info for the properties of the domain_entity field data structure.
 */
function domain_entity_field_data_property_info($name = NULL) {
  return array(
    'domain_id' => array(
      'label' => t('Domain ID'),
      'description' => !empty($name) ? t('Domain ID value of field %name', array(
        '%name' => $name,
      )) : '',
      'type' => 'int',
      'getter callback' => 'entity_property_verbatim_get',
      'setter callback' => 'entity_property_verbatim_set',
    ),
  );
}

/**
 * Implements hook_commerce_product_reference_default_delta_alter().
 */
function domain_entity_commerce_product_reference_default_delta_alter(&$delta, $products) {
  $allowed_entity_types = domain_entity_allowed_entity_types();
  if (!in_array('commerce_product', array_keys($allowed_entity_types))) {
    return;
  }
  foreach ($products as $new_delta => $product) {
    if (!empty($product)) {
      $delta = $new_delta;
      return;
    }
  }
}

/**
 * Create a field instance.
 */
function domain_entity_create_field_instance($field_name, $field_type, $required, $entity_type, $bundle, $label, $widget, $description = NULL, $weight = 0, $display = array()) {

  // Look for or add the specified field to the requested entity bundle.
  $field = field_info_field($field_name);
  $instance = field_info_instance($entity_type, $field_name, $bundle);
  if (empty($field)) {
    $field = array(
      'field_name' => $field_name,
      'type' => $field_type,
      'cardinality' => FIELD_CARDINALITY_UNLIMITED,
      'entity_types' => array(
        $entity_type,
      ),
      'translatable' => FALSE,
      'locked' => FALSE,
    );
    $field = field_create_field($field);
  }
  if (empty($instance)) {
    $instance = array(
      'field_name' => $field_name,
      'entity_type' => $entity_type,
      'bundle' => $bundle,
      'label' => $label,
      'required' => $required,
      'settings' => array(),
      'display' => array(),
      'description' => $description,
      'default_value' => array(
        array(
          'value' => 0,
        ),
      ),
      'widget' => array(
        'type' => $widget,
      ),
      'display' => array(),
    );
    $entity_info = entity_get_info($entity_type);

    // Add default view mode and teaser so display is set.
    $entity_info['view modes'] += array(
      'default' => array(),
      'node_teaser' => array(),
    );
    foreach ($entity_info['view modes'] as $view_mode => $data) {
      $instance['display'][$view_mode] = $display + array(
        'label' => 'hidden',
        'type' => 'hidden',
        'settings' => array(),
        'weight' => $weight,
      );
    }
    field_create_instance($instance);
  }
}

/**
 * Helper function to active domain field on bundles of entity types.
 *
 * @param array $entity_types
 *   List of Entity types, that list her bundles.
 */
function domain_entity_types_enable_domain_field($entity_types) {

  // Common settings.
  $field_type = 'domain_entity';
  $label = t('Domain');
  $required = TRUE;
  $entities_to_update = array();

  // Reset the entity info, before enabling domain access on entity.
  // Some entities are not fieldable, but this module force it to.
  entity_info_cache_clear();

  // Create fields instance.
  foreach ($entity_types as $entity_type => $bundles) {
    $field_name = domain_entity_get_entity_field_name($entity_type);
    $entity_info = entity_get_info($entity_type);
    foreach ($bundles as $bundle => $widget) {

      // Look for or add the specified field to the requested entity bundle.
      $instance = field_info_instance($entity_type, $field_name, $bundle);
      if (empty($instance)) {
        domain_entity_create_field_instance($field_name, $field_type, $required, $entity_type, $bundle, $label, key($widget));
        drupal_set_message(t("Domain Access behaviour '@widget' has been enabled on the bundle @type of @entity entity type", array(
          '@widget' => key($widget),
          '@type' => $bundle,
          '@entity' => $entity_type,
        )));
      }
    }

    // Query to look at unafilliated entities.
    // EntityFieldQuery excludes entities with empty field values from results
    // when using fieldCondition(), so we look for the difference between
    // results for all entities and those that are already affiliated to
    // domains.
    $entity_key = $entity_info['entity keys']['id'];

    // Query for all entities in the type.
    $query = new EntityFieldQuery();
    $query
      ->entityCondition('entity_type', $entity_type);
    $result = $query
      ->execute();
    if (!empty($result[$entity_type])) {
      $all_entities = $result[$entity_type];

      // Query for entities affiliated to domains.
      $query = new EntityFieldQuery();
      $query
        ->entityCondition('entity_type', $entity_type);
      $query
        ->fieldCondition($field_name);
      $result = $query
        ->execute();
      $affiliated_entities = empty($result[$entity_type]) ? array() : $result[$entity_type];

      // Find unafilliated entities by taking the differernce.
      $unaffiliated_entities = array_diff_key($all_entities, $affiliated_entities);
      if (!empty($unaffiliated_entities)) {
        $entities_to_update[$entity_type] = array();
        foreach ($unaffiliated_entities as $key => $value) {
          $id = $value->{$entity_key};
          $entities_to_update[$entity_type][] = $id;
        }
      }
    }
  }

  // Clear cache as we are going to update existing entities field values.
  field_cache_clear();

  // Create a batch operation to update entities that are not affiliated to a domain.
  $operations = array();
  foreach ($entities_to_update as $entity_type => $entities) {
    foreach ($entities as $entity_id) {
      $operations[] = array(
        '_domain_entity_update_entity_defaut_value',
        array(
          $entity_type,
          $entity_id,
        ),
      );
    }
  }
  $batch = array(
    'operations' => $operations,
    'title' => t('Update existing entities domain affiliation default values'),
    'error_message' => st('The domain access update has encountered an error.'),
    'finished' => '_domain_entity_update_entity_defaut_value_finished',
  );
  if (count($operations)) {

    // Bypass access restriction to allow the current user,
    // to access the entity that are not already assigned.
    $domain_entity_allowed_entity_types_backup = variable_get('domain_entity_allowed_entity_types', array());
    variable_set('domain_entity_bypass_access_conditions_backup', variable_get('domain_entity_bypass_access_conditions', FALSE));
    variable_set('domain_entity_bypass_access_conditions', TRUE);
    batch_set($batch);
  }
  else {
    drupal_set_message(t('0 entities updated.'));
  }
}

/**
 * Batch operation processing callback.
 */
function _domain_entity_update_entity_defaut_value($entity_type, $entity_id, &$context) {
  $entity = entity_load_single($entity_type, $entity_id);
  if ($entity) {

    // Just call entity_save(), the hook domain_entity_entity_presave()
    // take care of the field domain default assignation(s), if nothing is set.
    entity_save($entity_type, $entity);
    $context['results'][] = $entity_type . ' - Id : ' . $entity_id . ' updated.';
    $context['message'] = t('Updated: %entity_type - ID : %entity_id.', array(
      '%entity_type' => $entity_type,
      '%entity_id' => $entity_id,
    ));
  }
}

/**
 * Batch operation finished callback.
 */
function _domain_entity_update_entity_defaut_value_finished($finished, $results) {

  // Restore entity type domain access.
  variable_set('domain_entity_bypass_access_conditions', variable_get('domain_entity_bypass_access_conditions_backup', FALSE));
  variable_del('domain_entity_bypass_access_conditions_backup');
  drupal_set_message(t('%count entities updated.', array(
    '%count' => count($results),
  )));
}

/**
 * Return the name of the field for an entity type.
 *
 * @param String $entity_type
 *   The type of the entity that hold the field.
 */
function domain_entity_get_entity_field_name($entity_type) {
  $field_name = 'domain_' . $entity_type;
  if (strlen($field_name) > 21) {
    $field_name = substr('domain_' . md5($field_name), 0, -7);
  }
  return $field_name;
}

Functions

Namesort descending Description
domain_entity_allowed_entity_types Return the list of the domain_entity allowed entity types.
domain_entity_allowed_entity_types_base_tables Return each base table of the allowed entity type.
domain_entity_commerce_product_reference_default_delta_alter Implements hook_commerce_product_reference_default_delta_alter().
domain_entity_create_field_instance Create a field instance.
domain_entity_entity_access_callback Entity access callback.
domain_entity_entity_field_instance Get the domain_entity field name and his settings for an entity type.
domain_entity_entity_info_alter Implements hook_entity_info_alter().
domain_entity_entity_presave Implements hook_entity_presave().
domain_entity_field_data_property_info Defines info for the properties of the domain_entity field data structure.
domain_entity_field_formatter_info Implements hook_field_formatter_info().
domain_entity_field_formatter_view Implements hook_field_formatter_view().
domain_entity_field_info Implements hook_field_info().
domain_entity_field_instances Get a keyed list of domain_entity field id and field name.
domain_entity_field_is_empty Implements of hook_field_is_empty().
domain_entity_field_widget_error Implements hook_field_widget_error().
domain_entity_field_widget_form Implements hook_field_widget_form().
domain_entity_field_widget_info Implements hook_field_widget_info().
domain_entity_form_field_ui_field_edit_form_alter Implements hook_form_FORM_ID_alter().
domain_entity_get_entity_field_name Return the name of the field for an entity type.
domain_entity_get_user_available_domains Return a list of domain id's, accessible by the current user.
domain_entity_menu Implements hook_menu().
domain_entity_permission Implements hook_permission().
domain_entity_property_info_callback Callback to alter the property info of domain fields.
domain_entity_query_alter Implements hook_query_alter().
domain_entity_types_enable_domain_field Helper function to active domain field on bundles of entity types.
domain_entity_views_api Implements hook_views_api().
domain_entity_views_data_alter Implements hook_views_data_alter().
domain_entity_widget_multiple_values_form_validate Widget form validate.
_domain_entity_update_entity_defaut_value Batch operation processing callback.
_domain_entity_update_entity_defaut_value_finished Batch operation finished callback.

Constants

Namesort descending Description
DOMAIN_ENTITY_BEHAVIOR_AUTO Domain entity behavior widget type, add a hidden field on entity. Entity is automatically assigned to the current domain. (invisible for user)
DOMAIN_ENTITY_BEHAVIOR_USER Domain entity behavior widget type, add a field on entity creation form, allowing user to choose entity affiliation on creation/update form.
DOMAIN_ENTITY_SEND_TO_ALL Domain entity Joker domain value, means "Send to all...".