function configuration_context_process_property in Configuration Management 6
Process a single mapping config property. Various properties will mark static data that will be processed later on in the configuration phases.
Parameters
$property: The property needing processed
$value: The value of the property
$context: The context area of the data to process with this property
$config: The config this property=>value pair is a part of
3 calls to configuration_context_process_property()
- configuration_apply_map in ./
configuration.module - Apply an individual configuration map to the data set object
- configuration_find_attributes in ./
configuration.module - Helper function to convert tags to attributes
- _configuration_replace_tokens in ./
configuration.module - Helper function to replace key/values using tokens
File
- ./
configuration.module, line 649 - Provide a unified method for defining site configurations abstracted from their data format. Various data formats should be supported via a plugin architecture such as XML, YAML, JSON, PHP
Code
function configuration_context_process_property($property, $value, &$context, &$config = array()) {
$empty = $context->empty;
// This is a list of properties that can take an empty match
$empty_properties = array(
'#alias',
'#required',
'#create',
'#default',
'#default callback',
'#default php',
'#default path',
'#default value',
);
// This is a list of properties that do not modify the context object
// which will save any integrity checks later on
$no_modify_propertiers = array(
'#include',
'#action',
'#action callback',
'#required',
'#options',
'#options callback',
);
// If this is an empty context and not in the empty property list, return immediately
if ($empty && !in_array($property, $empty_properties)) {
return;
}
switch ($property) {
case '#include':
$file = './' . $value;
if (!is_file($file)) {
configuration_set_error('pre-validate: include', array(
'!file' => $file,
));
}
else {
@(require_once $file);
$context->include = $file;
}
break;
case '#alias':
// TODO Figure out how to deal with the $matches array syncing with new matches here
if ($empty) {
if (is_scalar($value)) {
$value = array(
$value,
);
}
foreach ($value as $alias) {
// Find the alias, if it exists rename it
if (array_key_exists($alias, $context->parent->item)) {
// Find the alias context
for ($i = 0; isset($context->parent->children[$i]); $i++) {
$change =& $context->parent->children[$i];
if ($change->key == $alias) {
configuration_context_process_property('#key', $context->key, $change, $config);
break 2;
}
}
}
}
}
// Deal with secondary keys here. No need to check if it already exists
// since they can exist multiple times
for ($i = 0; isset($context->parent->children[$i]); $i++) {
$check =& $context->parent->children[$i];
if (($pos = in_array($check->secondary_key, $value)) !== false) {
$check->secondary_key = $context->secondary_key;
}
}
break;
case '#default callback':
if ($empty) {
if (is_array($value)) {
$args = reset($value);
$value = key($value);
}
if (function_exists($value)) {
if (isset($args)) {
$context->parent->item[$context->key] = call_user_func_array($value, $args);
}
else {
$context->parent->item[$context->key] = $value($context);
}
$context->empty = false;
}
}
break;
case '#default php':
if ($empty) {
// Make sure it is set and then get the default and reset it to that
$context->parent->item[$context->key] = null;
$php = $value;
$value =& $context->parent->item[$context->key];
$new = eval($php);
if (isset($new)) {
$context->parent->item[$context->key] = $new;
}
$context->empty = false;
}
break;
case '#default path':
if ($empty && ($matches = configuration_fetch($value, $context)) && count($matches) == 1) {
$context->parent->item[$context->key] = $matches[0]->item;
$context->empty = false;
}
break;
case '#default':
case '#default value':
case '#create':
if ($empty) {
// TODO Think about converting all other context keys to ->_ like ->_parent ->_item
if ($context->_attribute) {
$context->item = $value;
}
else {
$context->parent->item[$context->key] = $value;
$context->item =& $context->parent->item[$context->key];
}
$context->empty = false;
}
break;
case '#key callback':
if (function_exists($value)) {
$value = $value($context->item);
}
else {
configuration_set_error(t('An invalid callback was specified: !callback', array(
'!callback' => $value,
)));
break;
}
case '#key path':
if ($property == '#key path') {
if (is_array($value)) {
$path = key($value);
$default = current($value);
}
else {
$path = $value;
}
$match = configuration_fetch($path, $context);
if (count($match) == 1 && is_scalar($match[0]->item)) {
$value = $match[0]->item;
}
else {
if ($config['#key default']) {
$value = $config['#key default'];
}
else {
break;
}
}
}
case '#key php':
if ($property == '#key php') {
$value = eval($value);
}
break;
case '#key':
if (array_key_exists($value, $context->parent->item)) {
// Key exists already
// TODO Is it a problem that the key exists already? Quite possibly....
break;
}
$key = $context->key;
$context->parent->item[$value] =& $context->item;
// We need to keep our current context object. check_context should fix the trace paths below
$context->key = $value;
// A plain unset is sufficient even with indexed arrays because check_context will pick it up and fix
unset($context->parent->item[$key]);
break;
case '#array':
// TODO Figure out how to deal with associative vs indexed arrays
if (!is_array($context->item) || !array_key_exists(0, $context->item)) {
if (is_null($context->item) || is_array($context->item && empty($context->item))) {
$context->item = array();
}
else {
$context->item = array(
$context->item,
);
}
}
break;
case '#assoc':
if (!is_array($value) || array_key_exists(0, $context->item)) {
configuration_set_error('assoc array');
}
break;
// TODO Test both copy and move
case '#copy':
$destinations = configuration_fetch($value, $context);
foreach ($destinations as &$dest) {
// TODO We are making it impossible to overwrite an existing item. Maybe we should make it possible? This applies to #move too
if ($dest->empty) {
$dest->item = $context->item;
}
}
break;
case '#move':
// TODO Moving/Copying to the same array level as the current item can cause problems with the current matches set. Maybe make it impossible to do so or think of a solution.
$dest = configuration_fetch($value, $context);
if (count($dest) == 1 && ($dest =& $dest[0])) {
$parent =& $context->parent;
$key = $context->key;
// Move the necessary dest info over here
foreach (array_diff(array_keys((array) $dest), array(
'children',
'item',
)) as $key) {
// TODO Is there room to do better memory cleanup here or does it not matter?
$context->{$key} =& $dest->{$key};
}
// Make sure the old child pointer points to the new context
for ($i = 0; isset($context->parent->children[$i]); $i++) {
$check =& $context->parent->children[$i];
if ($check === $dest) {
$context->parent->children[$i] =& $context;
break;
}
}
// Make sure the moved data exists in the right place of the original array
$context->parent->item[$context->key] =& $context->item;
// Remove the item here. check_context will make sure contexts are removed
// We can't remove if we moved to this items parent
// TODO Make it work so you can move two parents up
if ($parent !== $dest) {
unset($parent->item[$key]);
}
// Fix all the children trace paths
configuration_fix_context_trace($context);
}
case '#required':
if ($context->empty) {
$path = implode('/', array_merge($context->trace, array(
$context->key,
)));
configuration_set_error('pre-validate: required', array(
'!tag' => $path,
));
}
else {
$context->required = true;
}
break;
case '#context key':
if (is_scalar($context->item)) {
$context->parent->secondary_key = $context->item;
}
break;
case '#attribute':
if (!is_scalar($context->item)) {
$path = implode('/', $context->trace);
configuration_set_error('pre-validate: attribute', array(
'!tag' => $path,
));
}
else {
if ($context->key[0] == CONFIGURATION_ATTRIBUTE_KEY) {
$key = substr($context->key, 1);
}
else {
$key = $context->key;
}
if (!configuration_reserved_attribute($key)) {
$context->parent->{$key} = $context->item;
unset($context->parent->item[$context->key]);
}
}
break;
case '#options callback':
if (function_exists($value)) {
$value = $value($context);
}
case '#options':
if (is_scalar($value)) {
$value = array(
$value,
);
}
if (!in_array($context->item, $value)) {
if (!($context->item === '' && !$context->required)) {
$path = implode('/', $context->trace);
configuration_set_error('pre-validate: options', array(
'!path' => $path,
'!options' => implode(', ', $value),
));
break;
}
}
case '#value alias':
foreach ($value as $real => $aliases) {
foreach ($aliases as $alias) {
if ($context->item == $alias) {
$context->item = $real;
break 2;
}
}
}
break;
case '#value callback':
if (function_exists($value)) {
$value($context->item, $context);
}
else {
configuration_set_error('value callback', array(
'@callback' => $value,
));
}
break;
case '#value php':
$php = $value;
$value =& $context->item;
$new = eval($php);
if (isset($new)) {
$context->item = $new;
}
break;
case '#value path':
if (($matches = configuration_fetch($value, $context)) && count($matches) == 1) {
$context->item = $matches[0]->item;
}
break;
case '#value':
$context->item = $value;
break;
case '#id callback':
if (function_exists($value)) {
$identifiers =& configuration_get_data('identifiers');
}
break;
case '#id php':
break;
case '#id path':
break;
// Not used/supported.
// TODO Remove?
case '#build callback':
if (function_exists($value)) {
$context->build_data = $value($context);
}
break;
case '#build php':
$context->build_data = eval($value);
break;
case '#action':
if (!is_array($value)) {
$value = array(
$value,
);
}
$actions =& configuration_get_data('actions');
foreach ($value as $action) {
$action[] = array(
$action,
null,
&$context,
);
}
break;
case '#action callback':
if (function_exists($value)) {
$actions =& configuration_get_data('actions');
$context->action_callback = $value;
$actions[] = array(
null,
&$context,
);
}
else {
configuration_set_error('missing action callback', array(
'@callback' => $value,
));
}
break;
case '#enable module':
if (is_scalar($context->item)) {
$enable =& configuration_get_data('enable modules');
$enable[] = $context->item;
}
break;
case '#disable module':
if (is_scalar($context->item)) {
$disable =& configuration_get_data('disable modules');
$disable[] = $context->item;
}
break;
case '#delete':
unset($context->parent->item[$context->key]);
break;
}
// Update the context object to reflect any possible new changes
if (!in_array($property, $no_modify_propertiers)) {
configuration_check_context($context);
}
}