| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619 | <?phprequire('context.core.inc');define('CONTEXT_GET', 0);define('CONTEXT_SET', 1);define('CONTEXT_ISSET', 2);define('CONTEXT_CLEAR', 3);define('CONTEXT_CONDITION_MODE_OR', 0);define('CONTEXT_CONDITION_MODE_AND', 1);/** * Master context function. Avoid calling this directly -- use one of the helper functions below. * * @param $op *   The operation to perform - handled by the context helper functions. Use them. * @param $namespace *   A string to be used as the namespace for the context information. * @param $attribute *   Usually a string to be used as a key to set/retrieve context information. An array can *   also be used when setting context to establish an entire context namespace at once. *   (At some point objects may also be accepted, but currently functionaliy isn't complete.) * @param $value *   A value to set for the provided key. If omitted the value will be set to true. * * @return *   Either the requested value, or false if the operation fails. */function context_context($op = CONTEXT_GET, $namespace = NULL, $attribute = NULL, $value = NULL) {  static $context;  $context = !$context ? array() : $context;  switch ($op) {    case CONTEXT_GET:      // return entire context      if (!$namespace) {        return $context;      }      // return entire space if set      elseif (isset($context[(string) $namespace])) {        // return val of key from space        if (is_array($context[(string) $namespace]) && isset($context[(string) $namespace][(string) $attribute])) {          return $context[(string) $namespace][(string) $attribute];        }        elseif (!$attribute) {          return $context[(string) $namespace];        }      }      break;    case CONTEXT_SET:      // bail if invalid space is specified or context is already set      if (is_string($namespace) || is_int($namespace)) {        // initialize namespace if no key is specified        if (!$attribute) {          $context[(string) $namespace] = array();          return TRUE;        }        // set to true if key is a usable identifier. otherwise, allow a key or object to be inserted        if ($value === NULL) {          if (is_string($attribute) || is_int($attribute)) {            $context[(string) $namespace][(string) $attribute] = TRUE;            return TRUE;          }          elseif (is_array($attribute) || is_object($attribute)) {            $context[(string) $namespace] = $attribute;            return TRUE;          }        }        // set value if key is valid        if ((is_string($attribute) || is_int($attribute)) && $value !== NULL) {          $context[$namespace][$attribute] = $value;          return TRUE;        }      }      break;    case CONTEXT_ISSET:      // return entire context      if (!$namespace) return FALSE;      if (!$attribute) {        // return entire space if set        return isset($context[$namespace]);      }      // return val of key from space      return isset($context[$namespace][$attribute]);    case CONTEXT_CLEAR:      $context = array();      return TRUE;  }  return FALSE;}/** * Sets a context by namespace + attribute. */function context_set($namespace, $attribute = NULL, $value = NULL) {  return context_context(CONTEXT_SET, $namespace, $attribute, $value);}/** * Retrieves a context by namespace + (optional) attribute. */function context_get($namespace = NULL, $attribute = NULL) {  return context_context(CONTEXT_GET, $namespace, $attribute, NULL);}/** * Returns a boolean for whether a context namespace + attribute have been set. */function context_isset($namespace = NULL, $attribute = NULL) {  return context_context(CONTEXT_ISSET, $namespace, $attribute, NULL);}/** * Deprecated context_exists() function. Retained for backwards * compatibility -- please use context_isset() instead. */function context_exists($namespace = NULL, $attribute = NULL) {  return context_context(CONTEXT_ISSET, $namespace, $attribute, NULL);}/** * Clears static context array() -- meant only for testing */function context_clear() {  return context_context(CONTEXT_CLEAR);}/** * Implemented hooks ================================================== *//** * Implementation of hook_ctools_plugin_type(). */function context_ctools_plugin_type() {  return array(    'plugins' => array(      'cache' => TRUE,      'use hooks' => TRUE,      'classes' => array('handler'),    ),  );}/** * Implementation of hook_context_plugins(). * * This is a ctools plugins hook. */function context_context_plugins() {  module_load_include('inc', 'context', 'context.plugins');  return _context_context_plugins();}/** * Implementation of hook_context_registry(). */function context_context_registry() {  module_load_include('inc', 'context', 'context.plugins');  return _context_context_registry();}/** * Implementation of hook_init(). */function context_init() {  if ($plugin = context_get_plugin('condition', 'sitewide')) {    $plugin->execute(1);  }  if ($plugin = context_get_plugin('condition', 'path')) {    $plugin->execute();  }  if ($plugin = context_get_plugin('condition', 'query_string')) {    $plugin->execute();  }  if ($plugin = context_get_plugin('condition', 'language')) {    global $language;    $plugin->execute($language->language);  }  if ($plugin = context_get_plugin('condition', 'user')) {    global $user;    $plugin->execute($user);  }}/** * Implementation of hook_preprocess_menu_link(). * * This allows menus that are not primary/secondary menus to get * the "active" class assigned to them. This assumes they are using * theme('menu_link') for the menu rendering to html. */function context_preprocess_menu_link(&$variables) {  if ($contexts = context_active_contexts()) {    foreach ($contexts as $context) {      if (isset($context->reactions['menu'])) {        // In context module < v3.2 the url was a string. In version 3.3+ this is        // an array of urls. Implement interims BC layer.        //        // Examples:        // - OLD < v3.2 context reaction structure:        // array('menu' => 'taxonomy/term/1')        //        // - NEW 3.3+ context reaction structure:        // array(        //   'menu' => array(        //     0 => 'navigation:taxonomy/term/1'        //     1 => 'foo-menu:taxonomy/term/1'        //   )        // )        $reactions_menu = is_array($context->reactions['menu']) ? array_values($context->reactions['menu']) : array($context->reactions['menu']);        // Get everything after the first ':' character (if found) as the url to        // match against element '#href'.        $urls = array();        foreach ($reactions_menu as $url) {          if (strpos($url, ':') !== FALSE) {            // Get unique menu name 'navigation' from 'navigation:taxonomy/term/1'            $reaction_menu = explode(':', $url);            $path = $reaction_menu[1];            $urls[$path] = $reaction_menu[0];          }          else {            // BC layer for menu contexts that have not re-saved. This is for            // urls like 'taxonomy/term/1'. We need to add a fake menu key            // 'bc-context-menu-layer' or the BC link get's removed by            // array_intersect below.            //            // @TODO: Remove BC layer in 4.x            $urls[$url] = 'context-reaction-menu-bc-layer';          }        }        // Filter urls by the menu name of the current link. The link reaction        // can be configured per menu link in specific menus and the contect        // reaction should not applied to other menus with the same menu link.        $menu_name = $variables['element']['#original_link']['menu_name'];        $menu_paths = array_intersect($urls, array($menu_name, 'context-reaction-menu-bc-layer'));        $reaction_menu_paths = array_keys($menu_paths);        // - If menu href and context reaction menu url match, add the 'active'        //   css class to the link of this menu.        // - Do not add class twice on current page.        if (in_array($variables['element']['#href'], $reaction_menu_paths) && $variables['element']['#href'] != $_GET['q']) {          // Do not add the 'active' class twice in views tabs.          if (!in_array('active', $variables['element']['#localized_options']['attributes']['class'])) {            $variables['element']['#localized_options']['attributes']['class'][] = 'active';          }        }      }    }  }}/** * Load & crud functions ============================================== *//** * Context loader. * * @param $name *   The name for this context object. * * @return *   Returns a fully-loaded context definition. */function context_load($name = NULL, $reset = FALSE) {  ctools_include('export');  static $contexts;  static $altered;  if (!isset($contexts) || $reset) {    $contexts = $altered = array();    if (!$reset && $contexts = context_cache_get('context')) {      // Nothing here.    }    else {      if ($reset) {        ctools_export_load_object_reset('context');      }      $contexts = ctools_export_load_object('context', 'all');      context_cache_set('context', $contexts);    }  }  if (isset($name)) {    // Allow other modules to alter the value just before it's returned.    if (isset($contexts[$name]) && !isset($altered[$name])) {      $altered[$name] = TRUE;      drupal_alter('context_load', $contexts[$name]);    }    return isset($contexts[$name]) ? $contexts[$name] : FALSE;  }  return $contexts;}/** * Inserts or updates a context object into the database. * @TODO: should probably return the new cid on success -- make sure * this doesn't break any checks elsewhere. * * @param $context *   The context object to be inserted. * * @return *   Returns true on success, false on failure. */function context_save($context) {  $existing = context_load($context->name, TRUE);  if ($existing && ($existing->export_type & EXPORT_IN_DATABASE)) {    drupal_write_record('context', $context, 'name');  }  else {    drupal_write_record('context', $context);  }  context_load(NULL, TRUE);  context_invalidate_cache();  return TRUE;}/** * Deletes an existing context. * * @param $context *   The context object to be deleted. * * @return *   Returns true on success, false on failure. */function context_delete($context) {  if (isset($context->name) && ($context->export_type & EXPORT_IN_DATABASE)) {    db_query("DELETE FROM {context} WHERE name = :name", array(':name' => $context->name));    context_invalidate_cache();    return TRUE;  }  return FALSE;}/** * Exports the specified context. */function context_export($context, $indent = '') {  $output = ctools_export_object('context', $context, $indent);  $translatables = array();  foreach (array('description', 'tag') as $key) {    if (!empty($context->{$key})) {      $translatables[] = $context->{$key};    }  }  $translatables = array_filter(array_unique($translatables));  if (!empty($translatables)) {    $output .= "\n";    $output .= "{$indent}// Translatables\n";    $output .= "{$indent}// Included for use with string extractors like potx.\n";    sort($translatables);    foreach ($translatables as $string) {      $output .= "{$indent}t(" . ctools_var_export($string) . ");\n";    }  }  return $output;}/** * API FUNCTIONS ====================================================== *//** * CTools list callback for bulk export. */function context_context_list() {  $contexts = context_load(NULL, TRUE);  $list = array();  foreach ($contexts as $context) {    $list[$context->name] = $context->name;  }  return $list;}/** * Wrapper around cache_get() to make it easier for context to pull different * datastores from a single cache row. */function context_cache_get($key, $reset = FALSE) {  static $cache;  if (!isset($cache) || $reset) {    $cache = cache_get('context', 'cache');    $cache = $cache ? $cache->data : array();  }  return !empty($cache[$key]) ? $cache[$key] : FALSE;}/** * Wrapper around cache_set() to make it easier for context to write different * datastores to a single cache row. */function context_cache_set($key, $value) {  $cache = cache_get('context', 'cache');  $cache = $cache ? $cache->data : array();  $cache[$key] = $value;  cache_set('context', $cache);}/** * Wrapper around context_load() that only returns enabled contexts. */function context_enabled_contexts($reset = FALSE) {  $enabled = array();  foreach (context_load(NULL, $reset) as $context) {    if (empty($context->disabled)) {      $enabled[$context->name] = $context;    }  }  return $enabled;}/** * Queue or activate contexts that have met the specified condition. * * @param $context *   The context object to queue or activate. * @param $condition *   String. Name for the condition that has been met. * @param $reset *   Reset flag for the queue static cache. */function context_condition_met($context, $condition, $reset = FALSE) {  static $queue;  if (!isset($queue) || $reset) {    $queue = array();  }  if (!context_isset('context', $context->name)) {    // Context is using AND mode. Queue it.    if (isset($context->condition_mode) && $context->condition_mode == CONTEXT_CONDITION_MODE_AND) {      $queue[$context->name][$condition] = $condition;      // If all conditions have been met. set the context.      if (!array_diff(array_keys($context->conditions), $queue[$context->name])) {        context_set('context', $context->name, $context);      }    }    // Context is using OR mode. Set it.    else {      context_set('context', $context->name, $context);    }  }}/** * Loads any active contexts with associated reactions. This should be run * at a late stage of the page load to ensure that relevant contexts have been set. */function context_active_contexts() {  $contexts = context_get('context');  return !empty($contexts) && is_array($contexts) ? $contexts : array();}/** * Loads an associative array of conditions => context identifiers to allow * contexts to be set by different conditions. */function context_condition_map($reset = FALSE) {  static $condition_map;  if (!isset($condition_map) || $reset) {    if (!$reset && $cache = context_cache_get('condition_map')) {      $condition_map = $cache;    }    else {      $condition_map = array();      foreach (array_keys(context_conditions()) as $condition) {        if ($plugin = context_get_plugin('condition', $condition)) {          foreach (context_enabled_contexts() as $context) {            $values = $plugin->fetch_from_context($context, 'values');            foreach ($values as $value) {              if (!isset($condition_map[$condition][$value])) {                $condition_map[$condition][$value] = array();              }              $condition_map[$condition][$value][] = $context->name;            }          }        }      }      context_cache_set('condition_map', $condition_map);    }  }  return $condition_map;}/** * Invalidates all context caches(). * @TODO: Update to use a CTools API function for clearing plugin caches * when/if it becomes available. */function context_invalidate_cache() {  cache_clear_all('context', 'cache', TRUE);  cache_clear_all('plugins:context', 'cache', TRUE);}/** * Implementation of hook_flush_caches(). */function context_flush_caches() {  context_invalidate_cache();}/** * Recursive helper function to determine whether an array and its * children are entirely empty. */function context_empty($element) {  $empty = TRUE;  if (is_array($element)) {    foreach ($element as $child) {      $empty = $empty && context_empty($child);    }  }  else {    $empty = $empty && !isset($element);  }  return $empty;}/** * Get a plugin handler. */function context_get_plugin($type = 'condition', $key, $reset = FALSE) {  static $cache = array();  if (!isset($cache[$type][$key]) || $reset) {    switch ($type) {      case 'condition':        $registry = context_conditions();        break;      case 'reaction':        $registry = context_reactions();        break;    }    if (isset($registry[$key], $registry[$key]['plugin'])) {      ctools_include('plugins');      $info = $registry[$key];      $plugins = ctools_get_plugins('context', 'plugins');      if (isset($plugins[$info['plugin']]) && $class = ctools_plugin_get_class($plugins[$info['plugin']], 'handler')) {        // Check that class exists until CTools & registry issues are resolved.        if (class_exists($class)) {          $cache[$type][$key] = new $class($key, $info);        }      }    }  }  return isset($cache[$type][$key]) ? $cache[$type][$key] : FALSE;}/** * Get all context conditions. */function context_conditions($reset = FALSE) {  return _context_registry('conditions', $reset);}/** * Get all context reactions. */function context_reactions($reset = FALSE) {  return _context_registry('reactions', $reset);}/** * Retrieves & caches the context registry. */function _context_registry($key = NULL, $reset = FALSE) {  static $registry;  if (!isset($registry) || $reset) {    if (!$reset && $cache = context_cache_get('registry')) {      $registry = $cache;    }    else {      $registry = module_invoke_all('context_registry');      drupal_alter('context_registry', $registry);      context_cache_set('registry', $registry);    }  }  if (isset($key)) {    return isset($registry[$key]) ? $registry[$key] : array();  }  return $registry;}/** * hook_block_view_alter - if the context editor block is on this page, * ensure that all blocks have some content so that empty blocks are * not dropped */function context_block_view_alter(&$data, $block) {  if (context_isset('context_ui', 'context_ui_editor_present') && empty($data['content'])) {    $data['content']['#markup'] = "<div class='context-block-empty-content'>" . t('This block appears empty when displayed on this page.') . "</div>";    $data['context_block_hidden'] = TRUE;  }}/** * implement hook_page_alter() * * used for region context */function context_page_alter(&$page) {  if ($plugin = context_get_plugin('reaction', 'region')) {    $plugin->execute($page);  }}/** * hook_block_view_alter - if the context editor block is on this page, * ensure that all blocks have some content so that empty blocks are * not dropped */function context_preprocess_block(&$vars) {  if (isset($vars['block']->context_block_hidden)) {    $vars['classes_array'][] = 'context-block-hidden';    $vars['classes_array'][] = 'context-block-empty';  }}
 |