564 lines
16 KiB
Plaintext
564 lines
16 KiB
Plaintext
<?php
|
|
|
|
require('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', 'path')) {
|
|
$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']))){
|
|
if ($variables['element']['#href'] == $context->reactions['menu']) {
|
|
$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 && empty($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';
|
|
}
|
|
}
|