You are here

context_prefix.module in Context 5

File

context_prefix/context_prefix.module
View source
<?php

define('CONTEXT_PREFIX_PATH', 0);
define('CONTEXT_PREFIX_SUBDOMAIN', 1);
define('CONTEXT_PREFIX_DOMAIN', 2);
define('CONTEXT_PREFIX_PAIR', 3);

/**
 * Implementation of hook_menu().
 */
function context_prefix_menu($may_cache) {
  $items = array();
  if ($may_cache) {
    $items[] = array(
      'type' => module_exists('context_ui') ? MENU_LOCAL_TASK : MENU_NORMAL_ITEM,
      'title' => t('Context prefix'),
      'description' => t('Settings for context prefix.'),
      'path' => 'admin/build/context/prefix',
      'callback' => 'drupal_get_form',
      'callback arguments' => array(
        'context_prefix_settings_form',
      ),
      'access' => user_access('administer site configuration'),
      'weight' => 10,
    );
    $items[] = array(
      'type' => MENU_DEFAULT_LOCAL_TASK,
      'title' => t('Settings'),
      'path' => 'admin/build/context/prefix/settings',
      'callback arguments' => array(
        'context_prefix_settings_form',
      ),
      'access' => user_access('administer site configuration'),
      'weight' => 0,
    );
    $items[] = array(
      'type' => MENU_LOCAL_TASK,
      'title' => t('Registered prefixes'),
      'path' => 'admin/build/context/prefix/list',
      'callback' => 'context_prefix_admin',
      'access' => user_access('administer site configuration'),
      'weight' => 10,
    );
  }
  return $items;
}

/**
 * Implementation of hook_init()
 * Checks for any valid context prefixes in request string and sets the context appropriately
 */
function context_prefix_init() {
  static $once;
  if (!$once) {
    _context_prefix_init(CONTEXT_PREFIX_PATH);
    _context_prefix_init(CONTEXT_PREFIX_DOMAIN);
    _context_prefix_init(CONTEXT_PREFIX_PAIR);
    $once = true;
  }
}

/**
 * Helper function to initialize, parse + set prefixed contexts.
 */
function _context_prefix_init($method = CONTEXT_PREFIX_PATH) {
  switch ($method) {
    case CONTEXT_PREFIX_PATH:
      $q = isset($_REQUEST["q"]) ? trim($_REQUEST["q"], "/") : '';
      $parsed = context_prefix_parse(CONTEXT_PREFIX_PATH, $q);
      break;
    case CONTEXT_PREFIX_PAIR:
      $q = isset($_REQUEST["q"]) ? trim($_REQUEST["q"], "/") : '';
      $parsed = context_prefix_parse(CONTEXT_PREFIX_PAIR, $q);
      break;
    case CONTEXT_PREFIX_DOMAIN:
      $host = $_SERVER['HTTP_HOST'];

      // We handle sub.domain.com, and nothing more (no sub1.sub2.domain.com).
      $q = str_replace('http://', '', $host);
      $parsed = context_prefix_parse(CONTEXT_PREFIX_DOMAIN, $q);
      break;
  }

  // if $_GET and $_REQUEST are different, the path has NOT been
  // aliased. We may need to rewrite the path.
  if (in_array($method, array(
    CONTEXT_PREFIX_PATH,
    CONTEXT_PREFIX_PAIR,
  )) && $_GET['q'] == $_REQUEST['q']) {
    $q = context_prefix_unprefix($q, $method);

    // there is nothing beyond the path prefix -- treat as frontpage
    if ($q == '') {
      $_GET['q'] = variable_get('site_frontpage', 'node');
    }
    else {
      $_REQUEST['q'] = $_GET['q'] = _context_prefix_get_normal_path($q);
    }
  }
  if (is_array($parsed)) {
    foreach ($parsed as $prefix => $info) {
      context_prefix_set($method, $prefix, $info);
    }
  }
}

