context.module

Go to the documentation of this file.
00001 <?php
00002 
00003 require('context.core.inc');
00004 
00005 define('CONTEXT_GET', 0);
00006 define('CONTEXT_SET', 1);
00007 define('CONTEXT_ISSET', 2);
00008 define('CONTEXT_CLEAR', 3);
00009 
00010 define('CONTEXT_CONDITION_MODE_OR', 0);
00011 define('CONTEXT_CONDITION_MODE_AND', 1);
00012 
00013 /**
00014  * Master context function. Avoid calling this directly -- use one of the helper functions below.
00015  *
00016  * @param $op
00017  *   The operation to perform - handled by the context helper functions. Use them.
00018  * @param $namespace
00019  *   A string to be used as the namespace for the context information.
00020  * @param $attribute
00021  *   Usually a string to be used as a key to set/retrieve context information. An array can
00022  *   also be used when setting context to establish an entire context namespace at once.
00023  *   (At some point objects may also be accepted, but currently functionaliy isn't complete.)
00024  * @param $value
00025  *   A value to set for the provided key. If omitted the value will be set to true.
00026  *
00027  * @return
00028  *   Either the requested value, or false if the operation fails.
00029  */
00030 function context_context($op = CONTEXT_GET, $namespace = NULL, $attribute = NULL, $value = NULL) {
00031   static $context;
00032   $context = !$context ? array() : $context;
00033   switch ($op) {
00034     case CONTEXT_GET:
00035       // return entire context
00036       if (!$namespace) {
00037         return $context;
00038       }
00039       // return entire space if set
00040       elseif (isset($context[(string) $namespace])) {
00041         // return val of key from space
00042         if (is_array($context[(string) $namespace]) && isset($context[(string) $namespace][(string) $attribute])) {
00043           return $context[(string) $namespace][(string) $attribute];
00044         }
00045         elseif (!$attribute) {
00046           return $context[(string) $namespace];
00047         }
00048       }
00049       break;
00050     case CONTEXT_SET:
00051       // bail if invalid space is specified or context is already set
00052       if (is_string($namespace) || is_int($namespace)) {
00053         // initialize namespace if no key is specified
00054         if (!$attribute) {
00055           $context[(string) $namespace] = array();
00056           return TRUE;
00057         }
00058         // set to true if key is a usable identifier. otherwise, allow a key or object to be inserted
00059         if ($value === NULL) {
00060           if (is_string($attribute) || is_int($attribute)) {
00061             $context[(string) $namespace][(string) $attribute] = TRUE;
00062             return TRUE;
00063           }
00064           elseif (is_array($attribute) || is_object($attribute)) {
00065             $context[(string) $namespace] = $attribute;
00066             return TRUE;
00067           }
00068         }
00069         // set value if key is valid
00070         if ((is_string($attribute) || is_int($attribute)) && $value !== NULL) {
00071           $context[$namespace][$attribute] = $value;
00072           return TRUE;
00073         }
00074       }
00075       break;
00076     case CONTEXT_ISSET:
00077       // return entire context
00078       if (!$namespace) return FALSE;
00079       if (!$attribute) {
00080         // return entire space if set
00081         return isset($context[$namespace]);
00082       }
00083       // return val of key from space
00084       return isset($context[$namespace][$attribute]);
00085     case CONTEXT_CLEAR:
00086       $context = array();
00087       return TRUE;
00088   }
00089   return FALSE;
00090 }
00091 
00092 /**
00093  * Sets a context by namespace + attribute.
00094  */
00095 function context_set($namespace, $attribute = NULL, $value = NULL) {
00096   return context_context(CONTEXT_SET, $namespace, $attribute, $value);
00097 }
00098 
00099 /**
00100  * Retrieves a context by namespace + (optional) attribute.
00101  */
00102 function context_get($namespace = NULL, $attribute = NULL) {
00103   return context_context(CONTEXT_GET, $namespace, $attribute, NULL);
00104 }
00105 
00106 /**
00107  * Returns a boolean for whether a context namespace + attribute have been set.
00108  */
00109 function context_isset($namespace = NULL, $attribute = NULL) {
00110   return context_context(CONTEXT_ISSET, $namespace, $attribute, NULL);
00111 }
00112 
00113 /**
00114  * Deprecated context_exists() function. Retained for backwards
00115  * compatibility -- please use context_isset() instead.
00116  */
00117 function context_exists($namespace = NULL, $attribute = NULL) {
00118   return context_context(CONTEXT_ISSET, $namespace, $attribute, NULL);
00119 }
00120 
00121 /**
00122  * Clears static context array() -- meant only for testing
00123  */
00124 function context_clear() {
00125   return context_context(CONTEXT_CLEAR);
00126 }
00127 
00128 /**
00129  * Implemented hooks ==================================================
00130  */
00131 
00132 /**
00133  * Implementation of hook_ctools_plugin_type().
00134  */
00135 function context_ctools_plugin_type() {
00136   return array(
00137     'plugins' => array(
00138       'cache' => TRUE,
00139       'use hooks' => TRUE,
00140       'classes' => array('handler'),
00141     ),
00142   );
00143 }
00144 
00145 /**
00146  * Implementation of hook_context_plugins().
00147  *
00148  * This is a ctools plugins hook.
00149  */
00150 function context_context_plugins() {
00151   module_load_include('inc', 'context', 'context.plugins');
00152   return _context_context_plugins();
00153 }
00154 
00155 
00156 /**
00157  * Implementation of hook_context_registry().
00158  */
00159 function context_context_registry() {
00160   module_load_include('inc', 'context', 'context.plugins');
00161   return _context_context_registry();
00162 }
00163 
00164 /**
00165  * Implementation of hook_init().
00166  */
00167 function context_init() {
00168   if ($plugin = context_get_plugin('condition', 'path')) {
00169     $plugin->execute();
00170   }
00171   if ($plugin = context_get_plugin('condition', 'language')) {
00172     global $language;
00173     $plugin->execute($language->language);
00174   }
00175   if ($plugin = context_get_plugin('condition', 'user')) {
00176     global $user;
00177     $plugin->execute($user);
00178   }
00179 }
00180 
00181 /**
00182  * Implementation of hook_preprocess_menu_link().
00183  *
00184  * This allows menus that are not primary/secondary menus to get
00185  * the "active" class assigned to them. This assumes they are using
00186  * theme('menu_link') for the menu rendering to html.
00187  */
00188 function context_preprocess_menu_link(&$variables) {
00189   if($contexts = context_active_contexts()){
00190     foreach($contexts as $context){
00191       if((isset($context->reactions['menu']))){
00192         if ($variables['element']['#href'] == $context->reactions['menu']) {
00193           $variables['element']['#localized_options']['attributes']['class'][] = "active";
00194         }
00195       }
00196     }
00197   }
00198 }
00199 
00200 /**
00201  * Load & crud functions ==============================================
00202  */
00203 
00204 /**
00205  * Context loader.
00206  *
00207  * @param $name
00208  *   The name for this context object.
00209  *
00210  * @return
00211  *   Returns a fully-loaded context definition.
00212  */
00213 function context_load($name = NULL, $reset = FALSE) {
00214   ctools_include('export');
00215   static $contexts;
00216   static $altered;
00217   if (!isset($contexts) || $reset) {
00218     $contexts = $altered = array();
00219     if (!$reset && $contexts = context_cache_get('context')) {
00220       // Nothing here.
00221     }
00222     else {
00223       if ($reset) {
00224         ctools_export_load_object_reset('context');
00225       }
00226       $contexts = ctools_export_load_object('context', 'all');
00227       context_cache_set('context', $contexts);
00228     }
00229   }
00230   if (isset($name)) {
00231     // Allow other modules to alter the value just before it's returned.
00232     if (isset($contexts[$name]) && !isset($altered[$name])) {
00233       $altered[$name] = TRUE;
00234       drupal_alter('context_load', $contexts[$name]);
00235     }
00236     return isset($contexts[$name]) ? $contexts[$name] : FALSE;
00237   }
00238   return $contexts;
00239 }
00240 
00241 /**
00242  * Inserts or updates a context object into the database.
00243  * @TODO: should probably return the new cid on success -- make sure
00244  * this doesn't break any checks elsewhere.
00245  *
00246  * @param $context
00247  *   The context object to be inserted.
00248  *
00249  * @return
00250  *   Returns true on success, false on failure.
00251  */
00252 function context_save($context) {
00253   $existing = context_load($context->name, TRUE);
00254   if ($existing && ($existing->export_type & EXPORT_IN_DATABASE)) {
00255     drupal_write_record('context', $context, 'name');
00256   }
00257   else {
00258     drupal_write_record('context', $context);
00259   }
00260   context_load(NULL, TRUE);
00261   context_invalidate_cache();
00262   return TRUE;
00263 }
00264 
00265 /**
00266  * Deletes an existing context.
00267  *
00268  * @param $context
00269  *   The context object to be deleted.
00270  *
00271  * @return
00272  *   Returns true on success, false on failure.
00273  */
00274 function context_delete($context) {
00275   if (isset($context->name) && ($context->export_type & EXPORT_IN_DATABASE)) {
00276     db_query("DELETE FROM {context} WHERE name = :name", array(':name' => $context->name));
00277     context_invalidate_cache();
00278     return TRUE;
00279   }
00280   return FALSE;
00281 }
00282 
00283 /**
00284  * Exports the specified context.
00285  */
00286 function context_export($context, $indent = '') {
00287   $output = ctools_export_object('context', $context, $indent);
00288   $translatables = array();
00289   foreach (array('description', 'tag') as $key) {
00290     if (!empty($context->{$key})) {
00291       $translatables[] = $context->{$key};
00292     }
00293   }
00294   $translatables = array_filter(array_unique($translatables));
00295   if (!empty($translatables)) {
00296     $output .= "\n";
00297     $output .= "{$indent}// Translatables\n";
00298     $output .= "{$indent}// Included for use with string extractors like potx.\n";
00299     sort($translatables);
00300     foreach ($translatables as $string) {
00301       $output .= "{$indent}t(" . ctools_var_export($string) . ");\n";
00302     }
00303   }
00304   return $output;
00305 }
00306 
00307 /**
00308  * API FUNCTIONS ======================================================
00309  */
00310 
00311 /**
00312  * CTools list callback for bulk export.
00313  */
00314 function context_context_list() {
00315   $contexts = context_load(NULL, TRUE);
00316   $list = array();
00317   foreach ($contexts as $context) {
00318     $list[$context->name] = $context->name;
00319   }
00320   return $list;
00321 }
00322 
00323 /**
00324  * Wrapper around cache_get() to make it easier for context to pull different
00325  * datastores from a single cache row.
00326  */
00327 function context_cache_get($key, $reset = FALSE) {
00328   static $cache;
00329   if (!isset($cache) || $reset) {
00330     $cache = cache_get('context', 'cache');
00331     $cache = $cache ? $cache->data : array();
00332   }
00333   return !empty($cache[$key]) ? $cache[$key] : FALSE;
00334 }
00335 
00336 /**
00337  * Wrapper around cache_set() to make it easier for context to write different
00338  * datastores to a single cache row.
00339  */
00340 function context_cache_set($key, $value) {
00341   $cache = cache_get('context', 'cache');
00342   $cache = $cache ? $cache->data : array();
00343   $cache[$key] = $value;
00344   cache_set('context', $cache);
00345 }
00346 
00347 /**
00348  * Wrapper around context_load() that only returns enabled contexts.
00349  */
00350 function context_enabled_contexts($reset = FALSE) {
00351   $enabled = array();
00352   foreach (context_load(NULL, $reset) as $context) {
00353     if (empty($context->disabled)) {
00354       $enabled[$context->name] = $context;
00355     }
00356   }
00357   return $enabled;
00358 }
00359 
00360 /**
00361  * Queue or activate contexts that have met the specified condition.
00362  *
00363  * @param $context
00364  *   The context object to queue or activate.
00365  * @param $condition
00366  *   String. Name for the condition that has been met.
00367  * @param $reset
00368  *   Reset flag for the queue static cache.
00369  */
00370 function context_condition_met($context, $condition, $reset = FALSE) {
00371   static $queue;
00372   if (!isset($queue) || $reset) {
00373     $queue = array();
00374   }
00375   if (!context_isset('context', $context->name)) {
00376     // Context is using AND mode. Queue it.
00377     if (isset($context->condition_mode) && $context->condition_mode == CONTEXT_CONDITION_MODE_AND) {
00378       $queue[$context->name][$condition] = $condition;
00379 
00380       // If all conditions have been met. set the context.
00381       if (!array_diff(array_keys($context->conditions), $queue[$context->name])) {
00382         context_set('context', $context->name, $context);
00383       }
00384     }
00385     // Context is using OR mode. Set it.
00386     else {
00387       context_set('context', $context->name, $context);
00388     }
00389   }
00390 }
00391 
00392 /**
00393  * Loads any active contexts with associated reactions. This should be run
00394  * at a late stage of the page load to ensure that relevant contexts have been set.
00395  */
00396 function context_active_contexts() {
00397   $contexts = context_get('context');
00398   return !empty($contexts) && is_array($contexts) ? $contexts : array();
00399 }
00400 
00401 /**
00402  * Loads an associative array of conditions => context identifiers to allow
00403  * contexts to be set by different conditions.
00404  */
00405 function context_condition_map($reset = FALSE) {
00406   static $condition_map;
00407   if (!isset($condition_map) || $reset) {
00408     if (!$reset && $cache = context_cache_get('condition_map')) {
00409       $condition_map = $cache;
00410     }
00411     else {
00412       $condition_map = array();
00413       foreach (array_keys(context_conditions()) as $condition) {
00414         if ($plugin = context_get_plugin('condition', $condition)) {
00415           foreach (context_enabled_contexts() as $context) {
00416             $values = $plugin->fetch_from_context($context, 'values');
00417             foreach ($values as $value) {
00418               if (!isset($condition_map[$condition][$value])) {
00419                 $condition_map[$condition][$value] = array();
00420               }
00421               $condition_map[$condition][$value][] = $context->name;
00422             }
00423           }
00424         }
00425       }
00426       context_cache_set('condition_map', $condition_map);
00427     }
00428   }
00429   return $condition_map;
00430 }
00431 
00432 /**
00433  * Invalidates all context caches().
00434  * @TODO: Update to use a CTools API function for clearing plugin caches
00435  * when/if it becomes available.
00436  */
00437 function context_invalidate_cache() {
00438   cache_clear_all('context', 'cache', TRUE);
00439   cache_clear_all('plugins:context', 'cache', TRUE);
00440 }
00441 
00442 /**
00443  * Implementation of hook_flush_caches().
00444  */
00445 function context_flush_caches() {
00446   context_invalidate_cache();
00447 }
00448 
00449 /**
00450  * Recursive helper function to determine whether an array and its
00451  * children are entirely empty.
00452  */
00453 function context_empty($element) {
00454   $empty = TRUE;
00455   if (is_array($element)) {
00456     foreach ($element as $child) {
00457       $empty = $empty && context_empty($child);
00458     }
00459   }
00460   else {
00461     $empty = $empty && empty($element);
00462   }
00463   return $empty;
00464 }
00465 
00466 /**
00467  * Get a plugin handler.
00468  */
00469 function context_get_plugin($type = 'condition', $key, $reset = FALSE) {
00470   static $cache = array();
00471   if (!isset($cache[$type][$key]) || $reset) {
00472     switch ($type) {
00473       case 'condition':
00474         $registry = context_conditions();
00475         break;
00476       case 'reaction':
00477         $registry = context_reactions();
00478         break;
00479     }
00480     if (isset($registry[$key], $registry[$key]['plugin'])) {
00481       ctools_include('plugins');
00482       $info = $registry[$key];
00483       $plugins = ctools_get_plugins('context', 'plugins');
00484       if (isset($plugins[$info['plugin']]) && $class = ctools_plugin_get_class($plugins[$info['plugin']], 'handler')) {
00485         // Check that class exists until CTools & registry issues are resolved.
00486         if (class_exists($class)) {
00487           $cache[$type][$key] = new $class($key, $info);
00488         }
00489       }
00490     }
00491   }
00492   return isset($cache[$type][$key]) ? $cache[$type][$key] : FALSE;
00493 }
00494 
00495 /**
00496  * Get all context conditions.
00497  */
00498 function context_conditions($reset = FALSE) {
00499   return _context_registry('conditions', $reset);
00500 }
00501 
00502 /**
00503  * Get all context reactions.
00504  */
00505 function context_reactions($reset = FALSE) {
00506   return _context_registry('reactions', $reset);
00507 }
00508 
00509 /**
00510  * Retrieves & caches the context registry.
00511  */
00512 function _context_registry($key = NULL, $reset = FALSE) {
00513   static $registry;
00514   if (!isset($registry) || $reset) {
00515     if (!$reset && $cache = context_cache_get('registry')) {
00516       $registry = $cache;
00517     }
00518     else {
00519       $registry = module_invoke_all('context_registry');
00520       drupal_alter('context_registry', $registry);
00521       context_cache_set('registry', $registry);
00522     }
00523   }
00524   if (isset($key)) {
00525     return isset($registry[$key]) ? $registry[$key] : array();
00526   }
00527   return $registry;
00528 }
00529 
00530 /**
00531  * hook_block_view_alter - if the context editor block is on this page,
00532  * ensure that all blocks have some content so that empty blocks are
00533  * not dropped
00534  */
00535 function context_block_view_alter(&$data, $block) {
00536   if (context_isset('context_ui', 'context_ui_editor_present') && empty($data['content'])) {
00537     $data['content']['#markup'] = "<div class='context-block-empty-content'>" . t('This block appears empty when displayed on this page.') . "</div>";
00538     $data['context_block_hidden'] = TRUE;
00539   }
00540 }
00541 
00542 /**
00543  * implement hook_page_alter()
00544  *
00545  * used for region context
00546  */
00547 function context_page_alter(&$page) {
00548   if ($plugin = context_get_plugin('reaction', 'region')) {
00549     $plugin->execute($page);
00550   }
00551 }
00552 
00553 /**
00554  * hook_block_view_alter - if the context editor block is on this page,
00555  * ensure that all blocks have some content so that empty blocks are
00556  * not dropped
00557  */
00558 function context_preprocess_block(&$vars) {
00559   if (isset($vars['block']->context_block_hidden)) {
00560     $vars['classes_array'][] = 'context-block-hidden';
00561     $vars['classes_array'][] = 'context-block-empty';
00562   }
00563 }

Generated on Tue May 21 02:23:48 2013 for Context by  doxygen 1.4.7