features.ctools.inc

Tracking 7.x-2.x branch
  1. drupal
    1. 6 contributions/features/includes/features.ctools.inc
    2. 7 contributions/features/includes/features.ctools.inc

Functions & methods

NameDescription
ctools_component_features_apiMaster implementation of hook_features_api() for all ctools components.
ctools_component_features_exportMaster implementation of hook_features_export() for all ctools components.
ctools_component_features_export_optionsMaster implementation of hook_features_export_options() for all ctools components.
ctools_component_features_export_renderMaster implementation of hook_features_export_render() for all ctools components.
ctools_component_features_revertMaster implementation of hook_features_revert() for all ctools components.
ctools_features_apiImplements hook_features_api().
ctools_features_declare_functions
ctools_features_exportImplements hook_features_export(). Adds references to the ctools mothership hook, ctools_plugin_api().
ctools_features_export_renderImplements hook_features_export_render(). Adds the ctools mothership hook, ctools_plugin_api().
page_manager_pages_features_export_renderImplements hook_features_export_render() for page_manager.
page_manager_pages_features_revertImplements hook_features_revert() for page_manager.
views_features_pipe_views_view_alterImplements hook_features_pipe_COMPONENT_alter() for views_view.
_ctools_features_export_crud_deleteWrapper around ctools_export_crud_delete() for < 1.7 compatibility.
_ctools_features_export_crud_exportWrapper around ctools_export_crud_export() for < 1.7 compatibility.
_ctools_features_export_crud_loadWrapper around ctools_export_crud_load() for < 1.7 compatibility.
_ctools_features_export_default_listWrapper around ctools_export_default_list() for < 1.7 compatibility.
_ctools_features_get_infoHelper function to return various ctools information for components.

File