/**
 * Jose's very smart collision avoidance
 */
if (!function_exists('custom_url_rewrite')) {
  function custom_url_rewrite($type, $path, $original) {
    return context_prefix_url_rewrite($type, $path, $original);
  }
}

/**
 * Rewrites path with current context and removes context if searching for source path
 */
function context_prefix_url_rewrite($type, $path, $original) {
  $working_path = $path;

  // preserve original path
  $args = array();

  // Check to see whether url rewriting has been disabled for this one
  // instance -- currently only possible through cl()
  if (!clswitch('get')) {
    $active_path_prefixes = array();

    // Retrieve the path prefixes for the current page that were
    // "stripped out" and write them back into url paths.
    foreach (context_prefix_get(CONTEXT_PREFIX_PAIR) as $item) {
      $active_path_prefixes[] = $item['prefix'] . '/' . $item['id'];
    }
    foreach (context_prefix_get(CONTEXT_PREFIX_PATH) as $item) {
      $active_path_prefixes[] = $item['prefix'];
    }
    if (count($active_path_prefixes)) {
      $parsed = context_prefix_parse(CONTEXT_PREFIX_PATH, $working_path) + context_prefix_parse(CONTEXT_PREFIX_PAIR, $working_path);

      // A "normal" url was requested -- prefix the path
      if (!$options['alias'] && !strpos($path, '://') && !count($parsed) && count($active_path_prefixes)) {
        $args = $args + $active_path_prefixes;
      }
    }
  }
  if ($working_path) {
    $args[] = $working_path;
  }
  return is_array($args) ? implode('/', $args) : '';
}

/**
 * Queries the database & modules for valid prefixes based on prefixing method.
 *
 * Modules that wish to provide in-code prefixes should implement the 
 * hook_context_prefix_prefixes(). Which should return an array of prefixes by
 * by provider. 
 * 
 * For example:
 *
 *  return array(
 *    'my_module => array(
 *      array('prefix' => 'foo', 'id' => 1),
 *      array('prefix' => 'bar', 'id' => 2),
 *    ),
 *  );
 */
function context_prefix_prefixes($requested_method = CONTEXT_PREFIX_PATH, $reset = FALSE) {
  static $prefixes;
  if (!isset($prefixes) || $reset) {
    $prefixes = array();

    // Invoke context_prefix_prefixes() and gather all prefixes
    // provided "in code" (or stored by their respective modules)
    foreach (module_invoke_all('context_prefix_prefixes') as $provider => $items) {
      $method = variable_get('context_prefix_method_' . $provider, CONTEXT_PREFIX_PATH);

      // If using a prefix pair we don't need to cache the valid prefixes.
      if ($method == CONTEXT_PREFIX_PAIR) {
        $prefix = variable_get('context_prefix_method_' . $provider . '_key', false);
        if ($prefix != false) {
          $prefixes[$method][$prefix] = array(
            'provider' => $provider,
            'id' => null,
          );
        }
      }
      else {
        foreach ($items as $item) {
          if ($item['prefix'] && $item['id']) {
            $prefixes[$method][$item['prefix']] = array(
              'provider' => $provider,
              'id' => $item['id'],
            );
          }
        }
      }
    }

    // Gather database prefixes.
    $result = db_query("SELECT DISTINCT(provider) FROM {context_prefix}");
    while ($item = db_fetch_object($result)) {
      $method = variable_get('context_prefix_method_' . $item->provider, CONTEXT_PREFIX_PATH);

      // Don't load all data base prefixes for keyed pairs.
      if ($method == CONTEXT_PREFIX_PAIR) {
        $prefix = variable_get('context_prefix_method_' . $item->provider . '_key', false);
        if ($prefix != false) {
          $prefixes[$method][$prefix] = array(
            'provider' => $item->provider,
            'id' => null,
          );
        }
      }
      else {
        $result2 = db_query("SELECT * FROM {context_prefix} WHERE provider = '%s'", $item->provider);
        while ($row = db_fetch_object($result2)) {
          $prefixes[$method][$row->prefix] = array(
            'provider' => $row->provider,
            'id' => $row->id,
          );
        }
      }
    }
  }
  return isset($prefixes[$requested_method]) ? $prefixes[$requested_method] : array();
}

