You are here

og_context.module in Organic groups 7

Same filename and directory in other branches
  1. 7.2 og_context/og_context.module

Get a group from a viewed page.

File

og_context/og_context.module
View source
<?php

/**
 * @file
 * Get a group from a viewed page.
 */

/**
 * Implements hook_menu().
 */
function og_context_menu() {
  $items['admin/config/group/context'] = array(
    'title' => 'Organic groups context',
    'description' => 'Organic groups context detection and selection',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'og_context_configure_form',
    ),
    'access arguments' => array(
      'administer group',
    ),
    'file' => 'og_context.admin.inc',
  );
  return $items;
}

/**
 * Implements hook_theme().
 */
function og_context_theme() {
  return array(
    'og_context_configure_form' => array(
      'render element' => 'form',
    ),
  );
}

/**
 * Implements hook_entity_property_info().
 *
 * Add the current-group to the system token (i.e. like current-user).
 */
function og_context_entity_property_info() {
  $info = array();
  $properties =& $info['site']['properties'];
  $properties['current_group'] = array(
    'label' => t("Current group"),
    'description' => t("The group from context, if exists."),
    'getter callback' => 'og_context_get_properties',
    'type' => 'group',
  );
  return $info;
}

/**
 * Property getter callback.
 */
function og_context_get_properties($data = array(), array $options, $name, $type) {
  switch ($name) {
    case 'current_group':

      // Get the current group.
      // @code
      //   $wrapper = entity_metadata_site_wrapper();
      //   wrapper->current_group->value()
      // @endcode
      return ($group = og_context()) ? $group : NULL;
  }
}

/**
 * Implement hook_preprocess_html().
 *
 * HTML preprocess; Add context related templates and CSS.
 */
function og_context_preprocess_html(&$variables) {
  if ($group = og_context()) {

    // Add template suggestions.
    $variables['theme_hook_suggestions'][] = 'page__group_context';
    $variables['theme_hook_suggestions'][] = 'page__group_context__group_' . $group->gid;
    $variables['theme_hook_suggestions'][] = 'page__group_context__' . $group->entity_type;
    $variables['theme_hook_suggestions'][] = 'page__group_context__' . $group->entity_type . '_' . $group->etid;

    // Add CSS.
    $clean_html = drupal_html_class('group-context-' . $group->entity_type);
    $variables['classes_array'][] = 'group-context';
    $variables['classes_array'][] = 'group-context-group-' . $group->gid;
    $variables['classes_array'][] = $clean_html;
    $variables['classes_array'][] = $clean_html . '-' . $group->etid;

    // Add context to JS.
    og_context_add_js($group);
  }
}

/**
 * Implements hook_og_context_negotiation_info().
 */
function og_context_og_context_negotiation_info() {
  $providers = array();
  $providers['url'] = array(
    'name' => t('URL'),
    'description' => t("Select groups if they were passed in the URL (e.g. node/add/post?gids_node[]=4,5,6)."),
    'callback' => 'og_context_handler_url',
  );
  $providers['node'] = array(
    'name' => t('Node'),
    'description' => t("Determine context by checking if a node is a group or a group content."),
    'callback' => 'og_context_handler_node',
    'menu path' => array(
      'node/%',
      'node/%/edit',
    ),
  );
  $providers['user-view'] = array(
    'name' => t('User view'),
    'description' => t("Determine context by checking if a user is a group or a group content on the 'user view' page."),
    'callback' => 'og_context_handler_user_view',
    'menu path' => array(
      'user/%',
    ),
  );
  $providers['user-edit'] = array(
    'name' => t('User edit'),
    'description' => t("Determine context by checking if a user is a group or a group content on the 'user edit' page."),
    'callback' => 'og_context_handler_user_edit',
    'menu path' => array(
      'user/%/edit',
    ),
  );
  return $providers;
}

/**
 * Implement hook_init().
 */
function og_context_init() {
  og_context();
}

/**
 * Implements hook_views_api().
 */
function og_context_views_api() {
  return array(
    'api' => 2,
    'path' => drupal_get_path('module', 'og_context') . '/includes',
  );
}

/**
 * Implements hook_og_invalidate_cache().
 */