View source
  1. <?php
  2. function ctools_features_declare_functions($reset = FALSE) {
  3. /**
  4. * This is called by Features to ensure ctools component functions are defined
  5. * Dynamically declare functions under a ctools component's namespace if they are not already declared.
  6. */
  7. if (function_exists('_ctools_features_get_info')) {
  8. foreach (_ctools_features_get_info(NULL, $reset) as $component => $info) {
  9. $code = '';
  10. if (!function_exists("{$info['module']}_features_api")) {
  11. $code .= 'function '. $info['module'] .'_features_api() { return ctools_component_features_api("'. $info['module'] .'"); }';
  12. }
  13. // ctools component with owner defined as "ctools"
  14. if (!function_exists("{$component}_features_api") && $info['module'] === 'ctools') {
  15. $code .= 'function '. $component .'_features_api() { return ctools_component_features_api("'. $component .'"); }';
  16. }
  17. if (!function_exists("{$component}_features_export")) {
  18. $code .= 'function '. $component .'_features_export($data, &$export, $module_name = "") { return ctools_component_features_export("'. $component .'", $data, $export, $module_name); }';
  19. }
  20. if (!function_exists("{$component}_features_export_options")) {
  21. $code .= 'function '. $component .'_features_export_options() { return ctools_component_features_export_options("'. $component .'"); }';
  22. }
  23. if (!function_exists("{$component}_features_export_render")) {
  24. $code .= 'function '. $component .'_features_export_render($module, $data, $export = NULL) { return ctools_component_features_export_render("'. $component .'", $module, $data, $export); }';
  25. }
  26. if (!function_exists("{$component}_features_revert")) {
  27. $code .= 'function '. $component .'_features_revert($module) { return ctools_component_features_revert("'. $component .'", $module); }';
  28. }
  29. eval($code);
  30. }
  31. }
  32. }
  33. /**
  34. * Implements hook_features_api().
  35. */
  36. function ctools_features_api() {
  37. return array(
  38. 'ctools' => array(
  39. 'name' => 'CTools export API',
  40. 'feature_source' => TRUE,
  41. 'duplicates' => FEATURES_DUPLICATES_ALLOWED,
  42. // CTools API integration does not include a default hook declaration as
  43. // it is not a proper default hook.
  44. // 'default_hook' => 'ctools_plugin_api',
  45. ),
  46. );
  47. }
  48. /**
  49. * Implements hook_features_export().
  50. * Adds references to the ctools mothership hook, ctools_plugin_api().
  51. */
  52. function ctools_features_export($data, &$export, $module_name = '') {
  53. // Add ctools dependency
  54. $export['dependencies']['ctools'] = 'ctools';
  55. // Add the actual ctools components which will need to be accounted for in
  56. // hook_ctools_plugin_api(). The components are actually identified by a
  57. // delimited list of values: `module_name:api:current_version`
  58. foreach ($data as $component) {
  59. if ($info = _ctools_features_get_info($component)) {
  60. $identifier = "{$info['module']}:{$info['api']}:{$info['current_version']}";
  61. $export['features']['ctools'][$identifier] = $identifier;
  62. }
  63. }
  64. return array();
  65. }
  66. /**
  67. * Implements hook_features_export_render().
  68. * Adds the ctools mothership hook, ctools_plugin_api().
  69. */
  70. function ctools_features_export_render($module, $data) {
  71. $component_exports = array();
  72. foreach ($data as $component) {
  73. $code = array();
  74. if ($info = _ctools_features_get_info($component)) {
  75. // For background on why we change the output for hook_views_api()
  76. // see http://drupal.org/node/1459120.
  77. if ($info['module'] == 'views') {
  78. $code[] = ' return array("api" => "3.0");';
  79. }
  80. else {
  81. $code[] = ' list($module, $api) = func_get_args();';
  82. $code[] = ' if ($module == "'. $info['module'] .'" && $api == "'. $info['api'] .'") {';
  83. $code[] = ' return array("version" => "'. $info['current_version'] .'");';
  84. $code[] = ' }';
  85. }
  86. }
  87. ctools_include('plugins');
  88. $plugin_api_hook_name = ctools_plugin_api_get_hook($info['module'], $info['api']);
  89. if (key_exists($plugin_api_hook_name, $component_exports)) {
  90. $component_exports[$plugin_api_hook_name] .= "\n" . implode("\n", $code);
  91. }
  92. else {
  93. $component_exports[$plugin_api_hook_name] = implode("\n", $code);
  94. }
  95. }
  96. return $component_exports;
  97. }
  98. /**
  99. * Master implementation of hook_features_api() for all ctools components.
  100. *
  101. * Note that this master hook does not use $component like the others, but uses the
  102. * component module's namespace instead.
  103. */
  104. function ctools_component_features_api($module_name) {
  105. $api = array();
  106. foreach (_ctools_features_get_info() as $component => $info) {
  107. // if module owner is set to "ctools" we need to compare the component
  108. if ($info['module'] == $module_name || ($info['module'] === 'ctools' && $component == $module_name) ) {
  109. $api[$component] = $info;
  110. }
  111. }
  112. return $api;
  113. }
  114. /**
  115. * Master implementation of hook_features_export_options() for all ctools components.
  116. */
  117. function ctools_component_features_export_options($component) {
  118. $options = array();
  119. ctools_include('export');
  120. $schema = ctools_export_get_schema($component);
  121. if ($schema && $schema['export']['bulk export']) {
  122. if (!empty($schema['export']['list callback']) && function_exists($schema['export']['list callback'])) {
  123. $options = $schema['export']['list callback']();
  124. }
  125. else {
  126. $options = _ctools_features_export_default_list($component, $schema);
  127. }
  128. }
  129. asort($options);
  130. return $options;
  131. }
  132. /**
  133. * Master implementation of hook_features_export() for all ctools components.
  134. */
  135. function ctools_component_features_export($component, $data, &$export, $module_name = '') {
  136. // Add the actual implementing module as a dependency
  137. $info = _ctools_features_get_info();
  138. if ($module_name !== $info[$component]['module']) {
  139. $export['dependencies'][$info[$component]['module']] = $info[$component]['module'];
  140. }
  141. // Add the components
  142. foreach ($data as $object_name) {
  143. if ($object = _ctools_features_export_crud_load($component, $object_name)) {
  144. // If this object is provided as a default by a different module, don't
  145. // export and add that module as a dependency instead.
  146. if (!empty($object->export_module) && $object->export_module !== $module_name) {
  147. $export['dependencies'][$object->export_module] = $object->export_module;
  148. if (isset($export['features'][$component][$object_name])) {
  149. unset($export['features'][$component][$object_name]);
  150. }
  151. }
  152. // Otherwise, add the component.
  153. else {
  154. $export['features'][$component][$object_name] = $object_name;
  155. }
  156. }
  157. }
  158. // Let CTools handle API integration for this component.
  159. return array('ctools' => array($component));
  160. }
  161. /**
  162. * Master implementation of hook_features_export_render() for all ctools components.
  163. */
  164. function ctools_component_features_export_render($component, $module, $data) {
  165. // Reset the export display static to prevent clashes.
  166. drupal_static_reset('panels_export_display');
  167. ctools_include('export');
  168. $schema = ctools_export_get_schema($component);
  169. if (function_exists($schema['export']['to hook code callback'])) {
  170. $export = $schema['export']['to hook code callback']($data, $module);
  171. $code = explode("{\n", $export);
  172. array_shift($code);
  173. $code = explode('}', implode($code, "{\n"));
  174. array_pop($code);
  175. $code = implode('}', $code);
  176. }
  177. else {
  178. $code = ' $export = array();'."\n\n";
  179. foreach ($data as $object_name) {
  180. if ($object = _ctools_features_export_crud_load($component, $object_name)) {
  181. $identifier = $schema['export']['identifier'];
  182. $code .= _ctools_features_export_crud_export($component, $object, ' ');
  183. $code .= " \$export[" . ctools_var_export($object_name) . "] = \${$identifier};\n\n";
  184. }
  185. }
  186. $code .= ' return $export;';
  187. }
  188. return array($schema['export']['default hook'] => $code);
  189. }
  190. /**
  191. * Master implementation of hook_features_revert() for all ctools components.
  192. */
  193. function ctools_component_features_revert($component, $module) {
  194. if ($objects = features_get_default($component, $module)) {
  195. foreach ($objects as $name => $object) {
  196. // Some things (like views) do not use the machine name as key
  197. // and need to be loaded explicitly in order to be deleted.
  198. $object = ctools_export_crud_load($component, $name);
  199. if ($object && ($object->export_type & EXPORT_IN_DATABASE)) {
  200. _ctools_features_export_crud_delete($component, $object);
  201. }
  202. }
  203. }
  204. }
  205. /**
  206. * Helper function to return various ctools information for components.
  207. */
  208. function _ctools_features_get_info($identifier = NULL, $reset = FALSE) {
  209. static $components;
  210. if (!isset($components) || $reset) {
  211. $components = array();
  212. $modules = features_get_info();
  213. ctools_include('export');
  214. drupal_static('ctools_export_get_schemas', NULL, $reset);
  215. foreach (ctools_export_get_schemas_by_module() as $module => $schemas) {
  216. foreach ($schemas as $table => $schema) {
  217. if ($schema['export']['bulk export']) {
  218. // Let the API owner take precedence as the owning module.
  219. $api_module = isset($schema['export']['api']['owner']) ? $schema['export']['api']['owner'] : $module;
  220. $components[$table] = array(
  221. 'name' => isset($modules[$api_module]->info['name']) ? $modules[$api_module]->info['name'] : $api_module,
  222. 'default_hook' => $schema['export']['default hook'],
  223. 'default_file' => FEATURES_DEFAULTS_CUSTOM,
  224. 'module' => $api_module,
  225. 'feature_source' => TRUE,
  226. );
  227. if (isset($schema['export']['api'])) {
  228. $components[$table] += array(
  229. 'api' => $schema['export']['api']['api'],
  230. 'default_filename' => $schema['export']['api']['api'],
  231. 'current_version' => $schema['export']['api']['current_version'],
  232. );
  233. }
  234. }
  235. }
  236. }
  237. }
  238. // Return information specific to a particular component.
  239. if (isset($identifier)) {
  240. // Identified by the table name.
  241. if (isset($components[$identifier])) {
  242. return $components[$identifier];
  243. }
  244. // New API identifier. Allows non-exportables related CTools APIs to be
  245. // supported by an explicit `module:api:current_version` key.
  246. else if (substr_count($identifier, ':') === 2) {
  247. list($module, $api, $current_version) = explode(':', $identifier);
  248. // If a schema component matches the provided identifier, provide that
  249. // information. This also ensures that the version number is up to date.
  250. foreach ($components as $table => $info) {
  251. if ($info['module'] == $module && $info['api'] == $api && $info['current_version'] >= $current_version) {
  252. return $info;
  253. }
  254. }
  255. // Fallback to just giving back what was provided to us.
  256. return array('module' => $module, 'api' => $api, 'current_version' => $current_version);
  257. }
  258. return FALSE;
  259. }
  260. return $components;
  261. }
  262. /**
  263. * Wrapper around ctools_export_crud_export() for < 1.7 compatibility.
  264. */
  265. function _ctools_features_export_crud_export($table, $object, $indent = '') {
  266. return ctools_api_version('1.7') ? ctools_export_crud_export($table, $object, $indent) : ctools_export_object($table, $object, $indent);
  267. }
  268. /**
  269. * Wrapper around ctools_export_crud_load() for < 1.7 compatibility.
  270. */
  271. function _ctools_features_export_crud_load($table, $name) {
  272. if (ctools_api_version('1.7')) {
  273. return ctools_export_crud_load($table, $name);
  274. }
  275. elseif ($objects = ctools_export_load_object($table, 'names', array($name))) {
  276. return array_shift($objects);
  277. }
  278. return FALSE;
  279. }
  280. /**
  281. * Wrapper around ctools_export_default_list() for < 1.7 compatibility.
  282. */
  283. function _ctools_features_export_default_list($table, $schema) {
  284. if (ctools_api_version('1.7')) {
  285. return ctools_export_default_list($table, $schema);
  286. }
  287. elseif ($objects = ctools_export_load_object($table, 'all')) {
  288. return drupal_map_assoc(array_keys($objects));
  289. }
  290. return array();
  291. }
  292. /**
  293. * Wrapper around ctools_export_crud_delete() for < 1.7 compatibility.
  294. */
  295. function _ctools_features_export_crud_delete($table, $object) {
  296. if (ctools_api_version('1.7')) {
  297. ctools_export_crud_delete($table, $object);
  298. }
  299. else {
  300. $schema = ctools_export_get_schema($table);
  301. $export = $schema['export'];
  302. db_query("DELETE FROM {{$table}} WHERE {$export['key']} = '%s'", $object->{$export['key']});
  303. }
  304. }
  305. /**
  306. * Implements hook_features_export_render() for page_manager.
  307. */
  308. function page_manager_pages_features_export_render($module, $data) {
  309. // Reset the export display static to prevent clashes.
  310. drupal_static_reset('panels_export_display');
  311. // Ensure that handlers have their code included before exporting.
  312. page_manager_get_tasks();
  313. return ctools_component_features_export_render('page_manager_pages', $module, $data);
  314. }
  315. /**
  316. * Implements hook_features_revert() for page_manager.
  317. */
  318. function page_manager_pages_features_revert($module) {
  319. if ($pages = features_get_default('page_manager_pages', $module)) {
  320. require_once drupal_get_path('module', 'ctools') . '/page_manager/plugins/tasks/page.inc';
  321. foreach ($pages as $page) {
  322. page_manager_page_delete($page);
  323. }
  324. }
  325. }
  326. /**
  327. * Implements hook_features_pipe_COMPONENT_alter() for views_view.
  328. */
  329. function views_features_pipe_views_view_alter(&$pipe, $data, $export) {
  330. // @todo Remove this check before next stable release.
  331. if (!function_exists('views_plugin_list')) {
  332. return;
  333. }
  334. $map = array_flip($data);
  335. foreach (views_plugin_list() as $plugin) {
  336. foreach ($plugin['views'] as $view_name) {
  337. if (isset($map[$view_name])) {
  338. $pipe['dependencies'][$plugin['module']] = $plugin['module'];
  339. }
  340. }
  341. }
  342. }