/**
 * Parses a query string of various types (url, domain, etc.) and
 * returns an array of any found prefixes and their respective
 * providers/id values.
 */
function context_prefix_parse($method = CONTEXT_PREFIX_PATH, $q) {
  static $cache;
  if (!isset($cache[$method][$q])) {
    $valid_prefixes = context_prefix_prefixes($method);

    // Parse the provided query string and provide an array of any prefixes found
    switch ($method) {
      case CONTEXT_PREFIX_PATH:
      case CONTEXT_PREFIX_PAIR:
        $parsed = array();
        $args = explode('/', $q);
        $arg = $args[0];
        while (isset($valid_prefixes[$arg])) {
          $parsed[$arg] = $valid_prefixes[$arg];
          array_shift($args);
          if ($method == CONTEXT_PREFIX_PAIR) {
            $parsed[$arg]['id'] = array_shift($args);
          }
          $arg = $args[0];
          if (in_array($arg, $parsed)) {
            break;
          }
        }
        $cache[$method][$q] = $parsed;
        break;
      case CONTEXT_PREFIX_DOMAIN:
        $parsed = array();
        if (isset($valid_prefixes[$q])) {
          $parsed[$q] = $valid_prefixes[$q];
        }
        $cache[$method][$q] = $parsed;
        break;
    }
  }
  return $cache[$method][$q];
}

/**
 * Removes any prefixes from a query string. For path prefixes only.
 */
function context_prefix_unprefix($q, $method, $providers = array()) {
  $parsed = context_prefix_parse($method, $q);
  if (is_array($providers) && count($providers)) {
    foreach ($parsed as $prefix => $info) {
      if (!in_array($info['provider'], $providers)) {
        unset($parsed[$prefix]);
      }
    }
  }
  $parsed = array_keys($parsed);
  $args = explode('/', $q);
  switch ($method) {
    case CONTEXT_PREFIX_PATH:
      $args = array_diff($args, $parsed);
      break;
    case CONTEXT_PREFIX_PAIR:
      foreach ($parsed as $v) {
        array_splice($args, array_search($v, $args), 2);
      }
      break;
  }
  return implode('/', $args);
}

/**
 * Invokes hook_context_prefix_provider() to gather all providers.
 *
 * Modules that implement hook_context_prefix_provider need to return an
 * array of prefix definitions. Each definition should have the following 
 * keys:
 *  - name
 *  - description
 *  - callback
 *  - example 
 *
 * See the spaces module for an usage example.
 */
function context_prefix_providers($by_method = FALSE) {
  static $providers;
  if (!is_array($providers)) {
    $providers = array();
    $providers = module_invoke_all('context_prefix_provider');
  }
  if ($by_method) {
    static $methods;
    if (!isset($methods)) {
      $methods = new context_prefix_cache();
      foreach ($providers as $id => $provider) {
        $methods
          ->add(variable_get('context_prefix_method_' . $id, CONTEXT_PREFIX_PATH), array(
          $id => $provider,
        ));
      }
    }
    return $methods
      ->get();
  }
  else {
    return $providers;
  }
}

/**
 * Taken from i18n
 */
function _context_prefix_get_normal_path($path) {

  // If bootstrap, drupal_lookup_path is not defined
  if (!function_exists('drupal_get_headers')) {
    return $path;
  }
  elseif ($alias = drupal_lookup_path('source', $path)) {
    return $alias;
  }
  else {
    return $path;
  }
}

/**
 * Static cache function for setting + storing any prefixed contexts
 * that are present on this page's request.
 */