function og_context_og_invalidate_cache($gids = array()) {
  $caches = array(
    'og_context',
    'og_context_js',
  );
  foreach ($caches as $cache) {
    drupal_static_reset($cache);
  }
  if ($gids && !empty($_SESSION['og_context']) && in_array($_SESSION['og_context'], $gids)) {

    // Remove group's context.
    $_SESSION['og_context'] = NULL;
  }
}

/**
 * Implements hook_ctools_entity_contexts_alter().
 *
 * Change the OG context plugin.
 *
 * @see ctools_context_entity_get_children().
 */
function og_context_ctools_entity_contexts_alter(&$plugins) {
  if (empty($plugins['entity:group'])) {
    return;
  }
  $plugin =& $plugins['entity:group'];
  $plugin['context'] = 'og_context_create_og_group';
  $plugin['edit form'] = 'og_context_og_group_settings_form';
  $plugin['defaults'] = array(
    'type' => 'select',
    'gid' => '',
  );
}

/**
 * Return OG group form context.
 */
function og_context_create_og_group($empty, $data = NULL, $conf = FALSE) {
  $context = new ctools_context(array(
    'entity:group',
    'entity',
    'group',
  ));
  $context->plugin = 'og_group';
  if ($empty) {
    return $context;
  }
  if ($conf) {
    if ($data['type'] == 'select') {
      global $user;
      $data = og_load($data->gid);
    }
    else {
      $data = og_context();
    }
  }

  // Load entity if the data provided is a numeric value. This kind of data is
  // passed by some relationships.
  if (!empty($data) && is_numeric($data)) {
    $data = og_load($data);
  }
  if (!$data) {
    return ctools_context_create_empty('entity:group', NULL);
  }
  $context->data = $data;
  $context->argument = $data->gid;
  $context->title = og_label($data->gid);
  return $context;
}

/**
 * OG group context settings form.
 */
function og_context_og_group_settings_form($form, &$form_state) {
  $conf = $form_state['conf'];
  $form['type'] = array(
    '#title' => t('Enter the context type'),
    '#type' => 'radios',
    '#options' => array(
      'select' => t('Select an OG group'),
      'context' => t('OG group form context'),
    ),
    '#default_value' => $conf['type'],
  );
  $form['gid'] = array(
    '#title' => t('Enter a group ID'),
    '#type' => 'textfield',
    '#states' => array(
      'visible' => array(
        ':input[name=type]' => array(
          'value' => 'select',
        ),
      ),
    ),
    '#default_value' => $conf['gid'],
  );
  if (!empty($conf['gid'])) {
    $group = og_load($conf['gid']);
    if ($group) {
      $form['gid']['#description'] = t('Currently set to %name group', array(
        '%name' => og_label($group->gid),
      ));
    }
  }
  return $form;
}

/**
 * Validate an OG group.
 */
function og_context_og_group_settings_form_validate($form, &$form_state) {
  if ($form_state['values']['type'] != 'select') {
    return;
  }
  if (empty($form_state['values']['gid'])) {
    form_error($form['user'], t('You must select an OG group.'));
    return;
  }
  element_validate_integer_positive($form['gid'], $form_state);
  if (form_get_error($form['gid'])) {
    return;
  }
  $group = og_load($form_state['values']['gid']);
  if (!$group) {
    form_error($form['gid'], t('Invalid OG group selected.'));
  }
}

/**
 * Submit handler; Save values.
 */
function og_context_og_group_settings_form_submit($form, &$form_state) {
  $form_state['conf']['type'] = $form_state['values']['type'];
  $form_state['conf']['gid'] = $form_state['values']['gid'];
}

/**
 * Get or set group context using the menu system.
 *
 * @param $group
 *   Optional; The group entity to set as the context.
 *
 * @return
 *   A group entity, or FALSE if no context was found.
 */
function og_context($group = NULL) {
  global $user;
  $context =& drupal_static(__FUNCTION__, FALSE);
  if (!empty($group)) {
    $context = $group;
  }
  if (empty($context)) {

    // Get context from context handlers.
    if (($context = og_context_determine_context()) && $user->uid) {

      // TODO: Add option to save session for anonymous users as-well?
      // Save the group ID in the authenticated user's session,
      $_SESSION['og_context'] = $context->gid;
    }
  }
  return $context;
}

