context.module

Tracking 6.x-3.x branch
  1. drupal
    1. 6 contributions/context/context.module
    2. 7 contributions/context/context.module

Functions & methods

NameDescription
context_active_contextsLoads 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.
context_cache_getWrapper around cache_get() to make it easier for context to pull different datastores from a single cache row.
context_cache_setWrapper around cache_set() to make it easier for context to write different datastores to a single cache row.
context_clearClears static context array() -- meant only for testing
context_conditionsGet all context conditions.
context_condition_mapLoads an associative array of conditions => context identifiers to allow contexts to be set by different conditions.
context_condition_metQueue or activate contexts that have met the specified condition.
context_contextMaster context function. Avoid calling this directly -- use one of the helper functions below.
context_context_listCTools list callback for bulk export.
context_context_pluginsImplementation of hook_context_plugins().
context_context_registryImplementation of hook_context_registry().
context_ctools_plugin_pluginsImplementation of hook_ctools_plugin_plugins().
context_deleteDeletes an existing context.
context_emptyRecursive helper function to determine whether an array and its children are entirely empty.
context_enabled_contextsWrapper around context_load() that only returns enabled contexts.
context_existsDeprecated context_exists() function. Retained for backwards compatibility -- please use context_isset() instead.
context_exportExports the specified context.
context_flush_cachesImplementation of hook_flush_caches().
context_getRetrieves a context by namespace + (optional) attribute.
context_get_infoGet info for modules. @TODO: It really hurts that we have to do this. See a similar function in features.module and recognize that this should be in system.module but is not...
context_get_pluginGet a plugin handler.
context_initImplementation of hook_init().
context_invalidate_cacheInvalidates all context caches(). @TODO: Update to use a CTools API function for clearing plugin caches when/if it becomes available.
context_issetReturns a boolean for whether a context namespace + attribute have been set.
context_loadContext loader.
context_reactionsGet all context reactions.
context_saveInserts 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.
context_setSets a context by namespace + attribute.
_context_registryRetrieves & caches the context registry.

Constants

NameDescription
CONTEXT_CLEAR
CONTEXT_CONDITION_MODE_AND
CONTEXT_CONDITION_MODE_OR
CONTEXT_GET
CONTEXT_ISSET
CONTEXT_SET

File