function _context_prefix_set($op = 'set', $type = CONTEXT_PREFIX_PATH, $prefix = '', $info = array()) {
  static $used;
  if (!$used) {
    $used = new context_prefix_cache();
  }
  switch ($op) {
    case 'set':

      // Store prefix for url rewriting later on in the stack
      $info['prefix'] = $prefix;
      $used
        ->add($type, $info, false);

      // Fire the provider callback
      if ($info['provider'] && $info['id']) {

        // Fire the provider callback
        $providers = context_prefix_providers();
        $callback = $providers[$info['provider']]['callback'];
        $args = isset($providers[$info['provider']]['callback arguments']) ? $providers[$info['provider']]['callback arguments'] : array();
        $args[] = $info['id'];
        if (function_exists($callback)) {
          call_user_func_array($callback, $args);
        }
      }
      break;
    case 'get':
      if ($type === 'all') {
        return $used
          ->get();
      }
      else {
        return $used
          ->get($type);
      }
  }
}

/**
 * Set wrapper for _context_prefix_set()
 */
function context_prefix_set($type = CONTEXT_PREFIX_PATH, $prefix = '', $info = array()) {
  return _context_prefix_set('set', $type, $prefix, $info);
}

/**
 * Get wrapper for _context_prefix_set()
 */
function context_prefix_get($type = CONTEXT_PREFIX_PATH) {
  return _context_prefix_set('get', $type);
}

/**
 * PAGE CALLBACKS =====================================================
 */

/**
 * Page callback for the context_prefix administration page.
 */
function context_prefix_admin() {
  global $pager_page_array, $pager_total, $pager_total_items;
  $page = isset($_GET['page']) ? $_GET['page'] : 0;
  $element = 0;
  $limit = 20;

  // Convert $page to an array, used by other functions.
  $pager_page_array = array(
    $page,
  );
  $methods = _context_ui_options();
  $merged = array();
  foreach (array_keys($methods) as $method) {
    foreach (context_prefix_prefixes($method) as $prefix => $info) {
      $info['prefix'] = $prefix;
      $merged[] = $info;
    }
  }
  $rows = array();
  for ($i = $page * $limit; $i < ($page + 1) * $limit && $i < count($merged); $i++) {
    $rows[] = array(
      $merged[$i]['provider'],
      $merged[$i]['prefix'],
      $merged[$i]['id'],
      $methods[variable_get('context_prefix_method_' . $merged[$i]['provider'], CONTEXT_PREFIX_PATH)],
    );
  }

  // We calculate the total of pages as ceil(items / limit).
  $pager_total_items[$element] = count($merged);
  $pager_total[$element] = ceil($pager_total_items[$element] / $limit);
  $pager_page_array[$element] = max(0, min((int) $pager_page_array[$element], (int) $pager_total[$element] - 1));
  if ($rows) {
    $output .= theme('table', array(
      t('Provider'),
      t('Prefix'),
      t('ID'),
      t('Method'),
    ), $rows);
    $output .= theme('pager');
  }
  else {
    $output .= "<p>" . t('No context prefixes have been registered.') . "</p>";
  }
  return $output;
}

/**
 * Settings form for choosing the operating mode of context_prefix
 */
