| 1 |
<?php |
<?php |
| 2 |
// $Id: handler.module,v 1.11.2.4 2008/12/02 07:21:44 crell Exp $ |
// $Id: handler.module,v 1.11.2.5 2008/12/02 07:22:14 crell Exp $ |
| 3 |
|
|
| 4 |
/** |
/** |
| 5 |
* @file |
* @file |
| 10 |
* for a given context, which will be returned as an object that may be invoked. |
* for a given context, which will be returned as an object that may be invoked. |
| 11 |
*/ |
*/ |
| 12 |
|
|
|
/** |
|
|
* Include our additional libraries. |
|
|
* |
|
|
* These must be included before any hooks run, as some init hooks may depend |
|
|
* on them. |
|
|
*/ |
|
|
require_once(drupal_get_path('module', 'handler') .'/handler.environment.inc'); |
|
|
require_once(drupal_get_path('module', 'handler') .'/handler.classes.inc'); |
|
|
|
|
|
/** |
|
|
* Implementation of hook_init(). |
|
|
* |
|
|
* This is just for development. In practice we would only want to do this on |
|
|
* hook_flush_caches(), not every page load. |
|
|
*/ |
|
|
function handler_init() { |
|
|
handler_rebuild(); |
|
|
} |
|
|
|
|
|
/** |
|
|
* Implementation of hook_flush_caches(). |
|
|
*/ |
|
|
function handler_flush_caches() { |
|
|
handler_rebuild(); |
|
|
} |
|
|
|
|
|
/** |
|
|
* Rebuild the handler and slot registries. |
|
|
*/ |
|
|
function handler_rebuild() { |
|
|
$slots = handler_slot_build(); |
|
|
$handlers = handler_handler_build(); |
|
|
handler_lookup_build(); |
|
|
} |
|
|
|
|
|
/** |
|
|
* Rebuild the lookup table used for handler mapping. |
|
|
* |
|
|
*/ |
|
|
function handler_lookup_build() { |
|
|
|
|
|
$target_order = variable_get('handler_slot_targets', array()); |
|
|
|
|
|
// Now go through all the saved attachment directives and build out the lookup table. |
|
|
$result = db_query("SELECT slot_id, handler_id, targets FROM {handler_attachments}"); |
|
|
|
|
|
db_query("DELETE FROM {handler_lookup}"); |
|
|
|
|
|
while ($record = db_fetch_object($result)) { |
|
|
$record->targets = unserialize($record->targets); |
|
|
$fields = array( |
|
|
'slot' => $record->slot_id, |
|
|
'handler' => $record->handler_id, |
|
|
'specificity' => count($record->targets), |
|
|
'handler_class' => handler_load($record->slot_id, $record->handler_id)->class, |
|
|
); |
|
|
|
|
|
foreach ($record->targets as $target => $value) { |
|
|
// The target order array tracks the mapping of target key to db field. |
|
|
$fields[$target_order[$record->slot_id][$target]] = $value; |
|
|
} |
|
|
|
|
|
// Build the query. I want the D7 query builder! :-( |
|
|
$query_fields = implode(',', array_keys($fields)); |
|
|
$placeholders = implode(',', array_fill(0, count($fields), "'%s'")); |
|
|
$values = array_values($fields); |
|
|
|
|
|
// Insert this lookup record into the table. |
|
|
db_query("INSERT INTO {handler_lookup} ({$query_fields}) VALUES ({$placeholders})", $values); |
|
|
} |
|
|
|
|
|
// Now insert a record for the default handler for each slot. That way the |
|
|
// lookup routine can always find at least one record. |
|
|
$result = db_query("SELECT hsi.slot AS slot, hi.handler, class FROM {handler_info} hi INNER JOIN {handler_slot_info} hsi ON hi.slot=hsi.slot AND hi.handler=hsi.default_handler"); |
|
|
while ($record = db_fetch_array($result)) { |
|
|
// A 0 specificity will always match as a last case. |
|
|
$record[] = 0; |
|
|
db_query("INSERT INTO {handler_lookup} (slot, handler, handler_class, specificity) VALUES ('%s', '%s', '%s', %d)", $record); |
|
|
} |
|
|
} |
|
|
|
|
|
/** |
|
|
* Rebuild the handler info registry. |
|
|
* |
|
|
* @return |
|
|
* The array of handlers just defined. |
|
|
*/ |
|
|
function handler_handler_build() { |
|
|
|
|
|
$handlers = module_invoke_all('handler_info'); |
|
|
|
|
|
// Set default values, to avoid NULL issues if nothing else. |
|
|
foreach ($handlers as $slot => $handler_info) { |
|
|
foreach ($handler_info as $handler => $info) { |
|
|
$handlers[$slot][$handler] += handler_handler_defaults(); |
|
|
} |
|
|
} |
|
|
|
|
|
// Let other modules alter the handler registry if needed. |
|
|
drupal_alter('handler_info', $handlers); |
|
|
|
|
|
// Don't do the deletion until after we've gotten the new data. That reduces |
|
|
// the potential race condition window. |
|
|
db_query('DELETE FROM {handler_info}'); |
|
|
|
|
|
// Build the handler data. |
|
|
foreach ($handlers as $slot => $handler_info) { |
|
|
foreach ($handler_info as $handler => $info) { |
|
|
db_query("INSERT INTO {handler_info} (handler, slot, title, class, description) |
|
|
VALUES ('%s', '%s', '%s', '%s', '%s')", |
|
|
array($handler, $slot, $info['title'], $info['class'], $info['description']) |
|
|
); |
|
|
} |
|
|
} |
|
|
|
|
|
return $handlers ; |
|
|
} |
|
|
|
|
|
|
|
|
/** |
|
|
* Rebuild the handler slot info registry. |
|
|
* |
|
|
* @return |
|
|
* The array of slots just declared. |
|
|
*/ |
|
|
function handler_slot_build() { |
|
|
|
|
|
$slots = module_invoke_all('handler_slot_info'); |
|
|
|
|
|
// Set default values, to avoid NULL issues if nothing else. |
|
|
foreach ($slots as $slot => $info) { |
|
|
$slots[$slot] += handler_slot_defaults(); |
|
|
} |
|
|
|
|
|
// Let other modules alter the handler target registry if needed. |
|
|
drupal_alter('handler_slot_info', $slots); |
|
|
|
|
|
// Don't do the deletion until after we've gotten the new data. That reduces |
|
|
// the potential race condition window. |
|
|
db_query('DELETE FROM {handler_slot_info}'); |
|
|
|
|
|
$target_order = array(); |
|
|
|
|
|
// Build the target data. |
|
|
foreach ($slots as $slot => $info) { |
|
|
db_query("INSERT INTO {handler_slot_info} (slot, title, interface, factory, default_handler, targets, description) |
|
|
VALUES ('%s', '%s', '%s', '%s', '%s', '%s', '%s')", |
|
|
array($slot, $info['title'], $info['interface'], $info['factory'], $info['default_handler'], serialize($info['targets']), $info['description']) |
|
|
); |
|
|
|
|
|
// Determine the order of all possible targets, as this will be the order |
|
|
// used in the database. |
|
|
$targets = array_keys($info['targets']); |
|
|
ksort($targets); |
|
|
$i = 1; |
|
|
foreach ($targets as $target) { |
|
|
$target_order[$slot][$target] = 't'. $i++; |
|
|
} |
|
|
} |
|
|
|
|
|
variable_set('handler_slot_targets', $target_order); |
|
|
|
|
|
return $slots; |
|
|
} |
|
|
|
|
|
/** |
|
|
* Define various default values for handler slots. |
|
|
* |
|
|
* @return |
|
|
* The default "empty" slot definition. |
|
|
*/ |
|
|
function handler_slot_defaults() { |
|
|
return array( |
|
|
'slot' => '', |
|
|
'title' => '', |
|
|
'interface' => 'HandlerInterface', |
|
|
'factory' => 'handler_factory_generic', |
|
|
'default_handler' => 'default', |
|
|
'targets' => array(), |
|
|
'description' => '', |
|
|
); |
|
|
} |
|
|
|
|
|
/** |
|
|
* Define various default values for handlers. |
|
|
* |
|
|
* @return |
|
|
* The default "empty" handler definition. |
|
|
*/ |
|
|
function handler_handler_defaults() { |
|
|
return array( |
|
|
'handler' => '', |
|
|
'slot' => '', |
|
|
'title' => '', |
|
|
'class' => '', |
|
|
'description' => '', |
|
|
); |
|
|
} |
|
|
|
|
|
/** |
|
|
* Main handler entry-point. |
|
|
* |
|
|
* This function should be called in most instances in place of a factory |
|
|
* function. It will automatically route the request to the appropriate |
|
|
* factory. |
|
|
* |
|
|
* @param $slot_id |
|
|
* The internal ID of the slot for which we want to retrieve a handler. |
|
|
* @param $options |
|
|
* The options array determines which handler object should be used, depending |
|
|
* on the current configuration. |
|
|
* @return |
|
|
* The handler object required. |
|
|
*/ |
|
|
function handler($slot_id, $options = array()) { |
|
|
$function = handler_get_factory($slot_id); |
|
|
if (function_exists($function)) { |
|
|
return $function($options, $slot_id); |
|
|
} |
|
| 13 |
|
|
|
return NULL; |
|
|
} |
|
| 14 |
|
|
| 15 |
/** |
/** |
| 16 |
* Returns the factory function for a given target. |
* @ingroup handlers |
| 17 |
* |
* @{ |
|
* If no factory is defined or the function does not exist, a generic |
|
|
* factory is returned instead. |
|
|
* |
|
|
* @param $slot_id |
|
|
* The internal ID of the target. |
|
|
* @return |
|
|
* The name of the factory function as a string. |
|
| 18 |
*/ |
*/ |
|
function handler_get_factory($slot_id) { |
|
|
|
|
|
$slot = handler_slot_load($slot_id); |
|
|
|
|
|
return ($slot->factory && function_exists($slot->factory)) ? $slot->factory : 'handler_factory_generic'; |
|
|
} |
|
|
|
|
|
/** |
|
|
* Load function for slot info objects. |
|
|
* |
|
|
* @param $slot_id |
|
|
* The internal slot ID. |
|
|
* @param $refresh |
|
|
* If this is set to TRUE, the internal slot cache will be flushed. |
|
|
* @return |
|
|
* The slot object or NULL if it is not defined. |
|
|
*/ |
|
|
function handler_slot_load($slot_id, $refresh = FALSE) { |
|
|
static $slots; |
|
|
|
|
|
if ($refresh) { |
|
|
$slots = array(); |
|
|
} |
|
|
|
|
|
if (empty($slots[$slot_id])) { |
|
|
$slot = db_fetch_object(db_query("SELECT slot, title, interface, factory, default_handler, targets, description FROM {handler_slot_info} WHERE slot='%s'", array($slot_id))); |
|
|
$slot->targets = unserialize($slot->targets); |
|
|
$slots[$slot_id] = $slot; |
|
|
} |
|
|
|
|
|
return $slots[$slot_id]; |
|
|
} |
|
| 19 |
|
|
| 20 |
/** |
/** |
| 21 |
* Load function for handler info objects. |
* Request a handler object. |
| 22 |
* |
* |
| 23 |
* @param $slot_id |
* @param $slot_id |
| 24 |
* The internal slot ID. All handlers are namespaced within their slot. |
* The machine-readable name of the slot the handler belongs to. |
| 25 |
* @param $handler_id |
* @param $target |
| 26 |
* The internal handler ID. |
* The target inside the subsytem the handler belongs to. |
| 27 |
* @param $refresh |
* @param $reset |
| 28 |
* If this is set to TRUE, the internal handler cache will be flushed. |
* If this is set to TRUE, the internal caches are flushed. Internal use |
| 29 |
* @return |
* only. |
| 30 |
* The handler object or NULL if not defined. |
* |
| 31 |
*/ |
* @return |
| 32 |
function handler_load($slot_id, $handler_id, $refresh = FALSE) { |
* The associated handler object. |
| 33 |
static $handlers; |
* |
| 34 |
|
* @see hook_slot_info() |
| 35 |
if ($refresh) { |
* @see hook_handler_info() |
| 36 |
$handlers = array(); |
*/ |
| 37 |
} |
function handler($slot_id, $target = 'default', $reset = FALSE) { |
| 38 |
|
// $handler_mappings is an array, keyed by $slot_id and $target and the |
| 39 |
if (empty($handlers[$handler_id])) { |
// values are arrays containing class names and a boolean indicating |
| 40 |
$handler = db_fetch_object(db_query("SELECT handler, slot, title, class, description FROM {handler_info} WHERE slot='%s' AND handler='%s'", array($slot_id, $handler_id))); |
// reusability. handler_objects keeps the objects themselves. |
| 41 |
$handlers[$handler_id] = $handler; |
// $default_only[$slot_id] is TRUE if the given slot only uses defaults. |
| 42 |
|
static $handler_mappings, $handler_objects, $default_only; |
| 43 |
|
|
| 44 |
|
// We have to reset the target cache after a new handler has been attached |
| 45 |
|
// or detached. |
| 46 |
|
if ($reset) { |
| 47 |
|
$handler_mappings = array(); |
| 48 |
|
$handler_objects = array(); |
| 49 |
|
$default_only = array(); |
| 50 |
|
return; |
| 51 |
|
} |
| 52 |
|
|
| 53 |
|
// If we already have the appropriate handler cached, just use that. |
| 54 |
|
if (!empty($handler_objects[$slot_id][$target])) { |
| 55 |
|
return $handler_objects[$slot_id][$target]; |
| 56 |
|
} |
| 57 |
|
|
| 58 |
|
// While the objects need to be stored per target, the classnames can be per |
| 59 |
|
// slot, if the only attached handler is attached to default. That includes |
| 60 |
|
// any slot that does not make use of targets. We cache the handler |
| 61 |
|
// information for these slots in the variable system to reduce database |
| 62 |
|
// lookups. Because the variable system doesn't auto-initialize in |
| 63 |
|
// variable_get(), any handler lookup that runs before the variable system |
| 64 |
|
// has been initialized will simply fail this check and use the database |
| 65 |
|
// anyway. |
| 66 |
|
$mapping_target = isset($default_only[$slot_id]) ? 'default' : $target; |
| 67 |
|
// Look up the class for the requested slot/target. |
| 68 |
|
if (empty($handler_mappings[$slot_id][$mapping_target])) { |
| 69 |
|
// If the only attached handler is attached to default, |
| 70 |
|
if ($record = variable_get('handler_default_' . $slot_id, array())) { |
| 71 |
|
$default_only[$slot_id] = TRUE; |
| 72 |
|
$mapping_target = 'default'; |
| 73 |
|
} |
| 74 |
|
else { |
| 75 |
|
// Try to get the associated handler. If the first query finds an associated |
| 76 |
|
// handler, we use that. If not, the second query will always find the |
| 77 |
|
// default handler. By UNIONing them together we get the fallback default |
| 78 |
|
// behavior without having to issue a second request to the database. |
| 79 |
|
$record = db_query_range("SELECT class, reuse FROM {handler_attachments} WHERE slot = :slot_1 AND target = :target |
| 80 |
|
UNION SELECT class, reuse FROM {handler_attachments} WHERE slot = :slot_2 AND target = 'default'", array( |
| 81 |
|
':slot_1' => $slot_id, |
| 82 |
|
':slot_2' => $slot_id, |
| 83 |
|
':target' => $target, |
| 84 |
|
), 0, 1)->fetchAssoc(); |
| 85 |
|
|
| 86 |
|
// It's possible that this function will be called before the handler system |
| 87 |
|
// has first been initialized. That's especially the case for early-running |
| 88 |
|
// systems such as cache or path, as they operate during the bootstrap phase. |
| 89 |
|
// If we have no record at all, we first rebuild the registry and then try |
| 90 |
|
// again. That should at least always give us the slot-defined default |
| 91 |
|
// and allow the system to proceed. |
| 92 |
|
if (!$record) { |
| 93 |
|
registry_rebuild(); |
| 94 |
|
handlers_rebuild(); |
| 95 |
|
$record = db_query_range("SELECT class, reuse FROM {handler_attachments} WHERE slot = :slot_1 AND target = :target |
| 96 |
|
UNION SELECT class, reuse FROM {handler_attachments} WHERE slot = :slot_2 AND target = 'default'", array( |
| 97 |
|
':slot_1' => $slot_id, |
| 98 |
|
':slot_2' => $slot_id, |
| 99 |
|
':target' => $target, |
| 100 |
|
), 0, 1)->fetchAssoc(); |
| 101 |
|
} |
| 102 |
|
} |
| 103 |
|
// Statically cache the lookup information so that we don't need to check |
| 104 |
|
// for it again. |
| 105 |
|
$handler_mappings[$slot_id][$mapping_target] = $record; |
| 106 |
|
} |
| 107 |
|
|
| 108 |
|
// Create a new handler object. |
| 109 |
|
$handler = new $handler_mappings[$slot_id][$mapping_target]['class']($target); |
| 110 |
|
|
| 111 |
|
// Cache the handler object for later use, if flagged to do so. |
| 112 |
|
if ($handler_mappings[$slot_id][$mapping_target]['reuse']) { |
| 113 |
|
$handler_objects[$slot_id][$target] = $handler; |
| 114 |
} |
} |
| 115 |
|
return $handler; |
|
|
|
|
return $handlers[$handler_id]; |
|
| 116 |
} |
} |
| 117 |
|
|
| 118 |
/** |
/** |
| 119 |
* The generic handler factory. |
* Rebuild the handler and slot registries. |
|
* |
|
|
* In most cases, this factory will be sufficient for handlers that do not |
|
|
* need a new object generated on each call. |
|
|
* |
|
|
* @param $options |
|
|
* The options array determines which handler object should be used, depending |
|
|
* on the current configuration. |
|
|
* @param $slot_id |
|
|
* The slot we are handling. |
|
|
* @return |
|
|
* The handler object required. |
|
| 120 |
*/ |
*/ |
| 121 |
function handler_factory_generic(Array $options = array(), $slot_id) { |
function handlers_rebuild() { |
| 122 |
|
require_once DRUPAL_ROOT . '/includes/handlers.inc'; |
| 123 |
static $handlers; |
handler_slot_rebuild(); |
| 124 |
|
handler_handler_rebuild(); |
| 125 |
static $env; |
handler_ensure_defaults(); |
|
|
|
|
// We only need one environment variable in the default case. |
|
|
if (empty($env)) { |
|
|
$env = new EnvironmentDefault(); |
|
|
} |
|
|
|
|
|
$class = handler_get_registered_handler($slot_id, $options); |
|
|
|
|
|
// If we haven't already created this handler, instantiate a new object for it. |
|
|
if (empty($handlers[$class])) { |
|
|
$handler = new $class(); |
|
|
$handler->setEnvironment($env); |
|
|
|
|
|
$handlers[$class] = $handler; |
|
|
} |
|
|
|
|
|
return $handlers[$class]; |
|
| 126 |
} |
} |
| 127 |
|
|
| 128 |
/** |
/** |
| 129 |
* Derive the handler class for the specified target. |
* Interface for all handler classes for any slot. |
| 130 |
* |
* |
| 131 |
* @param $target_id |
* This is a very thin interface, but does serve to help standardize handler |
| 132 |
* The internal ID of the target. |
* behavior and provides a way to type-check a handler object. Interfaces for |
| 133 |
* @param $targets |
* specific slots should extend this interface. |
|
* The array of targets to help route this handler request. If it does not |
|
|
* have a value specified for every target, it will be filled in with the |
|
|
* slot-defined defaults. |
|
|
* @return |
|
|
* The name of the class that should be loaded for this |
|
|
* target/option configuration. |
|
| 134 |
*/ |
*/ |
| 135 |
function handler_get_registered_handler($slot_id, $targets) { |
interface HandlerInterface { |
|
|
|
|
// We maintain an alphabetical order in the lookup table so that everything |
|
|
// matches up properly. |
|
|
ksort($targets); |
|
|
|
|
|
$sql = "SELECT handler_class FROM {handler_lookup} WHERE "; |
|
|
|
|
|
$index = 1; |
|
|
$where = array(); |
|
|
$values = array(); |
|
|
foreach ($targets as $target => $value) { |
|
|
$field = 't'. $index++; |
|
|
$where[] = '('. $field ."='%s' OR ". $field .' IS NULL)'; |
|
|
$values[] = $value; |
|
|
} |
|
|
$where[] = 'specificity <= %d'; |
|
|
$values[] = count($targets); |
|
|
$sql .= implode(' AND ', $where); |
|
|
|
|
|
// This last check will always match the default |
|
|
$sql .= ' OR specificity = 0'; |
|
|
|
|
|
$sql .= " ORDER BY specificity DESC"; |
|
|
|
|
|
$class = db_result(db_query_range($sql, $values, 0, 1)); |
|
|
|
|
|
return $class; |
|
|
|
|
|
/* |
|
|
$mapping = handler_slot_mapping($slot_id); |
|
| 136 |
|
|
| 137 |
$targets += handler_default_targets($slot_id); |
/** |
| 138 |
|
* Constructor |
| 139 |
// Because we need to traverse down the options array somehow, we normalize |
* |
| 140 |
// the array order to alphabetic by the option key. That allows us to walk |
* @param $target |
| 141 |
// the array in a standardized order. |
* The target for which this handler is being called. Some handlers may |
| 142 |
ksort($options); |
* require this information in order to route commands properly. |
| 143 |
$handler_id = &$mapping; |
*/ |
| 144 |
foreach ($options as $option => $value) { |
function __construct($target = 'default'); |
|
if (isset($handler_id[$value])) { |
|
|
$handler_id = &$handler_id[$value]; |
|
|
} |
|
|
else { |
|
|
$slot = handler_target_load($slot_id); |
|
|
$handler_id = $slot->default_handler; |
|
|
break; |
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
$handler = handler_load($handler_id); |
|
|
|
|
|
return $handler->class; |
|
|
*/ |
|
|
} |
|
|
|
|
|
function handler_slot_mapping($slot_id) { |
|
|
|
|
|
$mapping = db_result(db_query("SELECT mapping FROM {handler_mapping} WHERE target='%s'", array($target_id))); |
|
|
|
|
|
if ($mapping) { |
|
|
$mapping = unserialize($mapping); |
|
|
} |
|
|
else { |
|
|
$mapping = array(); |
|
|
} |
|
|
|
|
|
return $mapping; |
|
| 145 |
} |
} |
| 146 |
|
|
| 147 |
/** |
/** |
| 148 |
* Asociate a given handler to a give slot for the specified targets. |
* Base implementation of a handler object. |
| 149 |
* |
* |
| 150 |
* @param $slot_id |
* Simple handler objects may choose to inherit from a base class in order to |
| 151 |
* The internal ID of the slot. |
* not reimplement routine functionality. Alternatively they may simply implement |
| 152 |
* @param $handler_id |
* the appropriate interface and implement their own version of common |
| 153 |
* The internal ID of the hand |
* functionality. Both methods are acceptable depending on the use case. |
|
* @param $options |
|
|
* The array of options |
|
| 154 |
*/ |
*/ |
| 155 |
function handler_attach($slot_id, $handler_id, $targets) { |
abstract class HandlerBase implements HandlerInterface { |
|
|
|
|
db_query("INSERT INTO {handler_attachments} (slot_id, handler_id, targets) VALUES ('%s', '%s', '%s')", array( |
|
|
$slot_id, $handler_id, serialize($targets) |
|
|
)); |
|
|
|
|
|
/* |
|
|
$mapping = db_result(db_query("SELECT mapping FROM {handler_mapping} WHERE slot='%s'", array($slot_id))); |
|
|
|
|
|
$is_new = FALSE; |
|
|
if ($mapping) { |
|
|
$mapping = unserialize($mapping); |
|
|
} |
|
|
else { |
|
|
$mapping = array(); |
|
|
$is_new = TRUE; |
|
|
} |
|
|
|
|
|
$options += handler_default_options($slot_id); |
|
| 156 |
|
|
| 157 |
ksort($options); |
/** |
| 158 |
$map_point = &$mapping; |
* The target for which this handler is active. |
| 159 |
foreach ($options as $key => $value) { |
*/ |
| 160 |
if (empty($map_point[$value])) { |
protected $target; |
|
$map_point[$value] = array(); |
|
|
} |
|
|
$map_point = &$map_point[$value]; |
|
|
} |
|
|
|
|
|
$map_point = $handler_id; |
|
| 161 |
|
|
| 162 |
// It would be nicer do a delete/insert cycle, but that would result in a race |
function __construct($target = 'default') { |
| 163 |
// condition. What we really want here is a merge query, but those will have |
$this->target = $target; |
|
// to wait until Drupal 7. |
|
|
if ($is_new) { |
|
|
db_query("INSERT INTO {handler_mapping} (slot, mapping) VALUES ('%s', '%s')", array($slot_id, serialize($mapping))); |
|
| 164 |
} |
} |
|
else { |
|
|
db_query("UPDATE {handler_mapping} SET mapping='%s' WHERE slot='%s'", array(serialize($mapping), $slot_id)); |
|
|
} |
|
|
*/ |
|
| 165 |
} |
} |
| 166 |
|
|
| 167 |
/** |
/** |
| 168 |
* Get the default targets for a given slot. |
* @} End of "ingroup handlers". |
|
* |
|
|
* @param $slot_id |
|
|
* The internal ID of the slot. |
|
|
* @return |
|
|
* An associative array of the default targets for the specified slot. |
|
| 169 |
*/ |
*/ |
|
function handler_default_targets($slot_id) { |
|
|
$slot = handler_slot_load($slot_id); |
|
|
|
|
|
return $slot->targets; |
|
|
} |
|
|
|
|