'Features', 'description' => 'Administer features.', 'page callback' => 'drupal_get_form', 'page arguments' => array('features_admin_form'), 'type' => MENU_NORMAL_ITEM, 'file' => 'features.admin.inc', ); $items['admin/features/manage'] = array( 'title' => 'Manage', 'description' => 'Enable and disable features.', 'page callback' => 'drupal_get_form', 'page arguments' => array('features_admin_form'), 'type' => MENU_DEFAULT_LOCAL_TASK, 'file' => 'features.admin.inc', ); $items['admin/features/compare/%'] = array( 'title' => 'Compare', 'description' => 'Compare default and current feature.', 'page callback' => 'features_feature_comparison', 'page arguments' => array(3), 'type' => MENU_CALLBACK, 'file' => 'features.admin.inc', ); $items['admin/features/export'] = array( 'title' => 'Export', 'description' => 'Export features to code.', 'page callback' => 'drupal_get_form', 'page arguments' => array('features_export_form'), 'type' => MENU_LOCAL_TASK, 'file' => "features.export.inc", 'weight' => 10, ); $items['admin/features/export/%'] = array( 'title' => 'Export', 'description' => 'Export features to code.', 'page callback' => 'drupal_get_form', 'page arguments' => array('features_export_form', 3), 'type' => MENU_LOCAL_TASK, 'file' => "features.export.inc", 'weight' => 10, ); $items['admin/features/%'] = array( 'title' => 'Feature components', 'description' => 'Display components of a feature.', 'page callback' => 'features_admin_components', 'page arguments' => array(2), 'type' => MENU_NORMAL_ITEM, 'file' => 'features.admin.inc', ); foreach ($items as $path => $item) { $items[$path]['access callback'] = 'user_access'; $items[$path]['access arguments'] = array('administer site configuration'); } return $items; } /** * Implementation of hook_menu_alter(). */ function features_menu_alter(&$cache) { // Collect exported menu items and graft them into the features menu. $items = module_invoke_all('menu_default_items'); foreach ($items as $item) { if (!empty($item['path'])) { $path = $item['path']; unset($item['path']); if (!empty($cache[$path])) { $cache[$path] = array_merge($cache[$path], $item); $cache[$path]['type'] = MENU_NORMAL_ITEM; $cache[$path]['menu_name'] = 'features'; } } } } /** * Implementation of hook_theme(). */ function features_theme() { $items = array(); $path = drupal_get_path('module', 'features') .'/theme'; $items['features_form'] = array(); $items['features_export_form_confirm'] = array(); $items['features_export_form_final'] = array(); $items['features_form_buttons'] = array( 'arguments' => array('element' => NULL), 'file' => 'theme.inc', 'path' => $path, ); $items['features_admin_components'] = array( 'arguments' => array('info' => NULL, 'dependencies' => NULL, 'components' => NULL, 'conflicts' => NULL), 'template' => 'features-admin-components', 'file' => 'theme.inc', 'path' => $path, ); $items['features_module_status'] = array( 'arguments' => array('module' => NULL, 'status' => NULL), 'file' => 'theme.inc', 'path' => $path, ); $items['features_storage'] = array( 'arguments' => array('storage' => NULL), 'file' => 'theme.inc', 'path' => $path, ); return $items; } /** * Implementation of hook_theme_registry_alter(). */ function features_theme_registry_alter(&$theme_registry) { if (!in_array('features_preprocess_page', $theme_registry['page']['preprocess functions'])) { $theme_registry['page']['preprocess functions'][] = 'features_preprocess_page'; } } /** * Return a module 'object' including .info information. * * @param $name * The name of the module to retrieve information for. If ommitted, * an array of all available modules will be returned. * @param $reset * Whether to reset the cache. * * @return * If a module is request (and exists) a module object is returned. If no * module is requested info for all modules is returned. */ function features_get_modules($name = NULL, $reset = FALSE) { return features_get_info('module', $name, $reset); } function features_get_features($name = NULL, $reset = FALSE) { return features_get_info('feature', $name, $reset); } function features_get_info($type = 'module', $name = NULL, $reset = FALSE) { $cache = cache_get('features_module_info'); if (($cache == 0) || $reset) { $data = array(); $result = db_query("SELECT filename, name, type, status, throttle, schema_version FROM {system} WHERE type = 'module'"); while ($row = db_fetch_object($result)) { $row->info = drupal_parse_info_file(dirname($row->filename) .'/'. $row->name .'.info'); if (!empty($row->info)) { if (!empty($row->info['feature'])) { $data['feature'][$row->name] = $row; } $data['module'][$row->name] = $row; } } cache_set("features_module_info", $data); $cache = new stdClass(); $cache->data = $data; } if (!empty($name)) { return !empty($cache->data[$type][$name]) ? $cache->data[$type][$name] : array(); } return !empty($cache->data[$type]) ? $cache->data[$type] : array(); } /** * Simple wrapper returns the status of a module. */ function features_get_module_status($module) { if (module_exists($module)) { return FEATURES_MODULE_ENABLED; } else if (features_get_modules($module)) { return FEATURES_MODULE_DISABLED; } else { return FEATURES_MODULE_MISSING; } } /** * Implementation of hook_form_alter() for features_admin_form. */ function features_form_features_admin_form_alter(&$form) { features_rebuild(); } /** * Implementation of hook_form_alter() for system_modules form. */ function features_form_system_modules_alter(&$form) { features_rebuild(); } /** * Rebuild definitions -- calls various scripts for non-exportables. */ function features_rebuild() { if (module_exists('content')) { features_content_fields_rebuild(); } } /** * Rebuild CCK field definitions. */ function features_content_fields_rebuild() { module_load_include('inc', 'content', 'includes/content.crud'); content_clear_type_cache(TRUE); $fields = module_invoke_all('content_default_fields'); foreach ($fields as $field) { $conflicts = array(); $existing_field = content_fields($field['field_name']); $existing_instance = content_fields($field['field_name'], $field['type_name']); // If field storage doesn't exists, create it if (!$existing_field) { content_field_instance_create($field); } // If field storage exists, check that storage and key descriptors don't conflict else { // Iterate through field properties to determine compatibility foreach ($field as $key => $value) { $excluded = array('type_name'); if (!is_array($value) && !in_array($key, $excluded)) { if ($value !== $existing_field[$key]) { $conflicts[] = $key; } } } if (!empty($conflicts)) { $tokens = array('!field' => $field['field_name'], '!type' => $field['type_name'], '!list' => implode(', ', $conflicts)); $message = t('Field !field was not created for !type because a conflict was detected for the following properties: !list', $tokens); drupal_set_message($message); } else if (!$existing_instance) { content_field_instance_create($field); } } // If there are no field conflicts, update the type instance if (empty($conflicts)) { $instance = content_fields($field['field_name'], $field['type_name']); if (!empty($instance)) { $field = array_merge($field, $instance); } content_field_instance_update($field); } else { drupal_set_message(t('Field !field was not updated for !type because conflicts were detected.', array('!field' => $field['field_name'], '!type' => $field['type_name']))); } } } /** * Returns a links array in the theme_links() format for the features menu. * * @return * Array of links. */ function features_menu_links($level = 0, $reset = FALSE) { static $links; if (!isset($links[$level]) || $reset) { if (!isset($links)) { $links = array(); } $links[$level] = menu_navigation_links('features', $level); } drupal_alter('features_menu_links', $links[$level]); return $links[$level]; } /** * Theme functions ==================================================== */ /** * Preprocess function for features links. */ function features_preprocess_page(&$vars) { if (variable_get('menu_primary_links_source', 'primary-links') == 'features') { $vars['primary_links'] = features_menu_links(); } if (variable_get('menu_secondary_links_source', 'secondary-links') == 'features') { if (variable_get('menu_secondary_links_source', 'primary-links') == 'features') { $vars['secondary_links'] = features_menu_links(1); } else { $vars['secondary_links'] = features_menu_links(); } } }