/**
 * Add the group entity of the context to the Drupal javascript entity.
 *
 * @param $group
 *   A group entity.
 */
function og_context_add_js($group) {

  // Static variable to indicate if group was already added to javascript.
  $js =& drupal_static(__FUNCTION__, FALSE);
  if (empty($js)) {
    drupal_add_js(array(
      'og' => array(
        'og_context' => $group,
      ),
    ), 'setting');
    $js = TRUE;
  }
}

/**
 * Return all the defined group context providers.
 *
 * @return
 *   An array of group context providers.
 */
function og_context_negotiation_info() {
  $group_context_providers =& drupal_static(__FUNCTION__);
  if (!isset($group_context_providers)) {

    // Collect all the module-defined og_context negotiation providers.
    $group_context_providers = module_invoke_all('og_context_negotiation_info');

    // Let other modules alter the list of og_context providers.
    drupal_alter('og_context_negotiation_info', $group_context_providers);
  }

  // Assign default values.
  foreach ($group_context_providers as &$group_context_provider) {
    $group_context_provider += array(
      'menu path' => array(),
    );
  }
  return $group_context_providers;
}

/**
 * Save a list of language providers.
 *
 * @param $type
 *   The language negotiation type.
 * @param $language_providers
 *   An array of language provider ids.
 */
function og_context_negotiation_set($group_context_providers) {
  $type = 'group_context';

  // Save only the necessary fields.
  $provider_fields = array(
    'callbacks',
  );
  $negotiation = array();
  $providers_weight = array();
  $defined_providers = og_context_negotiation_info();

  // Initialize the providers weight list.
  foreach ($group_context_providers as $id => $provider) {
    $providers_weight[$id] = og_context_provider_weight($provider);
  }

  // Order providers list by weight.
  asort($providers_weight);
  foreach ($providers_weight as $id => $weight) {
    if (isset($defined_providers[$id])) {
      $provider = $defined_providers[$id];
      $provider_data = array();
      foreach ($provider_fields as $field) {
        if (isset($provider[$field])) {
          $provider_data[$field] = $provider[$field];
        }
      }
      $negotiation[$id] = $provider_data;
    }
  }
  variable_set("og_context_negotiation_{$type}", $negotiation);
}

/**
 * Return the passed group context provider weight or a default value.
 *
 * @param $provider
 *   A group context provider data structure.
 *
 * @return
 *   A numeric weight.
 */
function og_context_provider_weight($provider) {
  $default = is_numeric($provider) ? $provider : 0;
  return isset($provider['weight']) && is_numeric($provider['weight']) ? $provider['weight'] : $default;
}

/**
 * Determine the best matching context of a viewed page.
 *
 * @param $item
 *   Optional; A menu item that context should be extracted from. If empty
 *   defaults to the current menu item by using menu_get_item().
 */
function og_context_determine_context($item = NULL) {
  $context = FALSE;

  // Enable url and node context handlers by default.
  $defaults = array(
    'url' => -5,
    'node' => -4,
  );
  if ($enabled_providers = array_keys(variable_get("og_context_negotiation_group_context", $defaults))) {
    if (empty($item)) {
      $item = menu_get_item();
    }
    foreach (og_context_negotiation_info() as $name => $provider) {
      if (in_array($name, $enabled_providers)) {
        $invoke = FALSE;
        if (!empty($provider['menu path'])) {
          foreach ($provider['menu path'] as $path) {
            if (strpos($item['path'], $path) === 0) {
              $invoke = TRUE;

              // Path matches, so we can break.
              break;
            }
          }
        }
        else {

          // Context isn't determined by the menu item.
          $invoke = TRUE;
        }
        $gids = array();
        if ($invoke && ($gids = call_user_func($provider['callback']))) {

          // Check if one of the group IDs already exists in the session, and if
          // so use it.
          if (!empty($_SESSION['og_context']) && in_array($_SESSION['og_context'], $gids)) {
            $gid = $_SESSION['og_context'];
          }
          else {

            // Grab the first group ID.
            $gid = reset($gids);
          }
          $context = og_load($gid);

          // We found the first context, so we can break.
          break;
        }
      }
    }
  }
  return $context;
}

