array( 'arguments' => array('form' => NULL), ), 'context_links' => array( 'arguments' => array('links' => NULL, 'attributes' => array('class' => 'links')), ), ); } /** * Implementation of hook_menu(). */ function context_prefix_menu() { $items = array(); $items['admin/build/context/prefix'] = array( 'type' => module_exists('context_ui') ? MENU_LOCAL_TASK : MENU_NORMAL_ITEM, 'title' => t('Context prefix'), 'description' => t('Settings for context prefix.'), 'page callback' => 'drupal_get_form', 'page arguments' => array('context_prefix_settings_form'), 'access callback' => 'user_access', 'access argumnets' => array('administer site configuration'), 'weight' => 10, ); $items['admin/build/context/prefix/settings'] = array( 'type' => MENU_DEFAULT_LOCAL_TASK, 'title' => t('Settings'), 'page callback' => 'drupal_get_form', 'page arguments' => array('context_prefix_settings_form'), 'access callback' => 'user_access', 'access arguments' => array('administer site configuration'), 'weight' => 0, ); $items['admin/build/context/prefix/list'] = array( 'type' => MENU_LOCAL_TASK, 'title' => t('Registered prefixes'), 'page callback' => 'context_prefix_admin', 'access callback' => 'user_access', 'access arguments' => array('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'); } // pass the rest of the path onto Drupal cleanly 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_outbound')) { function custom_url_rewrite_outbound(&$path, &$options, $original) { return context_prefix_url_rewrite($path, $options, $original); } } /** * Rewrites path with current context and removes context if searching for source path */ function context_prefix_url_rewrite(&$path, &$options, $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')) { // 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; } $path = 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; } // Check alias without lang 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 .= "
". t('No context prefixes have been registered.') ."
"; } 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[] = "$name