View source
  1. <?php
  2. require('context.core.inc');
  3. define('CONTEXT_GET', 0);
  4. define('CONTEXT_SET', 1);
  5. define('CONTEXT_ISSET', 2);
  6. define('CONTEXT_CLEAR', 3);
  7. define('CONTEXT_CONDITION_MODE_OR', 0);
  8. define('CONTEXT_CONDITION_MODE_AND', 1);
  9. /**
  10. * Master context function. Avoid calling this directly -- use one of the helper functions below.
  11. *
  12. * @param $op
  13. * The operation to perform - handled by the context helper functions. Use them.
  14. * @param $namespace
  15. * A string to be used as the namespace for the context information.
  16. * @param $attribute
  17. * Usually a string to be used as a key to set/retrieve context information. An array can
  18. * also be used when setting context to establish an entire context namespace at once.
  19. * (At some point objects may also be accepted, but currently functionaliy isn't complete.)
  20. * @param $value
  21. * A value to set for the provided key. If omitted the value will be set to true.
  22. *
  23. * @return
  24. * Either the requested value, or false if the operation fails.
  25. */
  26. function context_context($op = CONTEXT_GET, $namespace = NULL, $attribute = NULL, $value = NULL) {
  27. static $context;
  28. $context = !$context ? array() : $context;
  29. switch ($op) {
  30. case CONTEXT_GET:
  31. // return entire context
  32. if (!$namespace) {
  33. return $context;
  34. }
  35. // return entire space if set
  36. else if (isset($context[(string) $namespace])) {
  37. // return val of key from space
  38. if (is_array($context[(string) $namespace]) && isset($context[(string) $namespace][(string) $attribute])) {
  39. return $context[(string) $namespace][(string) $attribute];
  40. }
  41. elseif (!$attribute) {
  42. return $context[(string) $namespace];
  43. }
  44. }
  45. break;
  46. case CONTEXT_SET:
  47. // bail if invalid space is specified or context is already set
  48. if (is_string($namespace) || is_int($namespace)) {
  49. // initialize namespace if no key is specified
  50. if (!$attribute) {
  51. $context[(string) $namespace] = array();
  52. return TRUE;
  53. }
  54. // set to true if key is a usable identifier. otherwise, allow a key or object to be inserted
  55. if ($value === NULL) {
  56. if (is_string($attribute) || is_int($attribute)) {
  57. $context[(string) $namespace][(string) $attribute] = TRUE;
  58. return TRUE;
  59. }
  60. elseif (is_array($attribute) || is_object($attribute)) {
  61. $context[(string) $namespace] = $attribute;
  62. return TRUE;
  63. }
  64. }
  65. // set value if key is valid
  66. if ((is_string($attribute) || is_int($attribute)) && $value !== NULL) {
  67. $context[$namespace][$attribute] = $value;
  68. return TRUE;
  69. }
  70. }
  71. break;
  72. case CONTEXT_ISSET:
  73. // return entire context
  74. if (!$namespace) return FALSE;
  75. if (!$attribute) {
  76. // return entire space if set
  77. return isset($context[$namespace]);
  78. }
  79. // return val of key from space
  80. return isset($context[$namespace][$attribute]);
  81. case CONTEXT_CLEAR:
  82. $context = array();
  83. return TRUE;
  84. }
  85. return FALSE;
  86. }
  87. /**
  88. * Sets a context by namespace + attribute.
  89. */
  90. function context_set($namespace, $attribute = NULL, $value = NULL) {
  91. return context_context(CONTEXT_SET, $namespace, $attribute, $value);
  92. }
  93. /**
  94. * Retrieves a context by namespace + (optional) attribute.
  95. */
  96. function context_get($namespace = NULL, $attribute = NULL) {
  97. return context_context(CONTEXT_GET, $namespace, $attribute, NULL);
  98. }
  99. /**
  100. * Returns a boolean for whether a context namespace + attribute have been set.
  101. */
  102. function context_isset($namespace = NULL, $attribute = NULL) {
  103. return context_context(CONTEXT_ISSET, $namespace, $attribute, NULL);
  104. }
  105. /**
  106. * Deprecated context_exists() function. Retained for backwards
  107. * compatibility -- please use context_isset() instead.
  108. */
  109. function context_exists($namespace = NULL, $attribute = NULL) {
  110. return context_context(CONTEXT_ISSET, $namespace, $attribute, NULL);
  111. }
  112. /**
  113. * Clears static context array() -- meant only for testing
  114. */
  115. function context_clear() {
  116. return context_context(CONTEXT_CLEAR);
  117. }
  118. /**
  119. * Implemented hooks ==================================================
  120. */
  121. /**
  122. * Implementation of hook_ctools_plugin_plugins().
  123. */
  124. function context_ctools_plugin_plugins() {
  125. return array(
  126. 'cache' => TRUE,
  127. 'use hooks' => TRUE,
  128. );
  129. }
  130. /**
  131. * Implementation of hook_context_plugins().
  132. *
  133. * This is a ctools plugins hook.
  134. */
  135. function context_context_plugins() {
  136. module_load_include('inc', 'context', 'context.plugins');
  137. return _context_context_plugins();
  138. }
  139. /**
  140. * Implementation of hook_context_registry().
  141. */
  142. function context_context_registry() {
  143. module_load_include('inc', 'context', 'context.plugins');
  144. return _context_context_registry();
  145. }
  146. /**
  147. * Implementation of hook_init().
  148. */
  149. function context_init() {
  150. if ($plugin = context_get_plugin('condition', 'path')) {
  151. $plugin->execute();
  152. }
  153. if ($plugin = context_get_plugin('condition', 'language')) {
  154. global $language;
  155. $plugin->execute($language->language);
  156. }
  157. if ($plugin = context_get_plugin('condition', 'user')) {
  158. global $user;
  159. $plugin->execute($user);
  160. }
  161. }
  162. /**
  163. * Load & crud functions ==============================================
  164. */
  165. /**
  166. * Context loader.
  167. *
  168. * @param $name
  169. * The name for this context object.
  170. *
  171. * @return
  172. * Returns a fully-loaded context definition.
  173. */
  174. function context_load($name = NULL, $reset = FALSE) {
  175. ctools_include('export');
  176. static $contexts;
  177. static $altered;
  178. if (!isset($contexts) || $reset) {
  179. $contexts = $altered = array();
  180. if (!$reset && $contexts = context_cache_get('context')) {
  181. // Nothing here.
  182. }
  183. else {
  184. if ($reset) {
  185. ctools_export_load_object_reset('context');
  186. }
  187. $contexts = ctools_export_load_object('context', 'all');
  188. context_cache_set('context', $contexts);
  189. }
  190. }
  191. if (isset($name)) {
  192. // Allow other modules to alter the value just before it's returned.
  193. if (isset($contexts[$name]) && !isset($altered[$name])) {
  194. $altered[$name] = TRUE;
  195. drupal_alter('context_load', $contexts[$name]);
  196. }
  197. return isset($contexts[$name]) ? $contexts[$name] : FALSE;
  198. }
  199. return $contexts;
  200. }
  201. /**
  202. * Inserts or updates a context object into the database.
  203. * @TODO: should probably return the new cid on success -- make sure
  204. * this doesn't break any checks elsewhere.
  205. *
  206. * @param $context
  207. * The context object to be inserted.
  208. *
  209. * @return
  210. * Returns true on success, false on failure.
  211. */
  212. function context_save($context) {
  213. $existing = context_load($context->name, TRUE);
  214. if ($existing && ($existing->export_type & EXPORT_IN_DATABASE)) {
  215. drupal_write_record('context', $context, 'name');
  216. }
  217. else {
  218. drupal_write_record('context', $context);
  219. }
  220. context_load(NULL, TRUE);
  221. context_invalidate_cache();
  222. return TRUE;
  223. }
  224. /**
  225. * Deletes an existing context.
  226. *
  227. * @param $context
  228. * The context object to be deleted.
  229. *
  230. * @return
  231. * Returns true on success, false on failure.
  232. */
  233. function context_delete($context) {
  234. if (isset($context->name) && ($context->export_type & EXPORT_IN_DATABASE)) {
  235. db_query("DELETE FROM {context} WHERE name = '%s'", $context->name);
  236. context_invalidate_cache();
  237. return TRUE;
  238. }
  239. return FALSE;
  240. }
  241. /**
  242. * Exports the specified context.
  243. */
  244. function context_export($context, $indent = '') {
  245. $output = ctools_export_object('context', $context, $indent);
  246. $translatables = array();
  247. foreach (array('description', 'tag') as $key) {
  248. if (!empty($context->{$key})) {
  249. $translatables[] = $context->{$key};
  250. }
  251. }
  252. $translatables = array_filter(array_unique($translatables));
  253. if (!empty($translatables)) {
  254. $output .= "\n";
  255. $output .= "{$indent}// Translatables\n";
  256. $output .= "{$indent}// Included for use with string extractors like potx.\n";
  257. sort($translatables);
  258. foreach ($translatables as $string) {
  259. $output .= "{$indent}t(" . ctools_var_export($string) . ");\n";
  260. }
  261. }
  262. return $output;
  263. }
  264. /**
  265. * API FUNCTIONS ======================================================
  266. */
  267. /**
  268. * CTools list callback for bulk export.
  269. */
  270. function context_context_list() {
  271. $contexts = context_load(NULL, TRUE);
  272. $list = array();
  273. foreach ($contexts as $context) {
  274. $list[$context->name] = $context->name;
  275. }
  276. return $list;
  277. }
  278. /**
  279. * Wrapper around cache_get() to make it easier for context to pull different
  280. * datastores from a single cache row.
  281. */
  282. function context_cache_get($key, $reset = FALSE) {
  283. static $cache;
  284. if (!isset($cache) || $reset) {
  285. $cache = cache_get('context', 'cache');
  286. $cache = $cache ? $cache->data : array();
  287. }
  288. return !empty($cache[$key]) ? $cache[$key] : FALSE;
  289. }
  290. /**
  291. * Wrapper around cache_set() to make it easier for context to write different
  292. * datastores to a single cache row.
  293. */
  294. function context_cache_set($key, $value) {
  295. $cache = cache_get('context', 'cache');
  296. $cache = $cache ? $cache->data : array();
  297. $cache[$key] = $value;
  298. cache_set('context', $cache);
  299. }
  300. /**
  301. * Wrapper around context_load() that only returns enabled contexts.
  302. */
  303. function context_enabled_contexts($reset = FALSE) {
  304. $enabled = array();
  305. foreach (context_load(NULL, $reset) as $context) {
  306. if (empty($context->disabled)) {
  307. $enabled[$context->name] = $context;
  308. }
  309. }
  310. return $enabled;
  311. }
  312. /**
  313. * Queue or activate contexts that have met the specified condition.
  314. *
  315. * @param $context
  316. * The context object to queue or activate.
  317. * @param $condition
  318. * String. Name for the condition that has been met.
  319. * @param $reset
  320. * Reset flag for the queue static cache.
  321. */
  322. function context_condition_met($context, $condition, $reset = FALSE) {
  323. static $queue;
  324. if (!isset($queue) || $reset) {
  325. $queue = array();
  326. }
  327. if (!context_isset('context', $context->name)) {
  328. // Context is using AND mode. Queue it.
  329. if (isset($context->condition_mode) && $context->condition_mode == CONTEXT_CONDITION_MODE_AND) {
  330. $queue[$context->name][$condition] = $condition;
  331. // If all conditions have been met. set the context.
  332. if (!array_diff(array_keys($context->conditions), $queue[$context->name])) {
  333. context_set('context', $context->name, $context);
  334. }
  335. }
  336. // Context is using OR mode. Set it.
  337. else {
  338. context_set('context', $context->name, $context);
  339. }
  340. }
  341. }
  342. /**
  343. * Loads any active contexts with associated reactions. This should be run
  344. * at a late stage of the page load to ensure that relevant contexts have been set.
  345. */
  346. function context_active_contexts() {
  347. $contexts = context_get('context');
  348. return !empty($contexts) && is_array($contexts) ? $contexts : array();
  349. }
  350. /**
  351. * Loads an associative array of conditions => context identifiers to allow
  352. * contexts to be set by different conditions.
  353. */
  354. function context_condition_map($reset = FALSE) {
  355. static $condition_map;
  356. if (!isset($condition_map) || $reset) {
  357. if (!$reset && $cache = context_cache_get('condition_map')) {
  358. $condition_map = $cache;
  359. }
  360. else {
  361. $condition_map = array();
  362. foreach (array_keys(context_conditions()) as $condition) {
  363. if ($plugin = context_get_plugin('condition', $condition)) {
  364. foreach (context_enabled_contexts() as $context) {
  365. $values = $plugin->fetch_from_context($context, 'values');
  366. foreach ($values as $value) {
  367. if (!isset($condition_map[$condition][$value])) {
  368. $condition_map[$condition][$value] = array();
  369. }
  370. $condition_map[$condition][$value][] = $context->name;
  371. }
  372. }
  373. }
  374. }
  375. context_cache_set('condition_map', $condition_map);
  376. }
  377. }
  378. return $condition_map;
  379. }
  380. /**
  381. * Invalidates all context caches().
  382. * @TODO: Update to use a CTools API function for clearing plugin caches
  383. * when/if it becomes available.
  384. */
  385. function context_invalidate_cache() {
  386. cache_clear_all('context', 'cache', TRUE);
  387. cache_clear_all('plugins:context', 'cache', TRUE);
  388. }
  389. /**
  390. * Implementation of hook_flush_caches().
  391. */
  392. function context_flush_caches() {
  393. context_invalidate_cache();
  394. }
  395. /**
  396. * Recursive helper function to determine whether an array and its
  397. * children are entirely empty.
  398. */
  399. function context_empty($element) {
  400. $empty = TRUE;
  401. if (is_array($element)) {
  402. foreach ($element as $child) {
  403. $empty = $empty && context_empty($child);
  404. }
  405. }
  406. else {
  407. $empty = $empty && empty($element);
  408. }
  409. return $empty;
  410. }
  411. /**
  412. * Get a plugin handler.
  413. */
  414. function context_get_plugin($type = 'condition', $key, $reset = FALSE) {
  415. static $cache = array();
  416. if (!isset($cache[$type][$key]) || $reset) {
  417. switch ($type) {
  418. case 'condition':
  419. $registry = context_conditions();
  420. break;
  421. case 'reaction':
  422. $registry = context_reactions();
  423. break;
  424. }
  425. if (isset($registry[$key], $registry[$key]['plugin'])) {
  426. ctools_include('plugins');
  427. $info = $registry[$key];
  428. $plugins = ctools_get_plugins('context', 'plugins');
  429. if (isset($plugins[$info['plugin']]) && $class = ctools_plugin_get_class($plugins[$info['plugin']], 'handler')) {
  430. $cache[$type][$key] = new $class($key, $info);
  431. }
  432. }
  433. }
  434. return isset($cache[$type][$key]) ? $cache[$type][$key] : FALSE;
  435. }
  436. /**
  437. * Get info for modules.
  438. * @TODO: It really hurts that we have to do this. See a similar function in
  439. * features.module and recognize that this should be in system.module but is not...
  440. */
  441. function context_get_info($type = NULL, $name = NULL, $reset = FALSE) {
  442. static $info;
  443. if (!isset($info) || $reset) {
  444. $result = db_query("SELECT name,type,info FROM {system}");
  445. while ($row = db_fetch_object($result)) {
  446. $info[$row->type][$row->name] = unserialize($row->info);
  447. }
  448. }
  449. if (isset($type, $name)) {
  450. return isset($info[$type][$name]) ? $info[$type][$name] : FALSE;
  451. }
  452. else if (isset($type)) {
  453. return isset($info[$type]) ? $info[$type] : FALSE;
  454. }
  455. return $info;
  456. }
  457. /**
  458. * Get all context conditions.
  459. */
  460. function context_conditions($reset = FALSE) {
  461. return _context_registry('conditions', $reset);
  462. }
  463. /**
  464. * Get all context reactions.
  465. */
  466. function context_reactions($reset = FALSE) {
  467. return _context_registry('reactions', $reset);
  468. }
  469. /**
  470. * Retrieves & caches the context registry.
  471. */
  472. function _context_registry($key = NULL, $reset = FALSE) {
  473. static $registry;
  474. if (!isset($registry) || $reset) {
  475. if (!$reset && $cache = context_cache_get('registry')) {
  476. $registry = $cache;
  477. }
  478. else {
  479. $registry = module_invoke_all('context_registry');
  480. drupal_alter('context_registry', $registry);
  481. context_cache_set('registry', $registry);
  482. }
  483. }
  484. if (isset($key)) {
  485. return isset($registry[$key]) ? $registry[$key] : array();
  486. }
  487. return $registry;
  488. }