/**
 * Context handler; Get groups from URL.
 */
function og_context_handler_url() {
  $context = array();
  if ($gids = og_get_context_by_url()) {
    $context = $gids;
  }
  return $context;
}

/**
 * Context handler; Get groups from existing node or ctools context.
 */
function og_context_handler_node() {
  $node = menu_get_object('node');
  if ($node) {
    return _group_context_handler_entity('node', $node);
  }

  // The path may not be %node, but in fact is a ctools-context, so extract the
  // node from it. We check only the 1st position (e.g. node/%/foo).
  $item = menu_get_item();
  if (empty($item['map'][1]) || !is_object($item['map'][1]) || !$item['map'][1] instanceof ctools_context) {
    return;
  }

  // Check the context is a node type. We check only path similar to node/%/foo
  // and don't traverse over the whole arguments, as it might be a page manager
  // page passing multiple nodes (e.g. some/path/with/%node/%node). Implementing
  // modules wanting to handle the above example, should implement their own
  // context handler.
  $context = clone $item['map'][1];
  if (empty($context->type[0]) || $context->type[0] != 'entity:node') {
    return;
  }
  return _group_context_handler_entity('node', $context->data);
}

/**
 * Context handler; Get groups from user view.
 */
function og_context_handler_user_view() {
  global $user;
  return _group_context_handler_entity('user', $user);
}

/**
 * Context handler; Get groups from user edit.
 */
function og_context_handler_user_edit() {
  return _group_context_handler_entity('user');
}

/**
 * Helper function to get group context from an entity.
 *
 * @param $entity_type
 *   The entity type.
 * @param $entity
 *   Optional; The entity object.
 * @param $position
 *   Optional; The position that should be used in menu_get_object().
 */
function _group_context_handler_entity($entity_type = 'node', $entity = NULL, $position = 1) {
  $context = array();
  if (empty($entity)) {
    $entity = menu_get_object($entity_type, $position);
  }
  if ($entity) {

    // Check if the entity is itself a group.
    list($id) = entity_extract_ids($entity_type, $entity);

    // Only proceed if it really is the entity and we got an id.
    if (isset($id)) {
      if ($group = og_get_group($entity_type, $id)) {
        $context = drupal_map_assoc(array(
          $group->gid,
        ));
      }
      elseif ($gids = og_get_entity_groups($entity_type, $entity)) {
        $context = $gids;
      }
    }
  }
  return $context;
}

Functions

Namesort descending Description
og_context Get or set group context using the menu system.
og_context_add_js Add the group entity of the context to the Drupal javascript entity.
og_context_create_og_group Return OG group form context.
og_context_ctools_entity_contexts_alter Implements hook_ctools_entity_contexts_alter().
og_context_determine_context Determine the best matching context of a viewed page.
og_context_entity_property_info Implements hook_entity_property_info().
og_context_get_properties Property getter callback.
og_context_handler_node Context handler; Get groups from existing node or ctools context.
og_context_handler_url Context handler; Get groups from URL.
og_context_handler_user_edit Context handler; Get groups from user edit.
og_context_handler_user_view Context handler; Get groups from user view.
og_context_init Implement hook_init().
og_context_menu Implements hook_menu().
og_context_negotiation_info Return all the defined group context providers.
og_context_negotiation_set Save a list of language providers.
og_context_og_context_negotiation_info Implements hook_og_context_negotiation_info().
og_context_og_group_settings_form OG group context settings form.
og_context_og_group_settings_form_submit Submit handler; Save values.
og_context_og_group_settings_form_validate Validate an OG group.
og_context_og_invalidate_cache Implements hook_og_invalidate_cache().
og_context_preprocess_html Implement hook_preprocess_html().
og_context_provider_weight Return the passed group context provider weight or a default value.
og_context_theme Implements hook_theme().
og_context_views_api Implements hook_views_api().
_group_context_handler_entity Helper function to get group context from an entity.