function context_prefix_settings_form() {
  global $base_url;
  $form = array();
  $options = _context_ui_options();
  foreach (context_prefix_providers() as $id => $provider) {

    // Check to see whether provider has limited the available prefixing methods
    if (is_array($provider['methods']) && count($provider['methods'])) {
      $provider_options = array();
      foreach ($provider['methods'] as $method) {
        $provider_options[$method] = $options[$method];
      }
    }
    else {
      $provider_options = $options;
    }
    $form[$id] = array(
      '#fieldset' => true,
      '#provider' => true,
      '#title' => $provider['name'],
      '#description' => $provider['description'],
    );
    $form[$id]['context_prefix_method_' . $id] = array(
      '#title' => t('Method'),
      '#type' => 'select',
      '#options' => $provider_options,
      '#default_value' => variable_get('context_prefix_method_' . $id, CONTEXT_PREFIX_PATH),
    );
    $form[$id]['context_prefix_method_' . $id . '_key'] = array(
      '#title' => t('Key'),
      '#type' => 'textfield',
      '#size' => 12,
      '#default_value' => variable_get('context_prefix_method_' . $id . '_key', ''),
    );
  }
  $form['context_prefix_location'] = array(
    '#type' => 'fieldset',
    '#title' => t('Prefix location settings'),
  );
  $form['context_prefix_location']['context_prefix_base_domain'] = array(
    '#type' => 'textfield',
    '#title' => t('Select base domain'),
    '#description' => t('This setting determines the base domain for domain based context prefixing.'),
    '#required' => FALSE,
    '#default_value' => variable_get('context_prefix_base_domain', $base_url),
  );
  $form = system_settings_form($form);
  $form['#theme'] = 'context_prefix_settings_form';
  return $form;
}

/**
 * Theme function for context_prefix_settings_form()
 */
function theme_context_prefix_settings_form($form) {
  $output = '';
  $rows = array();
  foreach (element_children($form) as $id) {
    $row = array();
    if (isset($form[$id]['#provider'])) {
      $name = $form[$id]['#title'];
      $description = $form[$id]['#description'];
      unset($form[$id]['#title']);
      unset($form[$id]['#description']);
      $row[] = "<strong>{$name}</strong><div class='description'>{$description}</div>";
      foreach (element_children($form[$id]) as $item) {
        unset($form[$id][$item]['#title']);
        $row[] = drupal_render($form[$id][$item]);
      }
    }
    $rows[] = $row;
  }
  $output .= theme('table', array(
    t('Provider'),
    t('Prefix method'),
    t('Key'),
  ), $rows);
  $output .= drupal_render($form);
  drupal_add_js(drupal_get_path("module", "context_prefix") . "/context_prefix_admin.js");
  return $output;
}

/**
 * API Functions ======================================================
 */

/**
 * Provides a simple API for validating, adding, and deleting context defintions.
 */
function context_prefix_api($op = 'insert', $context) {
  switch ($op) {
    case 'load':
      if (isset($context['provider'])) {
        if ($context['id']) {
          $context = db_fetch_array(db_query("SELECT * FROM {context_prefix} WHERE id = '%s' AND provider = '%s'", $context['id'], $context['provider']));
          if ($context) {
            return $context;
          }
        }
        else {
          if ($context['prefix']) {
            $context = db_fetch_array(db_query("SELECT * FROM {context_prefix} WHERE prefix = '%s' AND provider = '%s'", $context['prefix'], $context['provider']));
            if ($context) {
              return $context;
            }
          }
        }
        return false;
      }
      break;
    case 'validate':
      if (check_plain($context['provider']) && preg_match('!^[a-z0-9_-]+$!', $context['prefix'])) {
        $id = db_result(db_query("SELECT id FROM {context_prefix} WHERE prefix = '%s'", $context['prefix']));
        if ($id && $id == $context['id']) {
          return true;
        }
        else {
          if (!$id) {
            return true;
          }
        }
        return false;
      }
      else {
        return false;
      }
    case 'insert':
      if (context_prefix_api('validate', $context)) {
        $status = db_query("INSERT INTO {context_prefix} (provider, prefix, id) VALUES ('%s', '%s', %d)", $context['provider'], $context['prefix'], $context['id']);
        return $status;
      }
      return false;
    case 'update':
      if (context_prefix_api('validate', $context)) {
        $status = db_query("UPDATE {context_prefix} SET prefix = '%s' WHERE id = '%s' AND provider = '%s'", $context['prefix'], $context['id'], $context['provider']);
        return $status;
      }
    case 'delete':
      if ($context['prefix']) {
        $param = 'prefix';
        $where = $context['prefix'];
      }
      else {
        if ($context['id']) {
          $param = 'id';
          $where = $context['id'];
        }
      }
      $check = db_result(db_query("SELECT id FROM {context_prefix} WHERE provider = '%s' AND {$param} = '%s'", $context['provider'], $where));
      if ($check) {
        $status = db_query("DELETE FROM {context_prefix} WHERE provider = '%s' AND {$param} = '%s'", $context['provider'], $where);
        return $status;
      }
      return false;
  }
  return false;
}

