Skip to content
Snippets Groups Projects
og.module 98.9 KiB
Newer Older
Amitaibu's avatar
Amitaibu committed
<?php
Amitaibu's avatar
Amitaibu committed
/**
 * @file
 * Enable users to create and manage groups with roles and permissions.
 */

/**
 * Define active group content states.
 */
Amitaibu's avatar
Amitaibu committed
define('OG_STATE_ACTIVE', 1);
Amitaibu's avatar
Amitaibu committed

/**
 * Define pending group content states. The user is subscribed to the group but
 * isn't an active member yet.
 */
Amitaibu's avatar
Amitaibu committed
define('OG_STATE_PENDING', 2);
Amitaibu's avatar
Amitaibu committed

/**
 * Define blocked group content states. The user is rejected from the group.
 */
Amitaibu's avatar
Amitaibu committed
define('OG_STATE_BLOCKED', 3);
Amitaibu's avatar
Amitaibu committed

/**
 * Group audience field.
 */
define('OG_AUDIENCE_FIELD', 'og_group_ref');
 * Define the "other groups" (i.e. not "my groups") default field name.
define('OG_AUDIENCE_OTHER_GROUPS_FIELD', 'og_group_ref_other_groups');
define('OG_GROUP_FIELD', 'group_group');
 * Group default roles and permissions field.
Amitaibu's avatar
Amitaibu committed
define('OG_DEFAULT_ACCESS_FIELD', 'og_roles_permissions');
Amitaibu's avatar
Amitaibu committed
/**
 * The role name of group non-members.
 */
define('OG_ANONYMOUS_ROLE', 'non-member');
Amitaibu's avatar
Amitaibu committed

/**
 * The role name of group member.
 */
define('OG_AUTHENTICATED_ROLE', 'member');
Amitaibu's avatar
Amitaibu committed

/**
 * The role name of group administrator.
 */
Amitaibu's avatar
Amitaibu committed
define('OG_ADMINISTRATOR_ROLE', 'administrator member');
Amitaibu's avatar
Amitaibu committed

/**
 * The default group membership type that is the bundle of group membership.
 */
define('OG_MEMBERSHIP_TYPE_DEFAULT', 'og_membership_type_default');

/**
 * The name of the user's request field in the default group membership type.
 */
define('OG_MEMBERSHIP_REQUEST_FIELD', 'og_membership_request');

function og_help($path, $arg) {
Amitaibu's avatar
Amitaibu committed
  // Provide messages for og-migrate module.
  if ($path != 'admin/config/group/group-migrate'
      && $path != 'batch' && strpos($path, '#') === FALSE
Amitaibu's avatar
Amitaibu committed
      && user_access('access administration pages') && og_needs_migrate()) {

    if (module_exists('og_migrate')) {
      $message = t('Organic groups or one of its modules needs to <a href="@url">migrate data</a>. Organic groups may not work properly without it. After a successful execution you can disable it.', array('@url' => url('admin/config/group/group-migrate')));
Amitaibu's avatar
Amitaibu committed
    }
    else {
      $message = t('Organic groups or one of its modules needs you to enable Organic groups migrate module.');
Amitaibu's avatar
Amitaibu committed
    }
    drupal_set_message($message, 'error');
  }

  switch ($path) {
    case 'admin/help#og':
      $path = drupal_get_path('module', 'og');
      $output  = '<p>' . t("Read the <a href='@url'>README.txt</a> file in the Organic groups module directory.", array('@url' => "/$path/README.txt")) . '</p>';
      $output .= '<p>' . t("Information about Organic Groups can also be found on the module's<a href='@og'>documentation page</a>.", array('@og' => 'http://drupal.org/documentation/modules/og')) . '</p>';
      return $output;
  }
}

Amitai's avatar
Amitai committed
/**
 * Implements hook_entity_info().
 */
