features.api.php 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675
  1. <?php
  2. /**
  3. * @file
  4. * Hooks provided by the features module.
  5. *
  6. * Features provides different kinds of hooks:
  7. *
  8. * - Regular module hooks.
  9. * These are implemented by modules, like elsewhere in Drupal, and typically
  10. * called via module_invoke_all().
  11. * Most of these are to be implemented by contrib modules that define features
  12. * components. Some implementations are provided by features itself, on behalf
  13. * of other core or contrib modules.
  14. *
  15. * - Special "component hooks".
  16. * These are implemented by features components, and usually invoked for one
  17. * specific component only.
  18. * For functions that implement these hooks, the "hook_" prefix is replaced
  19. * with "{$component}_", where $component can be the name of the component, or
  20. * its base component.
  21. *
  22. * - Generated feature module hooks.
  23. * These contain the actual exported component data. Implementations are
  24. * typically generated by features based on the values from
  25. * hook_features_export_render().
  26. * Some components already have these hooks defined in their own module, so
  27. * they won't occur in this file.
  28. *
  29. * - Component data alter hooks.
  30. * These can be implemented by any module, and allow to alter the exported
  31. * component data from the generated hooks.
  32. *
  33. * - Feature module hooks.
  34. * These can be implemented by feature modules, and typically called one at a
  35. * time via module_invoke(), for the one feature module targeted by the
  36. * current operation. Unlike the generated feature module hooks, these are
  37. * typically added by a developer in the custom code part of a feature.
  38. *
  39. * @todo Rename component hooks as COMPONENT_features_xyz()? See #3077027.
  40. */
  41. /**
  42. * Module hook. Allows a module to declare features components.
  43. *
  44. * @return array[]
  45. * Format: $[$component] = $component_info
  46. * An array of components, keyed by the component name. Each component can
  47. * define several keys:
  48. *
  49. * 'file': Optional path to a file to include which contains the rest
  50. * of the features API hooks for this module.
  51. *
  52. * 'default_hook': The defaults hook for your component that is called
  53. * when the cache of default components is generated. Examples include
  54. * hook_views_default_views() or hook_context_default_contexts().
  55. *
  56. * 'default_file': The file-writing behavior to use when exporting this
  57. * component. May be one of 3 constant values:
  58. *
  59. * FEATURES_DEFAULTS_INCLUDED_COMMON: write hooks/components to
  60. * `.features.inc` with other components. This is the default behavior
  61. * if this key is not defined.
  62. *
  63. * FEATURES_DEFAULTS_INCLUDED: write hooks/components to a component-
  64. * specific include named automatically by features.
  65. *
  66. * FEATURES_DEFAULTS_CUSTOM: write hooks/components to a component-
  67. * specific include with a custom name provided. If your module provides
  68. * large amounts of code that should not be parsed often (only on specific
  69. * cache clears/rebuilds, for example) you should use the 2nd or 3rd
  70. * options to split your component into its own include.
  71. *
  72. * 'default_filename': The filename to use when 'default_file' is set to
  73. * FEATURES_DEFAULTS_CUSTOM.
  74. *
  75. * 'feature_source': Boolean value for whether this component should be
  76. * offered as an option on the initial feature creation form.
  77. *
  78. * 'base': Optional. An alternative base key to use when calling features
  79. * hooks for this component. Can be used for features component types that
  80. * are declared "dynamically" or are part of a family of components.
  81. *
  82. * 'alter_type': What type of alter hook this hook uses. 'normal' is called
  83. * after the main hook is called. 'inline' is embedded within the default hook
  84. * and may not be implemented by some default hooks.
  85. * 'none' is no alter hook exists. Defaults to 'normal'
  86. *
  87. * 'alter_hook': What the name of the alter hook for this component is.
  88. * Do not include the '_alter' part. Defaults to 'default_hook'.
  89. */
  90. function hook_features_api() {
  91. return array(
  92. 'mycomponent' => array(
  93. 'default_hook' => 'mycomponent_defaults',
  94. 'default_file' => FEATURES_DEFAULTS_INCLUDED,
  95. 'feature_source' => TRUE,
  96. 'file' => drupal_get_path('module', 'mycomponent') . '/mycomponent.features.inc',
  97. ),
  98. );
  99. }
  100. /**
  101. * Component hook. Process the export array for a given component.
  102. *
  103. * The hook should be implemented using the name of the
  104. * component, not the module, eg. [component]_features_export() rather than
  105. * [module]_features_export().
  106. *
  107. * Implementations of this hook have three key tasks:
  108. *
  109. * 1. Determine module dependencies for any of the components passed to it
  110. * e.g. the views implementation iterates over each views' handlers and
  111. * plugins to determine which modules need to be added as dependencies.
  112. *
  113. * 2. Correctly add components to the export array. In general this is usually
  114. * adding all of the items in $data to $export['features']['my_key'], but
  115. * can become more complicated if components are shared between features
  116. * or modules.
  117. *
  118. * 3. Delegating further detection and export tasks to related or derivative
  119. * components.
  120. *
  121. * Each export processor can kickoff further export processors by returning a
  122. * keyed array (aka the "pipe") where the key is the next export processor hook
  123. * to call and the value is an array to be passed to that processor's $data
  124. * argument. This allows an export process to start simply at a few objects:
  125. *
  126. * [context]
  127. *
  128. * And then branch out, delegating each component to its appropriate hook:
  129. *
  130. * [context]--------+------------+
  131. * | | |
  132. * [node] [block] [views]
  133. * |
  134. * [CCK]
  135. * |
  136. * [imagecache]
  137. *
  138. * @param string[] $data
  139. * An array of machine names for the component in question to be exported.
  140. * @param array &$export
  141. * By reference. An array of all components to be exported with a given
  142. * feature. Component objects that should be exported should be added to
  143. * this array.
  144. * @param string $module_name
  145. * The name of the feature module to be generated.
  146. *
  147. * @return string[][]|void
  148. * Format: $[$component][] = $name
  149. * The pipe array of further processors that should be called.
  150. */
  151. function hook_features_export($data, &$export, $module_name) {
  152. // The following is the simplest implementation of a straight object export
  153. // with no further export processors called.
  154. foreach ($data as $component) {
  155. $export['features']['mycomponent'][$component] = $component;
  156. }
  157. return array();
  158. }
  159. /**
  160. * Component hook. List all objects for a component that may be exported.
  161. *
  162. * The hook should be implemented using the name of the
  163. * component, not the module, eg. [component]_features_export() rather than
  164. * [module]_features_export().
  165. *
  166. * @return string[]
  167. * Format: $[$value] = $label
  168. * A keyed array of items, suitable for use with a FormAPI select or
  169. * checkboxes element.
  170. */
  171. function hook_features_export_options() {
  172. $options = array();
  173. foreach (mycomponent_load() as $mycomponent) {
  174. $options[$mycomponent->name] = $mycomponent->title;
  175. }
  176. return $options;
  177. }
  178. /**
  179. * Component hook. Renders one or more component objects to code.
  180. *
  181. * The hook should be implemented using the name of the component, not the
  182. * module, eg. [component]_features_export_render() rather than
  183. * [module]_features_export_render().
  184. *
  185. * @param string $module_name
  186. * The name of the feature module to be exported.
  187. * @param array $data
  188. * An array of machine name identifiers for the objects to be rendered.
  189. * @param array $export
  190. * The full export array of the current feature being exported. This is only
  191. * passed when hook_features_export_render() is invoked for an actual feature
  192. * update or recreate, not during state checks or other operations.
  193. *
  194. * @return string[]|mixed[]
  195. * Format: Combination of:
  196. * - $[$hook] = $function_body
  197. * - $[$hook] = ['code' => $function_body, 'args' => $params_php]
  198. * An associative array of rendered PHP code where the key is the name of the
  199. * hook that should wrap the PHP code. The hook should not include the name
  200. * of the module, e.g. the key for `hook_example` should simply be `example`
  201. * The values in the array can also be in the form of an associative array
  202. * with the required key of 'code' and optional key of 'args', if 'args' need
  203. * to be added to the hook. Alternate it can be an associative array in the
  204. * same style as hook_features_export_files() to add additional files.
  205. */
  206. function hook_features_export_render($module_name, $data, $export = NULL) {
  207. $code = array();
  208. $code[] = '$mycomponents = array();';
  209. foreach ($data as $name) {
  210. $code[] = " \$mycomponents['{$name}'] = " . features_var_export(mycomponent_load($name)) . ";";
  211. }
  212. $code[] = "return \$mycomponents;";
  213. $code = implode("\n", $code);
  214. return array('mycomponent_defaults' => $code);
  215. }
  216. /**
  217. * Component hook. Reverts all component objects for a given feature module.
  218. *
  219. * The hook should be implemented using the name of the
  220. * component, not the module, eg. [component]_features_revert() rather than
  221. * [module]_features_export().
  222. *
  223. * @param string $module_name
  224. * The name of the feature module whose components should be reverted.
  225. *
  226. * @return bool|void
  227. * TRUE or FALSE for whether the components were successfully reverted.
  228. * NOTE: This return value is no longer used in the latest Features so
  229. * modules should no longer count on this value
  230. */
  231. function hook_features_revert($module_name) {
  232. $mycomponents = module_invoke($module_name, 'mycomponent_defaults');
  233. if (!empty($mycomponents)) {
  234. foreach ($mycomponents as $mycomponent) {
  235. mycomponent_delete($mycomponent);
  236. }
  237. }
  238. }
  239. /**
  240. * Component hook. Rebuild all component objects for a given feature module.
  241. *
  242. * Should only be implemented for 'faux-exportable' components.
  243. *
  244. * The hook should be implemented using the name of the
  245. * component, not the module, eg. [component]_features_export() rather than
  246. * [module]_features_export().
  247. *
  248. * This hook is called at points where Features determines that it is safe
  249. * (ie. the feature is in state `FEATURES_REBUILDABLE`) for your module to
  250. * replace objects in the database with defaults that you collect from your
  251. * own defaults hook. See API.txt for how Features determines whether a
  252. * rebuild of components is possible.
  253. *
  254. * @param string $module_name
  255. * The name of the feature module whose components should be rebuilt.
  256. */
  257. function hook_features_rebuild($module_name) {
  258. $mycomponents = module_invoke($module_name, 'mycomponent_defaults');
  259. if (!empty($mycomponents)) {
  260. foreach ($mycomponents as $mycomponent) {
  261. mycomponent_save($mycomponent);
  262. }
  263. }
  264. }
  265. /**
  266. * Component hook. Called when a feature gets disabled.
  267. *
  268. * @param string $module_name
  269. * Name of the feature that was disabled.
  270. *
  271. * @see \_features_restore()
  272. */
  273. function hook_features_disable_feature($module_name) {
  274. // React to the feature being disabled.
  275. }
  276. /**
  277. * Component hook. Called when a feature gets enabled.
  278. *
  279. * @param string $module_name
  280. * Name of the feature that was enabled.
  281. *
  282. * @see \_features_restore()
  283. */
  284. function hook_features_enable_feature($module_name) {
  285. // React to the feature being enabled.
  286. }
  287. /**
  288. * Module hook. Invoked before a restore operation is run.
  289. *
  290. * This hook is called before any of the restore operations on the components is
  291. * run.
  292. *
  293. * @param string $op
  294. * The operation that is triggered: revert, rebuild, disable, enable.
  295. * @param array $items
  296. * The items handled by the operation.
  297. */
  298. function hook_features_pre_restore($op, $items) {
  299. if ($op == 'rebuild') {
  300. // Use features rebuild to rebuild the features independent exports too.
  301. entity_defaults_rebuild();
  302. }
  303. }
  304. /**
  305. * Module hook. Invoked after a restore operation is run.
  306. *
  307. * This hook is called after any of the restore operations on the components is
  308. * run.
  309. *
  310. * @param string $op
  311. * The operation that is triggered: revert, rebuild, disable, enable.
  312. * @param array $items
  313. * The items handled by the operation.
  314. */
  315. function hook_features_post_restore($op, $items) {
  316. if ($op == 'rebuild') {
  317. // Use features rebuild to rebuild the features independent exports too.
  318. entity_defaults_rebuild();
  319. }
  320. }
  321. /**
  322. * Module hook. Allows to alter the export options.
  323. *
  324. * The hook was first introduced in #1999254, to allow hiding specific items
  325. * that should never be exported to a feature.
  326. *
  327. * Known issues:
  328. * - This is currently ONLY invoked in the admin UI, NOT in drush commands.
  329. * - There are no implementations within features itself. In fact there might be
  330. * no implementations of this hook in any contrib module.
  331. * - Use at your own risk! See #3079939.
  332. *
  333. * @param string[] $options
  334. * Format: $[$name] = $label
  335. * Machine names and labels of exportable items for the component.
  336. * @param string $component
  337. * The component name, e.g. 'field_instance'.
  338. *
  339. * @see \hook_features_export_options()
  340. * @see \_features_export_build()
  341. */
  342. function hook_features_export_options_alter(array &$options, $component) {
  343. // Alter the $options array.
  344. }
  345. /**
  346. * Module hook. Alter the final array of component names to be exported.
  347. *
  348. * Invoked just prior to the rendering of defaults. Allows modules a final say
  349. * in whether or not certain Components are exported (the Components' actual
  350. * data, however, cannot be altered by this hook).
  351. *
  352. * @param array &$export
  353. * By reference. An array of all component names to be exported with a given
  354. * feature.
  355. * @param array $module_name
  356. * The name of the feature module to be generated.
  357. */
  358. function hook_features_export_alter(&$export, $module_name) {
  359. // Example: do not allow the page content type to be exported, ever.
  360. if (!empty($export['features']['node']['page'])) {
  361. unset($export['features']['node']['page']);
  362. }
  363. }
  364. /**
  365. * Module hook. Alter the pipe array for a given component.
  366. *
  367. * This hook should be implemented with the name of the component type in place
  368. * of `component` in the function name, e.g. `features_pipe_views_alter()` will
  369. * alter the pipe for the Views component.
  370. *
  371. * @param string[][] $pipe
  372. * Format: $[$component][] = $name
  373. * By reference. The pipe array of further processors that should be called.
  374. * @param string[] $data
  375. * An array of machine names for the component in question to be exported.
  376. * @param array $export
  377. * An array of all components to be exported with a given feature.
  378. * Some contrib implementations declare this parameter as by-reference, which
  379. * allows them to modify it directly. Most implementations only modify the
  380. * $pipe array.
  381. * Special keys added to $export only during this alter hook:
  382. * - $export['component'] (string), the component being exported.
  383. * - $export['module_name'] (string), the module being exported to.
  384. */
  385. function hook_features_pipe_COMPONENT_alter(&$pipe, $data, $export) {
  386. if (in_array($data, 'my-node-type')) {
  387. $pipe['dependencies'][] = 'mymodule';
  388. }
  389. }
  390. /**
  391. * Module hook. Alter the pipe array for a given component.
  392. *
  393. * @param string[][] &$pipe
  394. * Format: $[$component][] = $name
  395. * By reference. The pipe array of further processors that should be called.
  396. * @param string[] $data
  397. * An array of machine names for the component in question to be exported.
  398. * @param array $export
  399. * An array of all components to be exported with a given feature.
  400. * Some contrib implementations declare this parameter as by-reference, which
  401. * allows them to modify it directly. Most implementations only modify the
  402. * $pipe array.
  403. * Special keys added to $export only during this alter hook:
  404. * - $export['component'] (string), the component being exported.
  405. * - $export['module_name'] (string), the module being exported to.
  406. */
  407. function hook_features_pipe_alter(&$pipe, $data, $export) {
  408. if ($export['component'] == 'node' && in_array('my-node-type', $data)) {
  409. $pipe['dependencies'][] = 'mymodule';
  410. }
  411. }
  412. /**
  413. * Module hook. Add extra files to the exported file.
  414. *
  415. * @param string $module_name
  416. * Module being processed.
  417. * @param array $export
  418. * Array of exported components.
  419. *
  420. * @return string[][]
  421. * An array of files, keyed by file name that will appear in feature and
  422. * with either file_path key to indicate where to copy the file from or
  423. * file_content key to indicate the contents of the file.
  424. * Format: A mix of:
  425. * - $[$path]['file_content'] = $file_content
  426. * - $[$path]['file_path'] = $source_file_to_copy
  427. */
  428. function hook_features_export_files($module_name, $export) {
  429. return array('css/main.css' => array('file_content' => 'body {background-color:blue;}'));
  430. }
  431. /**
  432. * Module hook. Alter the extra files added to the export.
  433. *
  434. * @param array[] $files
  435. * Format: A mix of:
  436. * - $[$path]['file_content'] = $file_content
  437. * - $[$path]['file_path'] = $source_file_to_copy.
  438. * @param string $module_name
  439. * Name of the feature module being updated / generated.
  440. * @param array $export
  441. * The export array, with a structure similar to a feature's *.info file.
  442. */
  443. function hook_features_export_files_alter(&$files, $module_name, $export) {
  444. $files['css/main.css']['file_content'] = 'body {background-color:black;}';
  445. }
  446. /**
  447. * @defgroup features_component_alter_hooks Feature's component alter hooks
  448. * @{
  449. * Hooks to modify components defined by other features. These come in the form
  450. * hook_COMPONENT_alter where COMPONENT is the default_hook declared by any of
  451. * components within features.
  452. *
  453. * CTools also has a variety of hook_FOO_alters.
  454. *
  455. * Note: While views is a component of features, it declares its own alter
  456. * function which takes a similar form:
  457. * hook_views_default_views_alter(&$views)
  458. */
  459. /**
  460. * Deprecated as of 7.x-2.0.
  461. *
  462. * Alter the default fields right before they are cached into the database.
  463. *
  464. * @param array[] &$fields
  465. * By reference. The fields that have been declared by another feature.
  466. *
  467. * @deprecated
  468. */
  469. function hook_field_default_fields_alter(&$fields) {
  470. }
  471. /**
  472. * Alter the base fields right before they are cached into the database.
  473. *
  474. * @param array[] &$fields
  475. * Field base definitions from another feature, by field name.
  476. */
  477. function hook_field_default_field_bases_alter(&$fields) {
  478. }
  479. /**
  480. * Alter the field instances right before they are cached into the database.
  481. *
  482. * @param array[] &$fields
  483. * Format: $["$entity_type-$bundle-$field_name"] = $field_instance
  484. * Field instance definitions from another feature.
  485. */
  486. function hook_field_default_field_instances_alter(&$fields) {
  487. }
  488. /**
  489. * Alter default field groups right before they are cached into the database.
  490. *
  491. * @param array[] &$groups
  492. * Field group definitions from another feature.
  493. *
  494. * @see \hook_field_group_info()
  495. * @see \hook_field_group_info_alter()
  496. */
  497. function hook_fieldgroup_default_groups_alter(&$groups) {
  498. }
  499. /**
  500. * Alter default filter formats right before they are cached into the database.
  501. *
  502. * @param array[] &$formats
  503. * By reference. The formats that have been declared by another feature.
  504. */
  505. function hook_filter_default_formats_alter(&$formats) {
  506. }
  507. /**
  508. * Alter the default menus right before they are cached into the database.
  509. *
  510. * @param array[] &$menus
  511. * By reference. The menus that have been declared by another feature.
  512. */
  513. function hook_menu_default_menu_custom_alter(&$menus) {
  514. }
  515. /**
  516. * Alter the default menu links right before they are cached into the database.
  517. *
  518. * @param array[] &$links
  519. * By reference. The menu links that have been declared by another feature.
  520. */
  521. function hook_menu_default_menu_links_alter(&$links) {
  522. }
  523. /**
  524. * Alter the default menu items right before they are cached into the database.
  525. *
  526. * @param array[] &$items
  527. * By reference. The menu items that have been declared by another feature.
  528. *
  529. * @deprecated
  530. * The 'menu' component should no longer be used.
  531. */
  532. function hook_menu_default_items_alter(&$items) {
  533. }
  534. /**
  535. * Alter default vocabularies right before they are cached into the database.
  536. *
  537. * @param array[] &$vocabularies
  538. * By reference. The vocabularies that have been declared by another feature.
  539. */
  540. function hook_taxonomy_default_vocabularies_alter(&$vocabularies) {
  541. }
  542. /**
  543. * Alter default permissions right before they are cached into the database.
  544. *
  545. * @param array[] &$permissions
  546. * By reference. The permissions that have been declared by another feature.
  547. */
  548. function hook_user_default_permissions_alter(&$permissions) {
  549. }
  550. /**
  551. * Alter the default roles right before they are cached into the database.
  552. *
  553. * @param array[] &$roles
  554. * By reference. The roles that have been declared by another feature.
  555. */
  556. function hook_user_default_roles_alter(&$roles) {
  557. }
  558. /**
  559. * @}
  560. */
  561. /**
  562. * @defgroup features_module_hooks Feature module hooks
  563. * @{
  564. * Hooks invoked on Feature modules when that module is enabled, disabled,
  565. * rebuilt, or reverted. These are ONLY invoked on the Features module on
  566. * which these actions are taken.
  567. */
  568. /**
  569. * Feature module hook. Invoked on that module before it is reverted.
  570. *
  571. * @param string $component
  572. * Name of the component that is about to be reverted.
  573. */
  574. function hook_pre_features_revert($component) {
  575. }
  576. /**
  577. * Feature module hook. Invoked on that module after it is reverted.
  578. *
  579. * @param string $component
  580. * Name of the component that has just been reverted.
  581. */
  582. function hook_post_features_revert($component) {
  583. }
  584. /**
  585. * Feature module hook. Invoked on that module before it is rebuilt.
  586. *
  587. * @param string $component
  588. * Name of the component that is about to be rebuilt.
  589. */
  590. function hook_pre_features_rebuild($component) {
  591. }
  592. /**
  593. * Feature module hook. Invoked on that module after it is rebuilt.
  594. *
  595. * @param string $component
  596. * Name of the component that has just been rebuilt.
  597. */
  598. function hook_post_features_rebuild($component) {
  599. }
  600. /**
  601. * Feature module hook. Invoked on that module before it is disabled.
  602. *
  603. * @param string $component
  604. * Name of the component that is about to be disabled.
  605. */
  606. function hook_pre_features_disable_feature($component) {
  607. }
  608. /**
  609. * Feature module hook. Invoked on that module after it is disabled.
  610. *
  611. * @param string $component
  612. * Name of the component that has just been disabled.
  613. */
  614. function hook_post_features_disable_feature($component) {
  615. }
  616. /**
  617. * Feature module hook. Invoked on that module before it is enabled.
  618. *
  619. * @param string $component
  620. * Name of the component that is about to be enabled.
  621. */
  622. function hook_pre_features_enable_feature($component) {
  623. }
  624. /**
  625. * Feature module hook. Invoked on that module after it is enabled.
  626. *
  627. * @param string $component
  628. * Name of the component that has just been enabled.
  629. */
  630. function hook_post_features_enable_feature($component) {
  631. }
  632. /**
  633. * @}
  634. */