/**
 * A wrapper around drupal_goto() that abstracts out the prefix/context setting
 * You provide both a normal drupal path ('node/43') and a context prefix ('dsi')
 * and context_prefix_goto will determine the correct location to use.
 */
function context_prefix_goto($provider, $id, $path = '', $query = NULL, $fragment = NULL, $http_response_code = 302) {

  /**
   * TODO: we need to abstract this base_url dissection into a
   * handler, and in there, we'll abstract out for
   * protocol handling, and handling the site's base_url like www.
   *
   * TODO: we need to make sure that other prefixed contexts don't
   * get dropped. e.g. if you are on 'en/node/43' and you
   * context_prefix_goto('spaces', 'mygroup'), you should end up
   * at 'en/mygroup', not 'mygroup'
   */
  $method = variable_get('context_prefix_method_' . $provider, CONTEXT_PREFIX_PATH);
  $prefixes = context_prefix_prefixes($method);
  switch ($method) {
    case CONTEXT_PREFIX_PATH:
      foreach ($prefixes as $key => $info) {
        if ($info['id'] == $id) {
          clswitch('set', true);

          // Drop prefixing for context_prefix goto's
          $path = $key . '/' . $path;
          break;
        }
      }
      break;
    case CONTEXT_PREFIX_PAIR:
      clswitch('set', true);
      $prefixes = array_keys($prefixes);
      $path = $prefixes[0] . '/' . $id . '/' . $path;
      break;
    case CONTEXT_PREFIX_DOMAIN:
      foreach ($prefixes as $key => $info) {
        if ($info['id'] == $id) {
          $path = 'http://' . $key . '/' . $path;
          break;
        }
      }
      break;
  }
  drupal_goto($path, $query, $fragment, $http_response_code);
}

/**
 * Custom l wrapper for links that need to leave all group contexts
 *
 * TODO: Like context_prefix_goto(), this function needs to allow the
 * selective dropping/adding of contexts.
 */
function cl($text, $path, $attributes = array(), $query = NULL, $fragment = NULL, $absolute = FALSE, $html = FALSE, $dropcontext = FALSE) {
  global $base_url;
  clswitch('set', $dropcontext);
  if (!$dropcontext && $path == '<front>') {
    $path = context_prefix_url_rewrite('alias', '', '');
  }

  // Handle domains -- need to force domain onto the path and push through as absolute url
  if ($dropcontext) {
    $absolute = TRUE;
    if ($path == '<front>') {
      $path = variable_get('site_frontpage', 'node');
    }
    if ($domain = variable_get('context_prefix_base_domain', '')) {
      $path = $domain . '/' . $path;

      // REPLACE BASE_URL with the hub domain.
    }
  }
  $l = l($text, $path, $attributes, $query, $fragment, $absolute, $html);
  clswitch('reset');
  return $l;
}

/**
 * Returns whether the current l/url call should use context rewriting or not
 */
function clswitch($op, $absolute = null) {
  static $drop;
  switch ($op) {
    case 'set':
      $drop = $absolute;
      break;
    case 'get':
      return $drop;
      break;
    case 'reset':
      $drop = null;
      break;
  }
}

/**
 * Like theme_links, but handles context warping.
 * theme_links couldn't believe it.
 */