function og_entity_info() {
  $items['og_membership_type'] = array(
    'label' => t('OG membership type'),
    'controller class' => 'EntityAPIControllerExportable',
    'entity class' => 'OgMembershipType',
    'base table' => 'og_membership_type',
    'fieldable' => TRUE,
    'entity keys' => array(
      'id' => 'id',
      'label' => 'description',
      'name' => 'name',
    'exportable' => TRUE,
    'export' => array(
      'default hook' => 'default_og_membership_type',
    ),
    'bundle of' => 'og_membership',
    'module' => 'og',
    'metadata controller class' => 'EntityDefaultMetadataController',
    'views controller class' => 'EntityDefaultViewsController',
    'access callback' => 'og_membership_type_access',
  if (class_exists('OgMembershipTypeUIController')) {
    $items['og_membership_type'] += array(
      // Enable the entity API's admin UI.
      'admin ui' => array(
        // TODO: This path doesn't exist before OG-ui.
        'path' => 'admin/config/group/group-membership',
        'file' => 'includes/og.admin.inc',
        'controller class' => 'OgMembershipTypeUIController',
      ),
    );
  }

  $items['og_membership'] = array(
    'label' => t('OG membership'),
Amitaibu's avatar
Amitaibu committed
    'entity class' => 'OgMembership',
    'controller class' => 'EntityAPIController',
    'base table' => 'og_membership',
    'fieldable' => TRUE,
    'entity keys' => array(
Amitaibu's avatar
Amitaibu committed
      'id' => 'id',
      // The message has no label.
      'label' => FALSE,
    'label callback' => 'og_membership_label',
    'bundles' => array(),
    'bundle keys' => array(
      'bundle' => 'name',
    ),
    'module' => 'og',
    'metadata controller class' => 'OgMembershipMetadataController',
    'views controller class' => 'OgMembershipViewsController',
    'access callback' => 'og_membership_access',
  );
Amitai's avatar
Amitai committed

  // Add bundle info but bypass entity_load() as we cannot use it here.
  if (db_table_exists('og_membership_type')) {
    $memberships = db_select('og_membership_type', 'g')
      ->fields('g')
      ->execute()
      ->fetchAllAssoc('name');

    foreach ($memberships as $type_name => $type) {
      $items['og_membership']['bundles'][$type_name] = array(
        'label' => $type->name,
        'admin' => array(
          'path' => 'admin/config/group/group-membership/manage/%og_membership_type',
          'real path' => 'admin/config/group/group-membership/manage/' . $type->name,
          'bundle argument' => 5,
          'access arguments' => array('administer group'),
        ),
      );
    }
/**
 * Implements hook_entity_property_info().
 */
function og_entity_property_info() {
  $info = array();

  // Add OG membership metadata for every bundle that is a group content.
  foreach (og_get_all_group_content_bundle() as $entity_type => $bundles) {
    foreach ($bundles as $bundle => $bundle_value) {
      $info[$entity_type]['bundles'][$bundle]['properties']['og_membership'] = array(
        'label' => t("OG memberships"),
        'type' => 'list<og_membership>',
        'description' => t("A list of all OG memberships of the @name entity.", array('@name' => $entity_type)),
        'getter callback' => 'og_get_og_membership_properties',
      );

      // Add per-state properties.
      $general = $info[$entity_type]['bundles'][$bundle]['properties']['og_membership'];
      foreach (og_group_content_states() as $state => $state_label) {
        $params = array('@state' => $state_label, '@name' => $entity_type);
        $info[$entity_type]['bundles'][$bundle]['properties']['og_membership__' . $state] = $general;
        $info[$entity_type]['bundles'][$bundle]['properties']['og_membership__' . $state]['label'] = t('@state OG membership', $params);
        $info[$entity_type]['bundles'][$bundle]['properties']['og_membership__' . $state]['description'] = t("A list of all OG memberships of the @name entity with @state state.", $params);
      }

      // Add OG membership per field in a bundle.
      foreach (og_get_group_audience_fields($entity_type, $bundle) as $field_name => $label) {
        $params = array('@label' => $label);
        $field_info = field_info_field($field_name);
        $group_type = $field_info['settings']['target_type'];
        $info[$entity_type]['bundles'][$bundle]['properties'][$field_name . '__og_membership'] = array(
          'label' => t('OG membership from field @label', $params),
          'type' => 'list<og_membership>',
          // The bundle in this context means the OG membership type.
          'bundle' => $field_info['settings']['handler_settings']['membership_type'],
          'description' => t('A list of all OG memberships registered in field @label.', $params),
          'getter callback' => 'og_get_field_og_membership_properties',
        );


        // Add per-state properties.
        $general = $info[$entity_type]['bundles'][$bundle]['properties'][$field_name . '__og_membership'];
        foreach (og_group_content_states() as $state => $state_label) {
          $params = array(
            '@label' => $label,
            '@label' => $label,
            '@state' => $state_label,
          );
          $info[$entity_type]['bundles'][$bundle]['properties'][$field_name . '__og_membership__' . $state] = $general;
          $info[$entity_type]['bundles'][$bundle]['properties'][$field_name . '__og_membership__' . $state]['label'] = t('@state OG memberships from field @label', $params);
          $info[$entity_type]['bundles'][$bundle]['properties'][$field_name . '__og_membership__' . $state]['description'] = t('A list of all OG memberships with @state registered in field @label.', $params);
        }
      }
    }
  foreach (og_get_all_group_bundle() as $entity_type => $bundles) {
    foreach ($bundles as $bundle => $bundle_value) {
      $info[$entity_type]['bundles'][$bundle]['properties']['members'] = array(
          'label' => t("Group members"),
          'type' => 'list<user>',
          'description' => t("A list group members of the @name entity.", array('@name' => $entity_type)),
          'getter callback' => 'og_get_group_members_properties',
        );

        // Add per-state properties.
        $general = $info[$entity_type]['bundles'][$bundle]['properties']['members'];
        foreach (og_group_content_states() as $state => $state_label) {
          $params = array('@state' => $state_label, '@name' => $entity_type);
          $info[$entity_type]['bundles'][$bundle]['properties']['members__' . $state] = $general;
          $info[$entity_type]['bundles'][$bundle]['properties']['members__' . $state]['label'] = t('@state group members', $params);
          $info[$entity_type]['bundles'][$bundle]['properties']['members__' . $state]['description'] = t("A list of all users of the @name entity with @state state.", $params);
        }
    }
 * Property getter callback for group members.
 *
 * @see og_entity_property_info()
function og_get_group_members_properties($entity, array $options, $name, $type) {
  $args = explode('__', $name);
  $state = !empty($args[1]) ? $args[1] : FALSE;
  list($id) = entity_extract_ids($type, $entity);

  $cache = &drupal_static(__FUNCTION__, array());
  if (isset($cache[$type][$id][$state])) {
    // Return the cached result.
    return $cache[$type][$id][$state];
  }
  $cache[$type][$id][$state] = array();
  $query = new EntityFieldQuery();
  $query
    ->entityCondition('entity_type', 'og_membership')
    ->propertyCondition('group_type', $type, '=')
    ->propertyCondition('gid', $id, '=')
    ->propertyCondition('entity_type', 'user', '=');
  if ($state) {
    $query->propertyCondition('state', $state, '=');
  }
  $result = $query->execute();
  if (!empty($result['og_membership'])) {
    $og_memberships = og_membership_load_multiple(array_keys($result['og_membership']));
    foreach ($og_memberships as $og_membership) {
      $cache[$type][$id][$state][] = $og_membership->etid;

    }
  }
  return $cache[$type][$id][$state];
}

/**
 * Property getter callback for OG membership.
 *
 * @see og_entity_property_info()
 */
function og_get_og_membership_properties($entity, array $options, $name, $type) {
  // Get the state from name, if exists.
  if ($name == 'og_membership') {
    $state = array();
  }
  else {
    $args = explode('__', $name);
    $state = array($args[1]);
  }

  $ids = array();

  if ($gids = og_get_entity_groups($type, $entity, $state)) {
    $ids = array();
    foreach ($gids as $group_type => $values) {
      $ids = $ids + array_keys($values);
    }
  }

  return $ids;
}

/**
 * Property getter callback for OG membership per field.
 *
 * @see og_entity_property_info()
 */
function og_get_field_og_membership_properties($entity, array $options, $name, $type) {
  $args = explode('__', $name);
  // Field name might have double underscore as-well, so we need to make
  // sure we get it right.
  $last_char = substr($name, -1);
  $state = is_numeric($last_char) ? $last_char : FALSE;

  // The number of characters to ignore in the name (i.e. remove the
  // "__og_membership" or "__og_membership__0").
  $remove_char = $state ? -18 : -15;
  $field_name = substr($name, 0, $remove_char);

  $field_name = $args[0];
  $state = count($args) == 2 ? FALSE : $args[2];
  list($id) = entity_extract_ids($type, $entity);

  $identifier = $type . ':' . $id . ':' . $field_name . ':' . $state;
  $cache = &drupal_static(__FUNCTION__, array());
  if (isset($cache[$identifier])) {
    // Return the cached result.
    return $cache[$identifier];

  $query = new EntityFieldQuery();
  $query
    ->entityCondition('entity_type', 'og_membership')
    ->propertyCondition('entity_type', $type, '=')
    ->propertyCondition('etid', $id, '=')
    ->propertyCondition('field_name', $field_name, '=');

  if ($state) {
    $query->propertyCondition('state', $state, '=');
  }

  $result = $query->execute();
  $cache[$identifier] = !empty($result['og_membership']) ? array_keys($result['og_membership']) : array();
  return $cache[$identifier];
 * Getter callback to load the 'entity' or 'group' property from OG membership.
 *
 * We have to return the entity wrapped.
function og_entity_getter($object, array $options, $property_name) {
  switch ($property_name) {
    case 'entity':
      return entity_metadata_wrapper($object->entity_type, $object->etid);
    case 'group':
      return entity_metadata_wrapper($object->group_type, $object->gid);
  }
 * Entity property info setter callback to set the "entity" property for groups
 * and memberships.
 *
 * As the property is of type entity, the value will be passed as a wrapped
 * entity.
 */
function og_entity_setter($object, $property_name, $wrapper) {
  switch ($property_name) {
    case 'entity':
      $object->entity_type = $wrapper->type();
      $object->etid = $wrapper->getIdentifier();
      break;
    case 'group':
      $object->group_type = $wrapper->type();
      $object->gid = $wrapper->getIdentifier();
      break;
  }
 * Implements hook_default_og_membership_type().
 */
function og_default_og_membership_type() {
  $items = array();
  $items['og_membership_type_default'] = entity_import('og_membership_type', '{
    "name" : "og_membership_type_default",
    "description" : "Default",
    "rdf_mapping" : []
  }');
  return $items;
}

 * Implements hook_modules_enabled().
function og_modules_enabled($modules) {
  // Reset this cache first, since Drush can call this function multiple times
  // before all modules are available.
  drupal_static_reset('og_get_permissions');
  foreach ($modules as $module) {
    // Add default roles and permissions, if existing and not set yet.
    og_set_global_access_by_module($module);
function og_modules_uninstalled($modules) {
Amitaibu's avatar
Amitaibu committed
  // Delete module's permissions.
  og_permissions_delete_by_module($modules);
 * Implements hook_ctools_plugin_directory().
 */
function og_ctools_plugin_directory($module, $plugin) {
  if ($module == 'ctools' || $module == 'og_migrate') {
    return 'plugins/' . $plugin;
  }
  elseif ($module == 'entityreference') {
    return "plugins/entityreference/$plugin";
  }
/**
 * Implements hook_permission().
 */
function og_permission() {
    'administer group' =>  array(
      'title' => t('Administer Organic groups permissions'),
      'description' => t('Administer all groups and permissions.'),
    ),
  );
}

/**
 * Implements hook_og_permission().
Amitaibu's avatar
Amitaibu committed
function og_og_permission() {
  // Generate standard node permissions for all applicable node types.
  $perms = array();

  $perms['update group'] = array(
    'title' => t('Edit group'),
    'description' => t('Edit the group. Note: This permission controls only node entity type groups.'),
  );
  $perms['administer group'] = array(
    'title' => t('Administer group'),
    'description' => t('Manage group members and content in the group.'),
  foreach (node_permissions_get_configured_types() as $type) {
    $perms = array_merge($perms, og_list_permissions($type));
 * Implements hook_og_default_roles().
Amitaibu's avatar
Amitaibu committed
function og_og_default_roles() {
Amitaibu's avatar
Amitaibu committed
  return array(OG_ADMINISTRATOR_ROLE);
 * Implements hook_node_access().
function og_node_access($node, $op, $account) {
  $type = is_string($node) ? $node : (is_array($node) ? $node['type'] : $node->type);

  if ($op == 'create' && og_is_group_content_type('node', $type) && variable_get('og_node_access_strict', TRUE) && !user_access('administer group')) {
    // We can't check if user has create permissions using og_user_access(), as
    // there is no group context. However, we can check if there are any groups
    // the user will be able to select, and if not, we don't allow access.
    // @see OgSelectionHandler::getReferencableEntities()
    foreach (og_get_group_audience_fields('node', $type, FALSE) as $field_name => $label) {
      $field = field_info_field($field_name);
      $instance = field_info_instance('node', $field_name, $type);
      if (entityreference_get_selection_handler($field, $instance)->getReferencableEntities()) {
        return NODE_ACCESS_ALLOW;
      }
    }
    return NODE_ACCESS_DENY;
  }
  elseif (in_array($op, array('update', 'delete'))) {
    $access = og_user_access_entity('administer group', 'node', $node, $account);

    if (is_null($access)) {
      // The node isn't in an OG context, so no need to keep testing.
      return NODE_ACCESS_IGNORE;
    else {
      $access = $access ||
        // Any content.
        og_user_access_entity("$op any $type content", 'node', $node, $account) ||
        // Own content.
        (og_user_access_entity("$op own $type content", 'node', $node, $account) && $account->uid == $node->uid);
    if (!$access && $op == 'update' && og_is_group('node', $node)) {
      // The node is a group, so check "update group" permission.
      $access = og_user_access_entity('update group', 'node', $node, $account);
    }

    if ($access) {
      return NODE_ACCESS_ALLOW;
    }

    // Check if OG should explicitly deny access or not.
    return variable_get('og_node_access_strict', TRUE) ? NODE_ACCESS_DENY : NODE_ACCESS_IGNORE;
 * Implements hook_field_access().
 *
 * Hide group-audience fields from user's edit profile for non-privileged users.
 */
function og_field_access($op, $field, $entity_type, $entity, $account) {
  global $user;

  if (empty($entity)) {
    // We are in field settings page.
    return;
  }


  if (!$user->uid) {
    // User is anonymous, and user register might try to add the
    // group-audience field.
    return;
  }

  if ($op != 'edit') {
    return;
  }

  $field_name = $field['field_name'];
  list($id, $vid, $bundle_name) = entity_extract_ids($entity_type, $entity);
  if ($field_name == OG_GROUP_FIELD) {
    $wrapper = entity_metadata_wrapper($entity_type, $entity);
    if ($wrapper->getIdentifier() && !$wrapper->{OG_GROUP_FIELD}->value()) {
      // Entity isn't an active group.
      return;
    }
    $instance = field_info_instance($entity_type, $field_name, $bundle_name);
    if (!empty($instance['widget']['settings']['og_hide'])) {
      return FALSE;
    }
    return;
  }

  if (!og_is_group_audience_field($field_name)) {
    return;
  }

  $field = field_info_field($field_name);
  $settings = $field['settings']['handler_settings'];

Amitaibu's avatar
Amitaibu committed
  // Check if we are editing the user entity, or need to hide a secondary
  // field.
  if ($entity_type == 'user' || (!empty($settings['primary_field']) && !empty($settings['hide_secondary_field']))) {
    return user_access('administer group', $account);
  }
}


/**
 * Implements hook_views_api().
    'path' => drupal_get_path('module', 'og') . '/includes',
  );
}
 * Implements hook_field_create_instance().
 *
 * - Create default OG roles per entity-type and bundle.
 * - Create a group audience field on the user's entity, referencing the first
 *   group defined.
function og_field_create_instance($instance) {
  if ($instance['field_name'] != OG_GROUP_FIELD) {
    return;
  }

  // Create global roles per entity-type per bundle.
  og_roles_override($instance['entity_type'], 0, $instance['bundle']);

  // Check if we need to add a group audience on the user's entity.
  // We add a different field, so each field can be set differently.
  if (!og_is_group_content_type('user', 'user')) {
    $og_field = og_fields_info(OG_AUDIENCE_FIELD);
    $og_field['field']['settings']['target_type'] = $instance['entity_type'];
    $og_field['instance']['label'] = t('Group membership');
    og_create_field('og_user_group_ref', 'user', 'user', $og_field);

    // Create "Other groups" field.
    $og_field['instance']['label'] = t('Other groups');
    $og_field['instance']['widget']['type'] = 'entityreference_autocomplete';
    $og_field['field']['settings']['handler_settings']['reference_type'] = 'other_groups';
    $og_field['field']['settings']['handler_settings']['primary_field'] = 'og_user_group_ref';
    $og_field['field']['settings']['handler_settings']['hide_secondary_field'] = TRUE;
    og_create_field('og_other_user_group_ref', 'user', 'user', $og_field);
Amitaibu's avatar
Amitaibu committed

 * Implements field_delete_instance().
 *
 * - Invalidate OG's static cache if a group-audience field is deleted.
 * - Delete the default OG roles per entity-type and bundle.
function og_field_delete_instance($instance) {
  if (og_is_group_audience_field($instance['field_name'])) {
    og_invalidate_cache();
  }

  if ($instance['field_name'] != OG_GROUP_FIELD) {
    return;
  }

  // Get the global roles.
  $roles = og_roles($instance['entity_type'], 0, $instance['bundle']);
  foreach ($roles as $rid => $name) {
    og_role_delete($rid);
/**
 * Implements hook_form_alter().
 */
function og_form_alter(&$form, $form_state, $form_id) {
  if (empty($form['#entity_type']) && empty($form['#bundle'])) {
    return;
  }
  $entity_type = $form['#entity_type'];
  $bundle = $form['#bundle'];

  if ($entity_type == 'user' || !og_is_group_type($entity_type, $bundle)) {
    return;
  }
  $form['#validate'][] = 'og_form_group_manager_validate';
}

/**
 * Validate handler; Make sure a group can be created.
 *
 * We check if the group manager has a matching group-audience field for the
 * OG membership do be created in.
 */
function og_form_group_manager_validate($form, &$form_state) {
  $entity_type = $form['#entity_type'];
  $bundle = $form['#bundle'];
  $entity = $form_state[$entity_type];
  $langcode = $form_state['values']['language'];

  if (!isset($form_state['values']['uid']) || !isset($entity->uid)) {
    // There is no user ID property on the entity.
    return;
  }

  if (isset($form_state['values'][OG_GROUP_FIELD]) && empty($form_state['values'][OG_GROUP_FIELD][$langcode][0]['value'])) {
    // Not a group.
    return;
  }

  if (!isset($form_state['values'][OG_GROUP_FIELD])) {
    // Field doesn't appear in the form, so it is probably hidden by
    // hook_field_access(). So check the default value of the field.
    $field = field_info_field(OG_GROUP_FIELD);
    $instance = field_info_instance($entity_type, OG_GROUP_FIELD, $bundle);

    $items = field_get_default_value($entity_type, $entity, $field, $instance, $langcode);
    if (empty($items[0]['value'])) {
      // Default value is not a group.
      return;
    }
  }

  if ($entity_type == 'node') {
    // A user might assign the node author by entering a user name in the
    // node form, which we then need to translate to a user ID.
    // However, this happens later on, in node_submit(), so we do a special
    // check for the node entity.
    if (!$account = user_load_by_name($form_state['values']['name'])) {
      // Invalid username.
      return;
    }
  }
  else {
    $account = user_load($form_state['values']['uid']);
  }

  list($id) = entity_extract_ids($entity_type, $entity);

  if ($id && $entity->uid == $account->uid) {
    // The entity's user ID hasn't changed.
    return;
  }

  if ($access = og_get_best_group_audience_field('user', $account, $entity_type, $bundle)) {
    // Matching group audience field found.
    return;
  }

  form_error($form, t("Can't save entity as group, because user @name can't be subscribed to group and become a manager.", array('@name' => format_username($account))));
}


/**
 * Implements hook_field_attach_form().
 *
 * Inject values to a secondary field, based on the primary field.
 */
function og_field_attach_form($entity_type, $entity, &$form, &$form_state, $langcode) {
  list($id,, $bundle_name) = entity_extract_ids($entity_type, $entity);
  if (!og_is_group_content_type($entity_type, $bundle_name)) {
    return;
  }

  $wrapper = entity_metadata_wrapper($entity_type, $entity);
  $has_secodary = FALSE;

  // Get all the group-audience fields in the entity.
  foreach (og_get_group_audience_fields($entity_type, $bundle_name) as $field_name => $label) {
    $field = field_info_field($field_name);

    if (empty($field['settings']['handler_settings']['primary_field'])) {
      continue;
    }
    $has_secodary = TRUE;

    $primary_field = $field['settings']['handler_settings']['primary_field'];
    $primary_ids = $wrapper->$primary_field->value(array('identifier' => TRUE));
    if (!$primary_ids) {
      continue;
    }

    // Intersect the IDs from the primary field, with the referencable IDs
    // from the secondary, by validating the IDs.
    if (!is_array($primary_ids)) {
      // If the field cardinality is 1, entity metadatwrapper, returns the
      // value as integer, so turn it into an array.
      $primary_ids = array($primary_ids);
    }
    $secondary_ids = entityreference_get_selection_handler($field)->validateReferencableEntities($primary_ids);
    if (!$secondary_ids) {
      continue;
    }

    // Rebuild the items array.
    $items = array();
    foreach ($secondary_ids as $id) {
      $items[] = array(
        'target_id' => $id,
      );
    if (empty($form_state['field'][$field_name])) {
      continue;
    }

    $key = key($form_state['field'][$field_name]);

    // We don't use field_form_set_state() as we just want to change the items
    // count. We have to do it before calling field_default_form().
    $form_state['field'][$field_name][$key]['items_count'] = count($items);

    $instance = $form_state['field'][$field_name][$key]['instance'];
    // Re-build the field, based on the injected values.
    $result = field_default_form($entity_type, $entity, $field, $instance, $key, $items, $form, $form_state, NULL);
    $form[$field_name] = $result[$field_name];
  }
  if ($has_secodary) {
    $form['#validate'][] = 'og_form_secondary_field_validate';
 * Validate handler; Check field cardinality of primary field.
 * We need to make sure that values pushed from a secondary field, don't exceed
 * the allowed values of the primary field.
function og_form_secondary_field_validate($form, &$form_state) {
  // Get an keyed with the primary field, and an arrayof secoadry fields as the
  // value.
  $entity_type = $form['#entity_type'];
  if (empty($form_state[$entity_type])) {
    // Entity info isn't in the $form_state (e.g. when admin creates a new
    // user).
    return;
  }
  $entity = $form_state[$entity_type];
  $fields_info = array();
  foreach ($form_state['field'] as $field_name => $value) {
    if (!og_is_group_audience_field($field_name)) {
      continue;
    }
    $langcode = key($value);
    // If there is no field info, it means the field isn't accessible.
    $field = !empty($value[$langcode]['field']) ? $value[$langcode]['field'] : array();
    if (!empty($field['settings']['handler_settings']['primary_field'])) {
      $fields_info[$field['settings']['handler_settings']['primary_field']][] = $field_name;
    }
  }

  foreach ($fields_info as $primary_field_name => $values) {
    $langcode = key($form_state['field'][$primary_field_name]);
    $primary_field = $form_state['field'][$primary_field_name][$langcode]['field'];
    if ($primary_field['cardinality'] == FIELD_CARDINALITY_UNLIMITED) {
      continue;
    }
    $primary_instance = $form_state['field'][$primary_field_name][$langcode]['instance'];
    // Get the items from the form state.
    $count = 0;
    $items = FALSE;
    field_default_extract_form_values($entity_type, $entity, $primary_field, $primary_instance, $langcode, $items, $form, $form_state);
    foreach ($items as $item) {
      if (!empty($item['target_id'])) {
        ++$count;
      }
    }

    $secondary_labels = array();
    foreach ($values as $secondary_field_name) {
      $langcode = key($form_state['field'][$secondary_field_name]);
      $secondary_field = $form_state['field'][$secondary_field_name][$langcode]['field'];
      $secondary_instance = $form_state['field'][$secondary_field_name][$langcode]['instance'];
      $secondary_labels[] = $secondary_instance['label'];
      // Get the items from the form state.
      $items = FALSE;
      field_default_extract_form_values($entity_type, $entity, $secondary_field, $secondary_instance, $langcode, $items, $form, $form_state);
      foreach ($items as $item) {
        if (!empty($item['target_id'])) {
          ++$count;
          // Set the field name that will invoke the error.
          $element_error = $secondary_field_name;
        }

    if ($count > $primary_field['cardinality']) {
      $params = array(
        '%primary' => $primary_instance['label'],
        '%secondary' => implode(', ', $secondary_labels),
        '@count' => $primary_field['cardinality'],
      );
      form_error($form[$element_error], t('Values from the secondary field(s) %secondary can not be pushed into the primary field %primary as it is limited to @count values.', $params));
    }
 * Implements hook_entity_presave().
function og_entity_presave($entity, $entity_type) {
  list(,,$bundle) = entity_extract_ids($entity_type, $entity);
  if (!og_is_group_content_type($entity_type, $bundle)) {
    return;
  }

  $wrapper = entity_metadata_wrapper($entity_type, $entity);
  // Get secondary fields.
  $fields_info = field_info_fields();
  foreach (field_info_instances($entity_type, $bundle) as $field_name => $field_instance) {
    $field_info = $fields_info[$field_name];
    if ($field_info['type'] != 'entityreference' || $field_info['settings']['handler'] != 'og') {
      // This is not an Entity reference field.
      continue;
    }

    if (empty($field_info['settings']['handler_settings']['primary_field'])) {
      continue;
    }

    if (!$wrapper->{$field_name}->value(array('identifier' => TRUE))) {
      continue;
    }

    $primary_field = $fields_info[$field_name]['settings']['handler_settings']['primary_field'];
    $primary_field_info = field_info_field($primary_field);
    $existing_ids = $wrapper->{$primary_field}->value(array('identifier' => TRUE));
    if (!is_array($existing_ids)) {
      // Entity metadta returned a single ID.
      $existing_ids = array($existing_ids);
    }
    foreach ($wrapper->{$field_name}->value(array('identifier' => TRUE)) as $id) {
      // TODO: Move this check to Entity API.
      if (!in_array($id, $existing_ids)) {
        if ($primary_field_info['cardinality'] == 1) {
          $wrapper->{$primary_field}->set($id);
        }
        else {
          $wrapper->{$primary_field}[] = $id;
        }

        $delta = $primary_field_info['cardinality'] == 1 ? 0 : $wrapper->{$primary_field}->count();
      }
    }

    // Remove the values from the secondary field.
    $wrapper->{$field_name}->set(NULL);
  }
Amitaibu's avatar
Amitaibu committed
}

/**
 * Implements hook_entity_insert().
Amitaibu's avatar
Amitaibu committed
 */
function og_entity_insert($entity, $entity_type) {
  _og_update_entity_fields($entity_type, $entity);
  if (!og_is_group($entity_type, $entity)) {
    return;
  }
  list($id, $vid, $bundle) = entity_extract_ids($entity_type, $entity);
  if (!empty($entity->uid)) {
    // Subscribe the group manager.
    og_group($entity_type, $id, array('entity' => $entity->uid));
    // Assign roles to group manager.
    $name = 'og_group_manager_default_rids_' . $entity_type . '_' . $bundle;
    if ($rids = variable_get($name)) {
      foreach ($rids as $rid) {
        og_role_grant($entity_type, $id, $entity->uid, $rid);
      }
    }
  }
  if (!og_is_group_default_access($entity_type, $entity)) {
    // Override default roles.
    og_roles_override($entity_type, $id, $bundle);
  }
}
/**
 * Implements hook_entity_update().
 */
function og_entity_update($entity, $entity_type) {
  _og_update_entity_fields($entity_type, $entity);
  if (!og_is_group($entity_type, $entity)) {
  list($id, $vid, $bundle) = entity_extract_ids($entity_type, $entity);
  if (!empty($entity->uid) && !og_is_member($entity_type, $entity, 'user', $entity->uid)) {
    // Subscribe the group manager, in case the owner changed.
    og_group($entity_type, $id, array('entity' => $entity->uid));
    // Assign roles to group manager.
    $name = 'og_group_manager_default_rids_' . $entity_type . '_' . $bundle;
    if ($rids = variable_get($name)) {
      foreach ($rids as $rid) {
        og_role_grant($entity_type, $id, $entity->uid, $rid);
      }
    }
  }
  $origianl_entity = $entity->original;
  $property = OG_DEFAULT_ACCESS_FIELD;

  if (!empty($entity->{$property}) && $entity->{$property} != $origianl_entity->{$property}) {
    if (!og_is_group_default_access($entity_type, $entity)) {
      // Override default roles.
      og_roles_override($entity_type, $id, $bundle);
    }
    else {
      // Delete overridden roles.
      og_delete_user_roles_by_group($entity_type, $entity);