'features_form');
$form['feature'] =
$form['links'] =
$form['version'] =
$form['weight'] =
$form['status'] = array(
'#tree' => TRUE,
);
$modules = features_get_modules('', TRUE);
// Generate features form.
foreach (features_get_features('', TRUE) as $name => $module) {
$unmet_dependencies = array();
if (!empty($module->info['dependencies'])) {
foreach ($module->info['dependencies'] as $dependency) {
if (empty($modules[$dependency])) {
$unmet_dependencies[] = theme('features_module_status', FEATURES_MODULE_MISSING, $dependency);
}
}
}
$form['feature'][$name] = array(
'#type' => 'value',
'#value' => $module,
);
$form['status'][$name] = array(
'#type' => 'checkbox',
'#title' => $module->info['name'],
'#description' => !empty($unmet_dependencies) ? t('Unmet dependencies: !dependencies', array('!dependencies' => implode(', ', $unmet_dependencies))) : $module->info['description'],
'#default_value' => $module->status,
'#disabled' => !empty($unmet_dependencies) ? TRUE : FALSE,
);
$uri = !empty($module->info['feature_uri']) ? $module->info['feature_uri'] : t('Unavailable');
$timestamp = !empty($module->info['feature_timestamp']) ? format_date($module->info['feature_timestamp'], 'small') : '';
$timestamp = !empty($timestamp) ? "
$timestamp
" : '';
$sign = "$uri $timestamp";
$form['sign'][$name] = array(
'#type' => 'markup',
'#value' => $sign,
);
if ($module->status) {
$storage = count(features_detect_overrides($module)) ? FEATURES_OVERRIDDEN : FEATURES_DEFAULT;
$actions = array();
$actions[] = l(t('View'), "admin/build/features/{$name}");
switch ($storage) {
case FEATURES_OVERRIDDEN:
$state = l(theme('features_storage', $storage), "admin/build/features/{$name}/compare", array('html' => TRUE));
$actions[] = l(t('Re-export'), "admin/build/features/{$name}/export");
break;
case FEATURES_DEFAULT:
$state = theme('features_storage', $storage);
break;
}
}
$form['state'][$name] = array(
'#type' => 'markup',
'#value' => !empty($state) ? $state : '',
);
$form['actions'][$name] = array(
'#type' => 'markup',
'#value' => !empty($actions) ? implode(' | ', $actions) : '',
);
}
$form['buttons'] = array(
'#theme' => 'features_form_buttons',
);
$form['buttons']['submit'] = array(
'#type' => 'submit',
'#value' => t('Save settings'),
'#submit' => array('features_form_submit'),
);
return $form;
}
/**
* Display the components of a feature.
*/
function features_admin_components($feature) {
module_load_include('inc', 'features', 'features.export');
$conflict = features_detect_overrides($feature);
// Retrieve basic information
$info = array();
$info['name'] = $feature->info['name'];
$info['description'] = $feature->info['description'];
// Iterate over dependencies and retrieve status for display
$dependencies = array();
if (!empty($feature->info['dependencies'])) {
foreach ($feature->info['dependencies'] as $dependency) {
$status = features_get_module_status($dependency);
$dependencies[$dependency] = $status;
}
}
// Iterate over components and retrieve status for display
$components = $feature->info['features'];
$conflicts = array();
foreach ($feature->info['features'] as $type => $items) {
if (!empty($conflict[$type])) {
$conflicts[$type] = l(theme('features_storage', FEATURES_OVERRIDDEN), "admin/build/features/{$feature->name}/compare", array('html' => TRUE));
unset($conflict[$type]);
}
else {
$conflicts[$type] = theme('features_storage', FEATURES_DEFAULT);
}
}
// There are new additions -- show
if (!empty($conflict)) {
foreach ($conflict as $type => $items) {
// If exportables are standardized with keyed arrays, this would work much better!
$components[$type] = array();
$conflicts[$type] = l(theme('features_storage', FEATURES_OVERRIDDEN), "admin/build/features/{$feature->name}/compare", array('html' => TRUE));
}
}
return theme('features_admin_components', $info, $dependencies, $components, $conflicts);
}
/**
* Submit handler for the 'manage features' form
*/
function features_form_submit(&$form, &$form_state) {
$features = $form_state['values']['feature'];
$install = array();
$disable = array();
if (!empty($features)) {
foreach ($features as $name => $feature) {
// Enable feature
if ($form_state['values']['status'][$name] && !module_exists($name)) {
if (!empty($feature->info['dependencies'])) {
foreach ($feature->info['dependencies'] as $dependency) {
if (!module_exists($dependency)) {
$install[] = $dependency;
}
}
}
$install[] = $name;
}
// Disable feature
else if (!$form_state['values']['status'][$name] && module_exists($name)) {
$disable[] = $name;
}
}
if (!empty($install)) {
module_enable($install);
// Make sure the install API is available.
include_once './includes/install.inc';
drupal_install_modules($install);
}
if (!empty($disable)) {
module_disable($disable);
}
}
// Clear the cache to respect any changes.
features_get_modules(NULL, TRUE);
$form['#redirect'] = 'admin/build/features/cache-clear';
}
/**
* Cache clear menu callback.
*/
function features_cache_clear() {
drupal_rebuild_theme_registry();
node_types_rebuild();
menu_rebuild();
drupal_goto('admin/build/features');
}
/**
* Page callback to display the differences between what's in code and
* what is in the db.
*
* @param $module
* The name of the feature module to check display differences for.
*
* @return Themed display of what is different.
*/
function features_feature_comparison($feature) {
drupal_add_css(drupal_get_path('module', 'features') .'/features.css');
module_load_include('inc', 'features', 'features.export');
$conflict = features_detect_overrides($feature);
// There are differences
if (!empty($conflict)) {
// Diff is installed
if (module_exists('diff')) {
module_load_include('php', 'diff', 'DiffEngine');
$formatter = new DrupalDiffFormatter();
foreach ($conflict as $k => $v) {
if (module_exists('diff')) {
if (is_object($v['default']) && get_class($v['default']) == 'view' ){
$old = $v['default']->export();
$new = $v['current']->export();
}
else {
$old = features_var_export($v['default']);
$new = features_var_export($v['current']);
}
// Eliminate whitespace differences
$old = _features_linetrim(explode("\n", $old));
$new = _features_linetrim(explode("\n", $new));
$diff = new Diff($old, $new);
$output .= '' . $k . '
';
$output .= theme('diff_table', array(t('Default'), '', t('Current'), ''), $formatter->format($diff), array('class' => 'diff'));
}
else {
$items[] = $k;
}
}
}
// Diff is not installed
else {
$output = "". t('Please install the diff module to view changes.') ."
";
}
}
// No changes
else {
$output = "". t('No changes have been made to this feature.') ."
";
}
$output = "{$output}
";
return $output;
}
/**
* Theme for features management form.
*/
function theme_features_form($form) {
drupal_add_css(drupal_get_path('module', 'features') .'/features.css');
drupal_add_js(drupal_get_path('module', 'features') .'/features.js');
$output = '';
$header = array('', t('Feature'), t('Signature'), t('State'), t('Actions'));
$rows = array();
foreach (element_children($form['status']) as $element) {
// Yank title & description fields off the form element for
// rendering in their own cells.
$name = "";
$name .= "
{$form['status'][$element]['#title']}";
$name .= "
{$form['status'][$element]['#description']}
";
$name .= "
";
unset($form['status'][$element]['#title']);
unset($form['status'][$element]['#description']);
$row = array(
'status' => drupal_render($form['status'][$element]),
'name' => $name,
'sign' => drupal_render($form['sign'][$element]),
'state' => drupal_render($form['state'][$element]),
'actions' => drupal_render($form['actions'][$element]),
);
// Determine row classes
$class = $form['status'][$element]['#default_value'] ? 'enabled' : 'disabled';
// Collect data + classes & add to master array.
foreach ($row as $key => $data) {
$row[$key] = array('data' => $data, 'class' => $key);
}
$rows[] = array('data' => $row, 'class' => $class);
}
$output .= theme('table', $header, $rows, array('id' => 'features-form-table', 'class' => 'features'));
// Prevent section from being rendered by drupal_render().
unset($form['features']);
$output .= drupal_render($form['buttons']);
$output .= drupal_render($form);
return $output;
}