function theme_context_links($links, $attributes = array(
  'class' => 'links',
)) {
  $output = '';
  if (count($links) > 0) {
    $output = '<ul' . drupal_attributes($attributes) . '>';
    $num_links = count($links);
    $i = 1;
    foreach ($links as $key => $link) {
      $class = '';

      // Automatically add a class to each link and also to each LI
      if (isset($link['attributes']) && isset($link['attributes']['class'])) {
        $link['attributes']['class'] .= ' ' . $key;
        $class = $key;
      }
      else {
        $link['attributes']['class'] = $key;
        $class = $key;
      }

      // Add active class for active menu items
      if (stristr($key, 'active')) {
        $class .= " active";
      }

      // Add first and last classes to the list of links to help out themers.
      $extra_class = '';
      if ($i == 1) {
        $extra_class .= 'first ';
      }
      if ($i == $num_links) {
        $extra_class .= 'last ';
      }
      $output .= '<li class="' . $extra_class . $class . '">';

      // Is the title HTML?
      $html = isset($link['html']) && $link['html'];

      // Initialize fragment and query variables.
      $link['query'] = isset($link['query']) ? $link['query'] : NULL;
      $link['fragment'] = isset($link['fragment']) ? $link['fragment'] : NULL;
      if (isset($link['href'])) {
        if ($link['warp']) {
          $output .= cl($link['title'], $link['href'], $link['attributes'], $link['query'], $link['fragment'], FALSE, $html, TRUE);
        }
        else {
          $output .= l($link['title'], $link['href'], $link['attributes'], $link['query'], $link['fragment'], FALSE, $html);
        }
      }
      else {
        if ($link['title']) {

          //Some links are actually not links, but we wrap these in <span> for adding title and class attributes
          if (!$html) {
            $link['title'] = check_plain($link['title']);
          }
          $output .= '<span' . drupal_attributes($link['attributes']) . '>' . $link['title'] . '</span>';
        }
      }
      $i++;
      $output .= "</li>\n";
    }
    $output .= '</ul>';
  }
  return $output;
}

/**
 * Generates a context prefix form element that can be dropped into a
 * FormAPI form array. Includes validation, but nsert/update must be
 * handled by the implementing submit handler.
 */
function context_prefix_form($provider, $id, $prefix = '') {
  switch (variable_get('context_prefix_method_' . $provider, CONTEXT_PREFIX_PATH)) {
    case CONTEXT_PREFIX_PATH:
    case CONTEXT_PREFIX_PAIR:
      $description = t('Choose a prefix path. May contain only lowercase letters, numbers, dashes and underscores. e.g. "my-prefix"');
      break;
    case CONTEXT_PREFIX_SUBDOMAIN:
      $description = t('Enter a domain registered for this context, such as "mygroup".  Do not include http://');
      break;
    case CONTEXT_PREFIX_DOMAIN:
      $description = t('Enter a domain registered for this context, such as "www.example.com".  Do not include http://');
      break;
  }
  $form = array(
    '#tree' => TRUE,
    '#validate' => array(
      'context_prefix_form_validate' => array(),
    ),
  );
  $form['prefix'] = array(
    '#title' => t('Path prefix'),
    '#type' => 'textfield',
    '#description' => $description,
    '#maxlength' => 255,
    '#required' => true,
    '#default_value' => $prefix,
  );
  $form['provider'] = array(
    '#type' => 'value',
    '#value' => $provider,
  );
  $form['id'] = array(
    '#type' => 'value',
    '#value' => $id,
  );
  return $form;
}

/**
 * Validation handler for context_prefix_form().
 */
function context_prefix_form_validate($form) {
  $definition = array(
    'provider' => $form['provider']['#value'],
    'prefix' => $form['prefix']['#value'],
    'id' => $form['id']['#value'],
  );
  if (!context_prefix_api('validate', $definition)) {
    form_set_error($form['#parents'][0], t('There was an error registering the prefix "@prefix". It is either invalid or is already taken. Please choose another.', array(
      '@prefix' => $form['prefix']['#value'],
    )));
    return false;
  }
  else {
    return true;
  }
}

