danielebarchiesi@4: $info) { danielebarchiesi@4: $code = ''; danielebarchiesi@4: if (!function_exists("{$info['module']}_features_api")) { danielebarchiesi@4: $code .= 'function '. $info['module'] .'_features_api() { return ctools_component_features_api("'. $info['module'] .'"); }'; danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: // ctools component with owner defined as "ctools" danielebarchiesi@4: if (!function_exists("{$component}_features_api") && $info['module'] === 'ctools') { danielebarchiesi@4: $code .= 'function '. $component .'_features_api() { return ctools_component_features_api("'. $component .'"); }'; danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: if (!function_exists("{$component}_features_export")) { danielebarchiesi@4: $code .= 'function '. $component .'_features_export($data, &$export, $module_name = "") { return ctools_component_features_export("'. $component .'", $data, $export, $module_name); }'; danielebarchiesi@4: } danielebarchiesi@4: if (!function_exists("{$component}_features_export_options")) { danielebarchiesi@4: $code .= 'function '. $component .'_features_export_options() { return ctools_component_features_export_options("'. $component .'"); }'; danielebarchiesi@4: } danielebarchiesi@4: if (!function_exists("{$component}_features_export_render")) { danielebarchiesi@4: $code .= 'function '. $component .'_features_export_render($module, $data, $export = NULL) { return ctools_component_features_export_render("'. $component .'", $module, $data, $export); }'; danielebarchiesi@4: } danielebarchiesi@4: if (!function_exists("{$component}_features_revert")) { danielebarchiesi@4: $code .= 'function '. $component .'_features_revert($module) { return ctools_component_features_revert("'. $component .'", $module); }'; danielebarchiesi@4: } danielebarchiesi@4: eval($code); danielebarchiesi@4: } danielebarchiesi@4: } danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: /** danielebarchiesi@4: * Implements hook_features_api(). danielebarchiesi@4: */ danielebarchiesi@4: function ctools_features_api() { danielebarchiesi@4: return array( danielebarchiesi@4: 'ctools' => array( danielebarchiesi@4: 'name' => 'CTools export API', danielebarchiesi@4: 'feature_source' => TRUE, danielebarchiesi@4: 'duplicates' => FEATURES_DUPLICATES_ALLOWED, danielebarchiesi@4: // CTools API integration does not include a default hook declaration as danielebarchiesi@4: // it is not a proper default hook. danielebarchiesi@4: // 'default_hook' => 'ctools_plugin_api', danielebarchiesi@4: ), danielebarchiesi@4: ); danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: /** danielebarchiesi@4: * Implements hook_features_export(). danielebarchiesi@4: * Adds references to the ctools mothership hook, ctools_plugin_api(). danielebarchiesi@4: */ danielebarchiesi@4: function ctools_features_export($data, &$export, $module_name = '') { danielebarchiesi@4: // Add ctools dependency danielebarchiesi@4: $export['dependencies']['ctools'] = 'ctools'; danielebarchiesi@4: danielebarchiesi@4: // Add the actual ctools components which will need to be accounted for in danielebarchiesi@4: // hook_ctools_plugin_api(). The components are actually identified by a danielebarchiesi@4: // delimited list of values: `module_name:api:current_version` danielebarchiesi@4: foreach ($data as $component) { danielebarchiesi@4: if ($info = _ctools_features_get_info($component)) { danielebarchiesi@4: $identifier = "{$info['module']}:{$info['api']}:{$info['current_version']}"; danielebarchiesi@4: $export['features']['ctools'][$identifier] = $identifier; danielebarchiesi@4: } danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: return array(); danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: /** danielebarchiesi@4: * Implements hook_features_export_render(). danielebarchiesi@4: * Adds the ctools mothership hook, ctools_plugin_api(). danielebarchiesi@4: */ danielebarchiesi@4: function ctools_features_export_render($module, $data) { danielebarchiesi@4: $component_exports = array(); danielebarchiesi@4: foreach ($data as $component) { danielebarchiesi@4: $code = array(); danielebarchiesi@4: if ($info = _ctools_features_get_info($component)) { danielebarchiesi@4: // For background on why we change the output for hook_views_api() danielebarchiesi@4: // see http://drupal.org/node/1459120. danielebarchiesi@4: if ($info['module'] == 'views') { danielebarchiesi@4: $code[] = ' return array("api" => "3.0");'; danielebarchiesi@4: } danielebarchiesi@4: else { danielebarchiesi@4: $code[] = ' if ($module == "'. $info['module'] .'" && $api == "'. $info['api'] .'") {'; danielebarchiesi@4: $code[] = ' return array("version" => "'. $info['current_version'] .'");'; danielebarchiesi@4: $code[] = ' }'; danielebarchiesi@4: } danielebarchiesi@4: } danielebarchiesi@4: ctools_include('plugins'); danielebarchiesi@4: $plugin_api_hook_name = ctools_plugin_api_get_hook($info['module'], $info['api']); danielebarchiesi@4: danielebarchiesi@4: if (key_exists($plugin_api_hook_name, $component_exports)) { danielebarchiesi@4: $component_exports[$plugin_api_hook_name]['code'] .= "\n" . implode("\n", $code); danielebarchiesi@4: } danielebarchiesi@4: else { danielebarchiesi@4: $component_exports[$plugin_api_hook_name] = array( danielebarchiesi@4: 'code' => implode("\n", $code), danielebarchiesi@4: 'args' => '$module = NULL, $api = NULL', danielebarchiesi@4: ); danielebarchiesi@4: } danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: return $component_exports; danielebarchiesi@4: danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: /** danielebarchiesi@4: * Master implementation of hook_features_api() for all ctools components. danielebarchiesi@4: * danielebarchiesi@4: * Note that this master hook does not use $component like the others, but uses the danielebarchiesi@4: * component module's namespace instead. danielebarchiesi@4: */ danielebarchiesi@4: function ctools_component_features_api($module_name) { danielebarchiesi@4: $api = array(); danielebarchiesi@4: foreach (_ctools_features_get_info() as $component => $info) { danielebarchiesi@4: // if module owner is set to "ctools" we need to compare the component danielebarchiesi@4: if ($info['module'] == $module_name || ($info['module'] === 'ctools' && $component == $module_name) ) { danielebarchiesi@4: $api[$component] = $info; danielebarchiesi@4: } danielebarchiesi@4: } danielebarchiesi@4: return $api; danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: /** danielebarchiesi@4: * Master implementation of hook_features_export_options() for all ctools components. danielebarchiesi@4: */ danielebarchiesi@4: function ctools_component_features_export_options($component) { danielebarchiesi@4: $options = array(); danielebarchiesi@4: danielebarchiesi@4: ctools_include('export'); danielebarchiesi@4: $schema = ctools_export_get_schema($component); danielebarchiesi@4: if ($schema && $schema['export']['bulk export']) { danielebarchiesi@4: if (!empty($schema['export']['list callback']) && function_exists($schema['export']['list callback'])) { danielebarchiesi@4: $options = $schema['export']['list callback'](); danielebarchiesi@4: } danielebarchiesi@4: else { danielebarchiesi@4: $options = _ctools_features_export_default_list($component, $schema); danielebarchiesi@4: } danielebarchiesi@4: } danielebarchiesi@4: asort($options); danielebarchiesi@4: return $options; danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: /** danielebarchiesi@4: * Master implementation of hook_features_export() for all ctools components. danielebarchiesi@4: */ danielebarchiesi@4: function ctools_component_features_export($component, $data, &$export, $module_name = '') { danielebarchiesi@4: // Add the actual implementing module as a dependency danielebarchiesi@4: $info = _ctools_features_get_info(); danielebarchiesi@4: if ($module_name !== $info[$component]['module']) { danielebarchiesi@4: $export['dependencies'][$info[$component]['module']] = $info[$component]['module']; danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: // Add the components danielebarchiesi@4: foreach ($data as $object_name) { danielebarchiesi@4: if ($object = _ctools_features_export_crud_load($component, $object_name)) { danielebarchiesi@4: // If this object is provided as a default by a different module, don't danielebarchiesi@4: // export and add that module as a dependency instead. danielebarchiesi@4: if (!empty($object->export_module) && $object->export_module !== $module_name) { danielebarchiesi@4: $export['dependencies'][$object->export_module] = $object->export_module; danielebarchiesi@4: if (isset($export['features'][$component][$object_name])) { danielebarchiesi@4: unset($export['features'][$component][$object_name]); danielebarchiesi@4: } danielebarchiesi@4: } danielebarchiesi@4: // Otherwise, add the component. danielebarchiesi@4: else { danielebarchiesi@4: $export['features'][$component][$object_name] = $object_name; danielebarchiesi@4: } danielebarchiesi@4: } danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: // Let CTools handle API integration for this component. danielebarchiesi@4: return array('ctools' => array($component)); danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: /** danielebarchiesi@4: * Master implementation of hook_features_export_render() for all ctools components. danielebarchiesi@4: */ danielebarchiesi@4: function ctools_component_features_export_render($component, $module, $data) { danielebarchiesi@4: // Reset the export display static to prevent clashes. danielebarchiesi@4: drupal_static_reset('panels_export_display'); danielebarchiesi@4: danielebarchiesi@4: ctools_include('export'); danielebarchiesi@4: $schema = ctools_export_get_schema($component); danielebarchiesi@4: danielebarchiesi@4: if (function_exists($schema['export']['to hook code callback'])) { danielebarchiesi@4: $export = $schema['export']['to hook code callback']($data, $module); danielebarchiesi@4: $code = explode("{\n", $export); danielebarchiesi@4: array_shift($code); danielebarchiesi@4: $code = explode('}', implode($code, "{\n")); danielebarchiesi@4: array_pop($code); danielebarchiesi@4: $code = implode('}', $code); danielebarchiesi@4: } danielebarchiesi@4: else { danielebarchiesi@4: $code = ' $export = array();'."\n\n"; danielebarchiesi@4: foreach ($data as $object_name) { danielebarchiesi@4: if ($object = _ctools_features_export_crud_load($component, $object_name)) { danielebarchiesi@4: $identifier = $schema['export']['identifier']; danielebarchiesi@4: $code .= _ctools_features_export_crud_export($component, $object, ' '); danielebarchiesi@4: $code .= " \$export[" . ctools_var_export($object_name) . "] = \${$identifier};\n\n"; danielebarchiesi@4: } danielebarchiesi@4: } danielebarchiesi@4: $code .= ' return $export;'; danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: return array($schema['export']['default hook'] => $code); danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: /** danielebarchiesi@4: * Master implementation of hook_features_revert() for all ctools components. danielebarchiesi@4: */ danielebarchiesi@4: function ctools_component_features_revert($component, $module) { danielebarchiesi@4: if ($objects = features_get_default($component, $module)) { danielebarchiesi@4: foreach ($objects as $name => $object) { danielebarchiesi@4: // Some things (like views) do not use the machine name as key danielebarchiesi@4: // and need to be loaded explicitly in order to be deleted. danielebarchiesi@4: $object = ctools_export_crud_load($component, $name); danielebarchiesi@4: if ($object && ($object->export_type & EXPORT_IN_DATABASE)) { danielebarchiesi@4: _ctools_features_export_crud_delete($component, $object); danielebarchiesi@4: } danielebarchiesi@4: } danielebarchiesi@4: } danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: /** danielebarchiesi@4: * Helper function to return various ctools information for components. danielebarchiesi@4: */ danielebarchiesi@4: function _ctools_features_get_info($identifier = NULL, $reset = FALSE) { danielebarchiesi@4: static $components; danielebarchiesi@4: if (!isset($components) || $reset) { danielebarchiesi@4: $components = array(); danielebarchiesi@4: $modules = features_get_info(); danielebarchiesi@4: ctools_include('export'); danielebarchiesi@4: drupal_static('ctools_export_get_schemas', NULL, $reset); danielebarchiesi@4: foreach (ctools_export_get_schemas_by_module() as $module => $schemas) { danielebarchiesi@4: foreach ($schemas as $table => $schema) { danielebarchiesi@4: if ($schema['export']['bulk export']) { danielebarchiesi@4: // Let the API owner take precedence as the owning module. danielebarchiesi@4: $api_module = isset($schema['export']['api']['owner']) ? $schema['export']['api']['owner'] : $module; danielebarchiesi@4: $components[$table] = array( danielebarchiesi@4: 'name' => isset($modules[$api_module]->info['name']) ? $modules[$api_module]->info['name'] : $api_module, danielebarchiesi@4: 'default_hook' => $schema['export']['default hook'], danielebarchiesi@4: 'default_file' => FEATURES_DEFAULTS_CUSTOM, danielebarchiesi@4: 'module' => $api_module, danielebarchiesi@4: 'feature_source' => TRUE, danielebarchiesi@4: ); danielebarchiesi@4: if (isset($schema['export']['api'])) { danielebarchiesi@4: $components[$table] += array( danielebarchiesi@4: 'api' => $schema['export']['api']['api'], danielebarchiesi@4: 'default_filename' => $schema['export']['api']['api'], danielebarchiesi@4: 'current_version' => $schema['export']['api']['current_version'], danielebarchiesi@4: ); danielebarchiesi@4: } danielebarchiesi@4: } danielebarchiesi@4: } danielebarchiesi@4: } danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: // Return information specific to a particular component. danielebarchiesi@4: if (isset($identifier)) { danielebarchiesi@4: // Identified by the table name. danielebarchiesi@4: if (isset($components[$identifier])) { danielebarchiesi@4: return $components[$identifier]; danielebarchiesi@4: } danielebarchiesi@4: // New API identifier. Allows non-exportables related CTools APIs to be danielebarchiesi@4: // supported by an explicit `module:api:current_version` key. danielebarchiesi@4: else if (substr_count($identifier, ':') === 2) { danielebarchiesi@4: list($module, $api, $current_version) = explode(':', $identifier); danielebarchiesi@4: // If a schema component matches the provided identifier, provide that danielebarchiesi@4: // information. This also ensures that the version number is up to date. danielebarchiesi@4: foreach ($components as $table => $info) { danielebarchiesi@4: if ($info['module'] == $module && $info['api'] == $api && $info['current_version'] >= $current_version) { danielebarchiesi@4: return $info; danielebarchiesi@4: } danielebarchiesi@4: } danielebarchiesi@4: // Fallback to just giving back what was provided to us. danielebarchiesi@4: return array('module' => $module, 'api' => $api, 'current_version' => $current_version); danielebarchiesi@4: } danielebarchiesi@4: return FALSE; danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: return $components; danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: /** danielebarchiesi@4: * Wrapper around ctools_export_crud_export() for < 1.7 compatibility. danielebarchiesi@4: */ danielebarchiesi@4: function _ctools_features_export_crud_export($table, $object, $indent = '') { danielebarchiesi@4: return ctools_api_version('1.7') ? ctools_export_crud_export($table, $object, $indent) : ctools_export_object($table, $object, $indent); danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: /** danielebarchiesi@4: * Wrapper around ctools_export_crud_load() for < 1.7 compatibility. danielebarchiesi@4: */ danielebarchiesi@4: function _ctools_features_export_crud_load($table, $name) { danielebarchiesi@4: if (ctools_api_version('1.7')) { danielebarchiesi@4: return ctools_export_crud_load($table, $name); danielebarchiesi@4: } danielebarchiesi@4: elseif ($objects = ctools_export_load_object($table, 'names', array($name))) { danielebarchiesi@4: return array_shift($objects); danielebarchiesi@4: } danielebarchiesi@4: return FALSE; danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: /** danielebarchiesi@4: * Wrapper around ctools_export_default_list() for < 1.7 compatibility. danielebarchiesi@4: */ danielebarchiesi@4: function _ctools_features_export_default_list($table, $schema) { danielebarchiesi@4: if (ctools_api_version('1.7')) { danielebarchiesi@4: return ctools_export_default_list($table, $schema); danielebarchiesi@4: } danielebarchiesi@4: elseif ($objects = ctools_export_load_object($table, 'all')) { danielebarchiesi@4: return drupal_map_assoc(array_keys($objects)); danielebarchiesi@4: } danielebarchiesi@4: return array(); danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: /** danielebarchiesi@4: * Wrapper around ctools_export_crud_delete() for < 1.7 compatibility. danielebarchiesi@4: */ danielebarchiesi@4: function _ctools_features_export_crud_delete($table, $object) { danielebarchiesi@4: if (ctools_api_version('1.7')) { danielebarchiesi@4: ctools_export_crud_delete($table, $object); danielebarchiesi@4: } danielebarchiesi@4: else { danielebarchiesi@4: $schema = ctools_export_get_schema($table); danielebarchiesi@4: $export = $schema['export']; danielebarchiesi@4: db_query("DELETE FROM {{$table}} WHERE {$export['key']} = '%s'", $object->{$export['key']}); danielebarchiesi@4: } danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: /** danielebarchiesi@4: * Implements hook_features_export_render() for page_manager. danielebarchiesi@4: */ danielebarchiesi@4: function page_manager_pages_features_export_render($module, $data) { danielebarchiesi@4: // Reset the export display static to prevent clashes. danielebarchiesi@4: drupal_static_reset('panels_export_display'); danielebarchiesi@4: danielebarchiesi@4: // Ensure that handlers have their code included before exporting. danielebarchiesi@4: page_manager_get_tasks(); danielebarchiesi@4: return ctools_component_features_export_render('page_manager_pages', $module, $data); danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: /** danielebarchiesi@4: * Implements hook_features_revert() for page_manager. danielebarchiesi@4: */ danielebarchiesi@4: function page_manager_pages_features_revert($module) { danielebarchiesi@4: if ($pages = features_get_default('page_manager_pages', $module)) { danielebarchiesi@4: require_once drupal_get_path('module', 'ctools') . '/page_manager/plugins/tasks/page.inc'; danielebarchiesi@4: foreach ($pages as $page) { danielebarchiesi@4: page_manager_page_delete($page); danielebarchiesi@4: } danielebarchiesi@4: } danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: /** danielebarchiesi@4: * Implements hook_features_pipe_COMPONENT_alter() for views_view. danielebarchiesi@4: */ danielebarchiesi@4: function views_features_pipe_views_view_alter(&$pipe, $data, $export) { danielebarchiesi@4: // @todo Remove this check before next stable release. danielebarchiesi@4: if (!function_exists('views_plugin_list')) { danielebarchiesi@4: return; danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: $map = array_flip($data); danielebarchiesi@4: foreach (views_plugin_list() as $plugin) { danielebarchiesi@4: foreach ($plugin['views'] as $view_name) { danielebarchiesi@4: if (isset($map[$view_name])) { danielebarchiesi@4: $pipe['dependencies'][$plugin['module']] = $plugin['module']; danielebarchiesi@4: } danielebarchiesi@4: } danielebarchiesi@4: } danielebarchiesi@4: }