/**
* Specialized cache for storing prefix information.
*/
class context_prefix_cache {
  protected $cache = array();
  function __construct() {
    $this->cache[CONTEXT_PREFIX_PATH] = array();
    $this->cache[CONTEXT_PREFIX_PAIR] = array();
    $this->cache[CONTEXT_PREFIX_SUBDOMAIN] = array();
    $this->cache[CONTEXT_PREFIX_DOMAIN] = array();
  }

  /**
   * @param $method
   *   The method to add to the cache for
   * @param $item
   *   Either a integer|string, or keyed array to add
   * @param $merge
   *   Preserve keys and merge into cache for method.
   */
  public function add($method, $item, $merge = true) {
    if (is_array($item) && $merge) {

      // Need to preserve keys so we use the '+' array operator.
      $this->cache[$method] = $this->cache[$method] + $item;
    }
    else {
      $this->cache[$method][] = $item;
    }
  }

  /**
   * @param $method
   *   The method to retrieve from the cache for.
   * @param $item
   *   Optionally and key of the required info.
   *
   * @return the desired info or false if an id doesn't exist.
   */
  public function get($method = false, $id = false) {
    if ($method !== false && $id !== false) {
      return isset($this->cache[$method][$id]) ? $this->cache[$method][$id] : false;
    }
    elseif ($method !== false) {
      return $this->cache[$method];
    }
    else {
      return $this->cache;
    }
  }

}

/**
 * Helper function, returns form options for prefix types.
 */
function _context_ui_options() {
  return array(
    CONTEXT_PREFIX_PATH => t('Path'),
    CONTEXT_PREFIX_PAIR => t('Keyed pair'),
    CONTEXT_PREFIX_DOMAIN => t('Full domain'),
  );
}

Functions

Namesort descending Description
cl Custom l wrapper for links that need to leave all group contexts
clswitch Returns whether the current l/url call should use context rewriting or not
context_prefix_admin Page callback for the context_prefix administration page.
context_prefix_api Provides a simple API for validating, adding, and deleting context defintions.
context_prefix_form Generates a context prefix form element that can be dropped into a FormAPI form array. Includes validation, but nsert/update must be handled by the implementing submit handler.
context_prefix_form_validate Validation handler for context_prefix_form().
context_prefix_get Get wrapper for _context_prefix_set()
context_prefix_goto A wrapper around drupal_goto() that abstracts out the prefix/context setting You provide both a normal drupal path ('node/43') and a context prefix ('dsi') and context_prefix_goto will determine the correct location to use.
context_prefix_init Implementation of hook_init() Checks for any valid context prefixes in request string and sets the context appropriately
context_prefix_menu Implementation of hook_menu().
context_prefix_parse Parses a query string of various types (url, domain, etc.) and returns an array of any found prefixes and their respective providers/id values.
context_prefix_prefixes Queries the database & modules for valid prefixes based on prefixing method.
context_prefix_providers Invokes hook_context_prefix_provider() to gather all providers.
context_prefix_set Set wrapper for _context_prefix_set()
context_prefix_settings_form Settings form for choosing the operating mode of context_prefix
context_prefix_unprefix Removes any prefixes from a query string. For path prefixes only.
context_prefix_url_rewrite Rewrites path with current context and removes context if searching for source path
theme_context_links Like theme_links, but handles context warping. theme_links couldn't believe it.
theme_context_prefix_settings_form Theme function for context_prefix_settings_form()
_context_prefix_get_normal_path Taken from i18n
_context_prefix_init Helper function to initialize, parse + set prefixed contexts.
_context_prefix_set Static cache function for setting + storing any prefixed contexts that are present on this page's request.
_context_ui_options Helper function, returns form options for prefix types.

Constants

Classes

Namesort descending Description
context_prefix_cache Specialized cache for storing prefix information.