module.api.php 46 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040
  1. <?php
  2. /**
  3. * @file
  4. * Hooks related to module and update systems.
  5. */
  6. use Drupal\Core\Database\Database;
  7. use Drupal\Core\Link;
  8. use Drupal\Core\Url;
  9. use Drupal\Core\Utility\UpdateException;
  10. /**
  11. * @defgroup update_api Update API
  12. * @{
  13. * Updating minor versions of modules
  14. *
  15. * When you update code in a module, you may need to update stored data so that
  16. * the stored data is compatible with the new code. If this update is between
  17. * two minor versions of your module within the same major version of Drupal,
  18. * you can use the Update API to update the data. This API is described in brief
  19. * here; for more details, see https://www.drupal.org/node/2535316. If you are
  20. * updating your module for a major version of Drupal (for instance, Drupal 7 to
  21. * Drupal 8), updates will not run and you will need to use the
  22. * @link migrate Migrate API @endlink instead.
  23. *
  24. * @section sec_when When to write update code
  25. * You need to provide code that performs an update to stored data whenever your
  26. * module makes a change to its data model. A data model change is any change
  27. * that makes stored data on an existing site incompatible with that site's
  28. * updated codebase. Examples:
  29. * - Configuration changes: adding/removing/renaming a config key, changing the
  30. * expected data type or value structure, changing dependencies, schema
  31. * changes, etc.
  32. * - Database schema changes: adding, changing, or removing a database table or
  33. * field; moving stored data to different fields or tables; changing the
  34. * format of stored data.
  35. * - Content entity or field changes: adding, changing, or removing a field
  36. * definition, entity definition, or any of their properties.
  37. *
  38. * @section sec_how How to write update code
  39. * Update code for a module is put into an implementation of hook_update_N(),
  40. * which goes into file mymodule.install (if your module's machine name is
  41. * mymodule). See the documentation of hook_update_N() and
  42. * https://www.drupal.org/node/2535316 for details and examples.
  43. *
  44. * @section sec_test Testing update code
  45. * Update code should be tested both manually and by writing an automated test.
  46. * Automated tests for update code extend
  47. * \Drupal\system\Tests\Update\UpdatePathTestBase -- see that class for details,
  48. * and find classes that extend it for examples.
  49. *
  50. * @see migration
  51. * @}
  52. */
  53. /**
  54. * @addtogroup hooks
  55. * @{
  56. */
  57. /**
  58. * Defines one or more hooks that are exposed by a module.
  59. *
  60. * Normally hooks do not need to be explicitly defined. However, by declaring a
  61. * hook explicitly, a module may define a "group" for it. Modules that implement
  62. * a hook may then place their implementation in either $module.module or in
  63. * $module.$group.inc. If the hook is located in $module.$group.inc, then that
  64. * file will be automatically loaded when needed.
  65. * In general, hooks that are rarely invoked and/or are very large should be
  66. * placed in a separate include file, while hooks that are very short or very
  67. * frequently called should be left in the main module file so that they are
  68. * always available.
  69. *
  70. * See system_hook_info() for all hook groups defined by Drupal core.
  71. *
  72. * @return
  73. * An associative array whose keys are hook names and whose values are an
  74. * associative array containing:
  75. * - group: A string defining the group to which the hook belongs. The module
  76. * system will determine whether a file with the name $module.$group.inc
  77. * exists, and automatically load it when required.
  78. */
  79. function hook_hook_info() {
  80. $hooks['token_info'] = [
  81. 'group' => 'tokens',
  82. ];
  83. $hooks['tokens'] = [
  84. 'group' => 'tokens',
  85. ];
  86. return $hooks;
  87. }
  88. /**
  89. * Alter the registry of modules implementing a hook.
  90. *
  91. * This hook is invoked during \Drupal::moduleHandler()->getImplementations().
  92. * A module may implement this hook in order to reorder the implementing
  93. * modules, which are otherwise ordered by the module's system weight.
  94. *
  95. * Note that hooks invoked using \Drupal::moduleHandler->alter() can have
  96. * multiple variations(such as hook_form_alter() and hook_form_FORM_ID_alter()).
  97. * \Drupal::moduleHandler->alter() will call all such variants defined by a
  98. * single module in turn. For the purposes of hook_module_implements_alter(),
  99. * these variants are treated as a single hook. Thus, to ensure that your
  100. * implementation of hook_form_FORM_ID_alter() is called at the right time,
  101. * you will have to change the order of hook_form_alter() implementation in
  102. * hook_module_implements_alter().
  103. *
  104. * @param $implementations
  105. * An array keyed by the module's name. The value of each item corresponds
  106. * to a $group, which is usually FALSE, unless the implementation is in a
  107. * file named $module.$group.inc.
  108. * @param $hook
  109. * The name of the module hook being implemented.
  110. */
  111. function hook_module_implements_alter(&$implementations, $hook) {
  112. if ($hook == 'form_alter') {
  113. // Move my_module_form_alter() to the end of the list.
  114. // \Drupal::moduleHandler()->getImplementations()
  115. // iterates through $implementations with a foreach loop which PHP iterates
  116. // in the order that the items were added, so to move an item to the end of
  117. // the array, we remove it and then add it.
  118. $group = $implementations['my_module'];
  119. unset($implementations['my_module']);
  120. $implementations['my_module'] = $group;
  121. }
  122. }
  123. /**
  124. * Alter the information parsed from module and theme .info.yml files.
  125. *
  126. * This hook is invoked in \Drupal\Core\Extension\ExtensionList::doList(). A
  127. * module may implement this hook in order to add to or alter the data generated
  128. * by reading the .info.yml file with \Drupal\Core\Extension\InfoParser.
  129. *
  130. * Using implementations of this hook to make modules required by setting the
  131. * $info['required'] key is discouraged. Doing so will slow down the module
  132. * installation and uninstallation process. Instead, use
  133. * \Drupal\Core\Extension\ModuleUninstallValidatorInterface.
  134. *
  135. * @param array $info
  136. * The .info.yml file contents, passed by reference so that it can be altered.
  137. * @param \Drupal\Core\Extension\Extension $file
  138. * Full information about the module or theme.
  139. * @param string $type
  140. * Either 'module' or 'theme', depending on the type of .info.yml file that
  141. * was passed.
  142. *
  143. * @see \Drupal\Core\Extension\ModuleUninstallValidatorInterface
  144. */
  145. function hook_system_info_alter(array &$info, \Drupal\Core\Extension\Extension $file, $type) {
  146. // Only fill this in if the .info.yml file does not define a 'datestamp'.
  147. if (empty($info['datestamp'])) {
  148. $info['datestamp'] = $file->getMTime();
  149. }
  150. }
  151. /**
  152. * Perform necessary actions before a module is installed.
  153. *
  154. * @param string $module
  155. * The name of the module about to be installed.
  156. */
  157. function hook_module_preinstall($module) {
  158. mymodule_cache_clear();
  159. }
  160. /**
  161. * Perform necessary actions after modules are installed.
  162. *
  163. * This function differs from hook_install() in that it gives all other modules
  164. * a chance to perform actions when a module is installed, whereas
  165. * hook_install() is only called on the module actually being installed. See
  166. * \Drupal\Core\Extension\ModuleInstaller::install() for a detailed description of
  167. * the order in which install hooks are invoked.
  168. *
  169. * This hook should be implemented in a .module file, not in an .install file.
  170. *
  171. * @param $modules
  172. * An array of the modules that were installed.
  173. * @param bool $is_syncing
  174. * TRUE if the module is being installed as part of a configuration import. In
  175. * these cases, your hook implementation needs to carefully consider what
  176. * changes, if any, it should make. For example, it should not make any
  177. * changes to configuration objects or entities.
  178. *
  179. * @see \Drupal\Core\Extension\ModuleInstaller::install()
  180. * @see hook_install()
  181. */
  182. function hook_modules_installed($modules, $is_syncing) {
  183. if (in_array('lousy_module', $modules)) {
  184. \Drupal::state()->set('mymodule.lousy_module_compatibility', TRUE);
  185. }
  186. if (!$is_syncing) {
  187. \Drupal::service('mymodule.service')->doSomething($modules);
  188. }
  189. }
  190. /**
  191. * Perform setup tasks when the module is installed.
  192. *
  193. * If the module implements hook_schema(), the database tables will
  194. * be created before this hook is fired.
  195. *
  196. * If the module provides a MODULE.routing.yml or alters routing information
  197. * these changes will not be available when this hook is fired. If up-to-date
  198. * router information is required, for example to use \Drupal\Core\Url, then
  199. * (preferably) use hook_modules_installed() or rebuild the router in the
  200. * hook_install() implementation.
  201. *
  202. * Implementations of this hook are by convention declared in the module's
  203. * .install file. The implementation can rely on the .module file being loaded.
  204. * The hook will only be called when a module is installed. The module's schema
  205. * version will be set to the module's greatest numbered update hook. Because of
  206. * this, any time a hook_update_N() is added to the module, this function needs
  207. * to be updated to reflect the current version of the database schema.
  208. *
  209. * See the @link https://www.drupal.org/node/146843 Schema API documentation
  210. * @endlink for details on hook_schema and how database tables are defined.
  211. *
  212. * Note that since this function is called from a full bootstrap, all functions
  213. * (including those in modules enabled by the current page request) are
  214. * available when this hook is called. Use cases could be displaying a user
  215. * message, or calling a module function necessary for initial setup, etc.
  216. *
  217. * Please be sure that anything added or modified in this function that can
  218. * be removed during uninstall should be removed with hook_uninstall().
  219. *
  220. * @param bool $is_syncing
  221. * TRUE if the module is being installed as part of a configuration import. In
  222. * these cases, your hook implementation needs to carefully consider what
  223. * changes, if any, it should make. For example, it should not make any
  224. * changes to configuration objects or entities.
  225. *
  226. * @see \Drupal\Core\Config\ConfigInstallerInterface::isSyncing
  227. * @see hook_schema()
  228. * @see \Drupal\Core\Extension\ModuleInstaller::install()
  229. * @see hook_uninstall()
  230. * @see hook_modules_installed()
  231. */
  232. function hook_install($is_syncing) {
  233. // Set general module variables.
  234. \Drupal::state()->set('mymodule.foo', 'bar');
  235. }
  236. /**
  237. * Perform necessary actions before a module is uninstalled.
  238. *
  239. * @param string $module
  240. * The name of the module about to be uninstalled.
  241. */
  242. function hook_module_preuninstall($module) {
  243. mymodule_cache_clear();
  244. }
  245. /**
  246. * Perform necessary actions after modules are uninstalled.
  247. *
  248. * This function differs from hook_uninstall() in that it gives all other
  249. * modules a chance to perform actions when a module is uninstalled, whereas
  250. * hook_uninstall() is only called on the module actually being uninstalled.
  251. *
  252. * It is recommended that you implement this hook if your module stores
  253. * data that may have been set by other modules.
  254. *
  255. * @param $modules
  256. * An array of the modules that were uninstalled.
  257. * @param bool $is_syncing
  258. * TRUE if the module is being uninstalled as part of a configuration import.
  259. * In these cases, your hook implementation needs to carefully consider what
  260. * changes, if any, it should make. For example, it should not make any
  261. * changes to configuration objects or entities.
  262. *
  263. * @see hook_uninstall()
  264. */
  265. function hook_modules_uninstalled($modules, $is_syncing) {
  266. if (in_array('lousy_module', $modules)) {
  267. \Drupal::state()->delete('mymodule.lousy_module_compatibility');
  268. }
  269. mymodule_cache_rebuild();
  270. if (!$is_syncing) {
  271. \Drupal::service('mymodule.service')->doSomething($modules);
  272. }
  273. }
  274. /**
  275. * Remove any information that the module sets.
  276. *
  277. * The information that the module should remove includes:
  278. * - state that the module has set using \Drupal::state()
  279. * - modifications to existing tables
  280. *
  281. * The module should not remove its entry from the module configuration.
  282. * Database tables defined by hook_schema() will be removed automatically.
  283. *
  284. * The uninstall hook must be implemented in the module's .install file. It
  285. * will fire when the module gets uninstalled but before the module's database
  286. * tables are removed, allowing your module to query its own tables during
  287. * this routine.
  288. *
  289. * @param bool $is_syncing
  290. * TRUE if the module is being uninstalled as part of a configuration import.
  291. * In these cases, your hook implementation needs to carefully consider what
  292. * changes, if any, it should make. For example, it should not make any
  293. * changes to configuration objects or entities.
  294. *
  295. * @see hook_install()
  296. * @see hook_schema()
  297. * @see hook_modules_uninstalled()
  298. */
  299. function hook_uninstall($is_syncing) {
  300. // Delete remaining general module variables.
  301. \Drupal::state()->delete('mymodule.foo');
  302. }
  303. /**
  304. * Return an array of tasks to be performed by an installation profile.
  305. *
  306. * Any tasks you define here will be run, in order, after the installer has
  307. * finished the site configuration step but before it has moved on to the
  308. * final import of languages and the end of the installation. This is invoked
  309. * by install_tasks(). You can have any number of custom tasks to perform
  310. * during this phase.
  311. *
  312. * Each task you define here corresponds to a callback function which you must
  313. * separately define and which is called when your task is run. This function
  314. * will receive the global installation state variable, $install_state, as
  315. * input, and has the opportunity to access or modify any of its settings. See
  316. * the install_state_defaults() function in the installer for the list of
  317. * $install_state settings used by Drupal core.
  318. *
  319. * At the end of your task function, you can indicate that you want the
  320. * installer to pause and display a page to the user by returning any themed
  321. * output that should be displayed on that page (but see below for tasks that
  322. * use the form API or batch API; the return values of these task functions are
  323. * handled differently). You should also use #title within the task
  324. * callback function to set a custom page title. For some tasks, however, you
  325. * may want to simply do some processing and pass control to the next task
  326. * without ending the page request; to indicate this, simply do not send back
  327. * a return value from your task function at all. This can be used, for
  328. * example, by installation profiles that need to configure certain site
  329. * settings in the database without obtaining any input from the user.
  330. *
  331. * The task function is treated specially if it defines a form or requires
  332. * batch processing; in that case, you should return either the form API
  333. * definition or batch API array, as appropriate. See below for more
  334. * information on the 'type' key that you must define in the task definition
  335. * to inform the installer that your task falls into one of those two
  336. * categories. It is important to use these APIs directly, since the installer
  337. * may be run non-interactively (for example, via a command line script), all
  338. * in one page request; in that case, the installer will automatically take
  339. * care of submitting forms and processing batches correctly for both types of
  340. * installations. You can inspect the $install_state['interactive'] boolean to
  341. * see whether or not the current installation is interactive, if you need
  342. * access to this information.
  343. *
  344. * Remember that a user installing Drupal interactively will be able to reload
  345. * an installation page multiple times, so you should use \Drupal::state() to
  346. * store any data that you may need later in the installation process. Any
  347. * temporary state must be removed using \Drupal::state()->delete() before
  348. * your last task has completed and control is handed back to the installer.
  349. *
  350. * @param array $install_state
  351. * An array of information about the current installation state.
  352. *
  353. * @return array
  354. * A keyed array of tasks the profile will perform during the final stage of
  355. * the installation. Each key represents the name of a function (usually a
  356. * function defined by this profile, although that is not strictly required)
  357. * that is called when that task is run. The values are associative arrays
  358. * containing the following key-value pairs (all of which are optional):
  359. * - display_name: The human-readable name of the task. This will be
  360. * displayed to the user while the installer is running, along with a list
  361. * of other tasks that are being run. Leave this unset to prevent the task
  362. * from appearing in the list.
  363. * - display: This is a boolean which can be used to provide finer-grained
  364. * control over whether or not the task will display. This is mostly useful
  365. * for tasks that are intended to display only under certain conditions;
  366. * for these tasks, you can set 'display_name' to the name that you want to
  367. * display, but then use this boolean to hide the task only when certain
  368. * conditions apply.
  369. * - type: A string representing the type of task. This parameter has three
  370. * possible values:
  371. * - normal: (default) This indicates that the task will be treated as a
  372. * regular callback function, which does its processing and optionally
  373. * returns HTML output.
  374. * - batch: This indicates that the task function will return a batch API
  375. * definition suitable for batch_set() or an array of batch definitions
  376. * suitable for consecutive batch_set() calls. The installer will then
  377. * take care of automatically running the task via batch processing.
  378. * - form: This indicates that the task function will return a standard
  379. * form API definition (and separately define validation and submit
  380. * handlers, as appropriate). The installer will then take care of
  381. * automatically directing the user through the form submission process.
  382. * - run: A constant representing the manner in which the task will be run.
  383. * This parameter has three possible values:
  384. * - INSTALL_TASK_RUN_IF_NOT_COMPLETED: (default) This indicates that the
  385. * task will run once during the installation of the profile.
  386. * - INSTALL_TASK_SKIP: This indicates that the task will not run during
  387. * the current installation page request. It can be used to skip running
  388. * an installation task when certain conditions are met, even though the
  389. * task may still show on the list of installation tasks presented to the
  390. * user.
  391. * - INSTALL_TASK_RUN_IF_REACHED: This indicates that the task will run on
  392. * each installation page request that reaches it. This is rarely
  393. * necessary for an installation profile to use; it is primarily used by
  394. * the Drupal installer for bootstrap-related tasks.
  395. * - function: Normally this does not need to be set, but it can be used to
  396. * force the installer to call a different function when the task is run
  397. * (rather than the function whose name is given by the array key). This
  398. * could be used, for example, to allow the same function to be called by
  399. * two different tasks.
  400. *
  401. * @see install_state_defaults()
  402. * @see batch_set()
  403. * @see hook_install_tasks_alter()
  404. * @see install_tasks()
  405. */
  406. function hook_install_tasks(&$install_state) {
  407. // Here, we define a variable to allow tasks to indicate that a particular,
  408. // processor-intensive batch process needs to be triggered later on in the
  409. // installation.
  410. $myprofile_needs_batch_processing = \Drupal::state()->get('myprofile.needs_batch_processing', FALSE);
  411. $tasks = [
  412. // This is an example of a task that defines a form which the user who is
  413. // installing the site will be asked to fill out. To implement this task,
  414. // your profile would define a function named myprofile_data_import_form()
  415. // as a normal form API callback function, with associated validation and
  416. // submit handlers. In the submit handler, in addition to saving whatever
  417. // other data you have collected from the user, you might also call
  418. // \Drupal::state()->set('myprofile.needs_batch_processing', TRUE) if the
  419. // user has entered data which requires that batch processing will need to
  420. // occur later on.
  421. 'myprofile_data_import_form' => [
  422. 'display_name' => t('Data import options'),
  423. 'type' => 'form',
  424. ],
  425. // Similarly, to implement this task, your profile would define a function
  426. // named myprofile_settings_form() with associated validation and submit
  427. // handlers. This form might be used to collect and save additional
  428. // information from the user that your profile needs. There are no extra
  429. // steps required for your profile to act as an "installation wizard"; you
  430. // can simply define as many tasks of type 'form' as you wish to execute,
  431. // and the forms will be presented to the user, one after another.
  432. 'myprofile_settings_form' => [
  433. 'display_name' => t('Additional options'),
  434. 'type' => 'form',
  435. ],
  436. // This is an example of a task that performs batch operations. To
  437. // implement this task, your profile would define a function named
  438. // myprofile_batch_processing() which returns a batch API array definition
  439. // that the installer will use to execute your batch operations. Due to the
  440. // 'myprofile.needs_batch_processing' variable used here, this task will be
  441. // hidden and skipped unless your profile set it to TRUE in one of the
  442. // previous tasks.
  443. 'myprofile_batch_processing' => [
  444. 'display_name' => t('Import additional data'),
  445. 'display' => $myprofile_needs_batch_processing,
  446. 'type' => 'batch',
  447. 'run' => $myprofile_needs_batch_processing ? INSTALL_TASK_RUN_IF_NOT_COMPLETED : INSTALL_TASK_SKIP,
  448. ],
  449. // This is an example of a task that will not be displayed in the list that
  450. // the user sees. To implement this task, your profile would define a
  451. // function named myprofile_final_site_setup(), in which additional,
  452. // automated site setup operations would be performed. Since this is the
  453. // last task defined by your profile, you should also use this function to
  454. // call \Drupal::state()->delete('myprofile.needs_batch_processing') and
  455. // clean up the state that was used above. If you want the user to pass
  456. // to the final Drupal installation tasks uninterrupted, return no output
  457. // from this function. Otherwise, return themed output that the user will
  458. // see (for example, a confirmation page explaining that your profile's
  459. // tasks are complete, with a link to reload the current page and therefore
  460. // pass on to the final Drupal installation tasks when the user is ready to
  461. // do so).
  462. 'myprofile_final_site_setup' => [],
  463. ];
  464. return $tasks;
  465. }
  466. /**
  467. * Alter the full list of installation tasks.
  468. *
  469. * You can use this hook to change or replace any part of the Drupal
  470. * installation process that occurs after the installation profile is selected.
  471. *
  472. * This hook is invoked on the install profile in install_tasks().
  473. *
  474. * @param $tasks
  475. * An array of all available installation tasks, including those provided by
  476. * Drupal core. You can modify this array to change or replace individual
  477. * steps within the installation process.
  478. * @param $install_state
  479. * An array of information about the current installation state.
  480. *
  481. * @see hook_install_tasks()
  482. * @see install_tasks()
  483. */
  484. function hook_install_tasks_alter(&$tasks, $install_state) {
  485. // Replace the entire site configuration form provided by Drupal core
  486. // with a custom callback function defined by this installation profile.
  487. $tasks['install_configure_form']['function'] = 'myprofile_install_configure_form';
  488. }
  489. /**
  490. * Perform a single update between minor versions.
  491. *
  492. * Hook hook_update_N() can only be used to update between minor versions of a
  493. * module. To upgrade between major versions of Drupal (for example, between
  494. * Drupal 7 and 8), use the @link migrate Migrate API @endlink instead.
  495. *
  496. * @section sec_naming Naming and documenting your function
  497. * For each change in a module that requires one or more actions to be performed
  498. * when updating a site, add a new implementation of hook_update_N() to your
  499. * mymodule.install file (assuming mymodule is the machine name of your module).
  500. * Implementations of hook_update_N() are named (module name)_update_(number).
  501. * The numbers are normally composed of three parts:
  502. * - 1 or 2 digits for Drupal core compatibility (Drupal 8, 9, 10, etc.). This
  503. * convention must be followed.
  504. * - 1 digit for your module's major release version; for example, for 8.x-1.*
  505. * use 1, for 8.x-2.* use 2, for Core 8.0.x use 0, and for Core 8.1.x use 1.
  506. * This convention is optional but suggested for clarity.
  507. * - 2 digits for sequential counting, starting with 01. Note that the x000
  508. * number can never be used: the lowest update number that will be recognized
  509. * and run for major version x is x001.
  510. * Examples:
  511. * - node_update_8001(): The first update for the Drupal 8.0.x version of the
  512. * Drupal Core node module.
  513. * - mymodule_update_8101(): The first update for your custom or contributed
  514. * module's 8.x-1.x versions.
  515. * - mymodule_update_8201(): The first update for the 8.x-2.x versions.
  516. *
  517. * Never renumber update functions. The numeric part of the hook implementation
  518. * function is stored in the database to keep track of which updates have run,
  519. * so it is important to maintain this information consistently.
  520. *
  521. * The documentation block preceding this function is stripped of newlines and
  522. * used as the description for the update on the pending updates task list,
  523. * which users will see when they run the update.php script.
  524. *
  525. * @section sec_notes Notes about the function body
  526. * Writing hook_update_N() functions is tricky. There are several reasons why
  527. * this is the case:
  528. * - You do not know when updates will be run: someone could be keeping up with
  529. * every update and run them when the database and code are in the same state
  530. * as when you wrote your update function, or they could have waited until a
  531. * few more updates have come out, and run several at the same time.
  532. * - You do not know the state of other modules' updates either.
  533. * - Other modules can use hook_update_dependencies() to run updates between
  534. * your module's updates, so you also cannot count on your functions running
  535. * right after one another.
  536. * - You do not know what environment your update will run in (which modules
  537. * are installed, whether certain hooks are implemented or not, whether
  538. * services are overridden, etc.).
  539. *
  540. * Because of these reasons, you'll need to use care in writing your update
  541. * function. Some things to think about:
  542. * - Never assume that the database schema is the same when the update will run
  543. * as it is when you wrote the update function. So, when updating a database
  544. * table or field, put the schema information you want to update to directly
  545. * into your function instead of calling your hook_schema() function to
  546. * retrieve it (this is one case where the right thing to do is copy and paste
  547. * the code).
  548. * - Never assume that the configuration schema is the same when the update will
  549. * run as it is when you wrote the update function. So, when saving
  550. * configuration, use the $has_trusted_data = TRUE parameter so that schema is
  551. * ignored, and make sure that the configuration data you are saving matches
  552. * the configuration schema at the time when you write the update function
  553. * (later updates may change it again to match new schema changes).
  554. * - Never assume your field or entity type definitions are the same when the
  555. * update will run as they are when you wrote the update function. Always
  556. * retrieve the correct version via
  557. * \Drupal::entityDefinitionUpdateManager()::getEntityType() or
  558. * \Drupal::entityDefinitionUpdateManager()::getFieldStorageDefinition(). When
  559. * adding a new definition always replicate it in the update function body as
  560. * you would do with a schema definition.
  561. * - Never call \Drupal::entityDefinitionUpdateManager()::applyUpdates() in an
  562. * update function, as it will apply updates for any module not only yours,
  563. * which will lead to unpredictable results.
  564. * - Be careful about API functions and especially CRUD operations that you use
  565. * in your update function. If they invoke hooks or use services, they may
  566. * not behave as expected, and it may actually not be appropriate to use the
  567. * normal API functions that invoke all the hooks, use the database schema,
  568. * and/or use services in an update function -- you may need to switch to
  569. * using a more direct method (database query, etc.).
  570. * - In particular, loading, saving, or performing any other CRUD operation on
  571. * an entity is never safe to do (they always involve hooks and services).
  572. * - Never rebuild the router during an update function.
  573. *
  574. * The following actions are examples of things that are safe to do during
  575. * updates:
  576. * - Cache invalidation.
  577. * - Using \Drupal::configFactory()->getEditable() and \Drupal::config(), as
  578. * long as you make sure that your update data matches the schema, and you
  579. * use the $has_trusted_data argument in the save operation.
  580. * - Marking a container for rebuild.
  581. * - Using the API provided by \Drupal::entityDefinitionUpdateManager() to
  582. * update the entity schema based on changes in entity type or field
  583. * definitions provided by your module.
  584. *
  585. * See https://www.drupal.org/node/2535316 for more on writing update functions.
  586. *
  587. * @section sec_bulk Batch updates
  588. * If running your update all at once could possibly cause PHP to time out, use
  589. * the $sandbox parameter to indicate that the Batch API should be used for your
  590. * update. In this case, your update function acts as an implementation of
  591. * callback_batch_operation(), and $sandbox acts as the batch context
  592. * parameter. In your function, read the state information from the previous
  593. * run from $sandbox (or initialize), run a chunk of updates, save the state in
  594. * $sandbox, and set $sandbox['#finished'] to a value between 0 and 1 to
  595. * indicate the percent completed, or 1 if it is finished (you need to do this
  596. * explicitly in each pass).
  597. *
  598. * See the @link batch Batch operations topic @endlink for more information on
  599. * how to use the Batch API.
  600. *
  601. * @param array $sandbox
  602. * Stores information for batch updates. See above for more information.
  603. *
  604. * @return string|null
  605. * Optionally, update hooks may return a translated string that will be
  606. * displayed to the user after the update has completed. If no message is
  607. * returned, no message will be presented to the user.
  608. *
  609. * @throws \Drupal\Core\Utility\UpdateException|PDOException
  610. * In case of error, update hooks should throw an instance of
  611. * Drupal\Core\Utility\UpdateException with a meaningful message for the user.
  612. * If a database query fails for whatever reason, it will throw a
  613. * PDOException.
  614. *
  615. * @ingroup update_api
  616. *
  617. * @see batch
  618. * @see schemaapi
  619. * @see hook_update_last_removed()
  620. * @see update_get_update_list()
  621. * @see \Drupal\Core\Entity\EntityDefinitionUpdateManagerInterface
  622. * @see node_update_8001
  623. * @see system_update_8004
  624. * @see https://www.drupal.org/node/2535316
  625. */
  626. function hook_update_N(&$sandbox) {
  627. // For non-batch updates, the signature can simply be:
  628. // function hook_update_N() {
  629. // Example function body for adding a field to a database table, which does
  630. // not require a batch operation:
  631. $spec = [
  632. 'type' => 'varchar',
  633. 'description' => "New Col",
  634. 'length' => 20,
  635. 'not null' => FALSE,
  636. ];
  637. $schema = Database::getConnection()->schema();
  638. $schema->addField('mytable1', 'newcol', $spec);
  639. // Example of what to do if there is an error during your update.
  640. if ($some_error_condition_met) {
  641. throw new UpdateException('Something went wrong; here is what you should do.');
  642. }
  643. // Example function body for a batch update. In this example, the values in
  644. // a database field are updated.
  645. if (!isset($sandbox['progress'])) {
  646. // This must be the first run. Initialize the sandbox.
  647. $sandbox['progress'] = 0;
  648. $sandbox['current_pk'] = 0;
  649. $sandbox['max'] = Database::getConnection()->query('SELECT COUNT(myprimarykey) FROM {mytable1}')->fetchField();
  650. }
  651. // Update in chunks of 20.
  652. $records = Database::getConnection()->select('mytable1', 'm')
  653. ->fields('m', ['myprimarykey', 'otherfield'])
  654. ->condition('myprimarykey', $sandbox['current_pk'], '>')
  655. ->range(0, 20)
  656. ->orderBy('myprimarykey', 'ASC')
  657. ->execute();
  658. foreach ($records as $record) {
  659. // Here, you would make an update something related to this record. In this
  660. // example, some text is added to the other field.
  661. Database::getConnection()->update('mytable1')
  662. ->fields(['otherfield' => $record->otherfield . '-suffix'])
  663. ->condition('myprimarykey', $record->myprimarykey)
  664. ->execute();
  665. $sandbox['progress']++;
  666. $sandbox['current_pk'] = $record->myprimarykey;
  667. }
  668. $sandbox['#finished'] = empty($sandbox['max']) ? 1 : ($sandbox['progress'] / $sandbox['max']);
  669. // To display a message to the user when the update is completed, return it.
  670. // If you do not want to display a completion message, return nothing.
  671. return t('All foo bars were updated with the new suffix');
  672. }
  673. /**
  674. * Executes an update which is intended to update data, like entities.
  675. *
  676. * These implementations have to be placed in a MODULE.post_update.php file.
  677. *
  678. * These updates are executed after all hook_update_N() implementations. At this
  679. * stage Drupal is already fully repaired so you can use any API as you wish.
  680. *
  681. * NAME can be arbitrary machine names. In contrast to hook_update_N() the
  682. * alphanumeric naming of functions in the file is the only thing which ensures
  683. * the execution order of those functions. If update order is mandatory,
  684. * you should add numerical prefix to NAME or make it completely numerical.
  685. *
  686. * Drupal also ensures to not execute the same hook_post_update_NAME() function
  687. * twice.
  688. *
  689. * @section sec_bulk Batch updates
  690. * If running your update all at once could possibly cause PHP to time out, use
  691. * the $sandbox parameter to indicate that the Batch API should be used for your
  692. * update. In this case, your update function acts as an implementation of
  693. * callback_batch_operation(), and $sandbox acts as the batch context
  694. * parameter. In your function, read the state information from the previous
  695. * run from $sandbox (or initialize), run a chunk of updates, save the state in
  696. * $sandbox, and set $sandbox['#finished'] to a value between 0 and 1 to
  697. * indicate the percent completed, or 1 if it is finished (you need to do this
  698. * explicitly in each pass).
  699. *
  700. * See the @link batch Batch operations topic @endlink for more information on
  701. * how to use the Batch API.
  702. *
  703. * @param array $sandbox
  704. * Stores information for batch updates. See above for more information.
  705. *
  706. * @return string|null
  707. * Optionally, hook_post_update_NAME() hooks may return a translated string
  708. * that will be displayed to the user after the update has completed. If no
  709. * message is returned, no message will be presented to the user.
  710. *
  711. * @throws \Drupal\Core\Utility\UpdateException|PDOException
  712. * In case of error, update hooks should throw an instance of
  713. * \Drupal\Core\Utility\UpdateException with a meaningful message for the
  714. * user. If a database query fails for whatever reason, it will throw a
  715. * PDOException.
  716. *
  717. * @ingroup update_api
  718. *
  719. * @see hook_update_N()
  720. * @see hook_removed_post_updates()
  721. */
  722. function hook_post_update_NAME(&$sandbox) {
  723. // Example of updating some content.
  724. $node = \Drupal\node\Entity\Node::load(123);
  725. $node->setTitle('foo');
  726. $node->save();
  727. $result = t('Node %nid saved', ['%nid' => $node->id()]);
  728. // Example of disabling blocks with missing condition contexts. Note: The
  729. // block itself is in a state which is valid at that point.
  730. // @see block_update_8001()
  731. // @see block_post_update_disable_blocks_with_missing_contexts()
  732. $block_update_8001 = \Drupal::keyValue('update_backup')->get('block_update_8001', []);
  733. $block_ids = array_keys($block_update_8001);
  734. $block_storage = \Drupal::entityTypeManager()->getStorage('block');
  735. $blocks = $block_storage->loadMultiple($block_ids);
  736. /** @var $blocks \Drupal\block\BlockInterface[] */
  737. foreach ($blocks as $block) {
  738. // This block has had conditions removed due to an inability to resolve
  739. // contexts in block_update_8001() so disable it.
  740. // Disable currently enabled blocks.
  741. if ($block_update_8001[$block->id()]['status']) {
  742. $block->setStatus(FALSE);
  743. $block->save();
  744. }
  745. }
  746. return $result;
  747. }
  748. /**
  749. * Return an array of removed hook_post_update_NAME() function names.
  750. *
  751. * This should be used to indicate post-update functions that have existed in
  752. * some previous version of the module, but are no longer available.
  753. *
  754. * This implementation has to be placed in a MODULE.post_update.php file.
  755. *
  756. * @return string[]
  757. * An array where the keys are removed post-update function names, and the
  758. * values are the first stable version in which the update was removed.
  759. *
  760. * @ingroup update_api
  761. *
  762. * @see hook_post_update_NAME()
  763. */
  764. function hook_removed_post_updates() {
  765. return [
  766. 'mymodule_post_update_foo' => '8.x-2.0',
  767. 'mymodule_post_update_bar' => '8.x-3.0',
  768. 'mymodule_post_update_baz' => '8.x-3.0',
  769. ];
  770. }
  771. /**
  772. * Return an array of information about module update dependencies.
  773. *
  774. * This can be used to indicate update functions from other modules that your
  775. * module's update functions depend on, or vice versa. It is used by the update
  776. * system to determine the appropriate order in which updates should be run, as
  777. * well as to search for missing dependencies.
  778. *
  779. * Implementations of this hook should be placed in a mymodule.install file in
  780. * the same directory as mymodule.module.
  781. *
  782. * @return
  783. * A multidimensional array containing information about the module update
  784. * dependencies. The first two levels of keys represent the module and update
  785. * number (respectively) for which information is being returned, and the
  786. * value is an array of information about that update's dependencies. Within
  787. * this array, each key represents a module, and each value represents the
  788. * number of an update function within that module. In the event that your
  789. * update function depends on more than one update from a particular module,
  790. * you should always list the highest numbered one here (since updates within
  791. * a given module always run in numerical order).
  792. *
  793. * @ingroup update_api
  794. *
  795. * @see update_resolve_dependencies()
  796. * @see hook_update_N()
  797. */
  798. function hook_update_dependencies() {
  799. // Indicate that the mymodule_update_8001() function provided by this module
  800. // must run after the another_module_update_8003() function provided by the
  801. // 'another_module' module.
  802. $dependencies['mymodule'][8001] = [
  803. 'another_module' => 8003,
  804. ];
  805. // Indicate that the mymodule_update_8002() function provided by this module
  806. // must run before the yet_another_module_update_8005() function provided by
  807. // the 'yet_another_module' module. (Note that declaring dependencies in this
  808. // direction should be done only in rare situations, since it can lead to the
  809. // following problem: If a site has already run the yet_another_module
  810. // module's database updates before it updates its codebase to pick up the
  811. // newest mymodule code, then the dependency declared here will be ignored.)
  812. $dependencies['yet_another_module'][8005] = [
  813. 'mymodule' => 8002,
  814. ];
  815. return $dependencies;
  816. }
  817. /**
  818. * Return a number which is no longer available as hook_update_N().
  819. *
  820. * If you remove some update functions from your mymodule.install file, you
  821. * should notify Drupal of those missing functions. This way, Drupal can
  822. * ensure that no update is accidentally skipped.
  823. *
  824. * Implementations of this hook should be placed in a mymodule.install file in
  825. * the same directory as mymodule.module.
  826. *
  827. * @return
  828. * An integer, corresponding to hook_update_N() which has been removed from
  829. * mymodule.install.
  830. *
  831. * @ingroup update_api
  832. *
  833. * @see hook_update_N()
  834. */
  835. function hook_update_last_removed() {
  836. // We've removed the 8.x-1.x version of mymodule, including database updates.
  837. // The next update function is mymodule_update_8200().
  838. return 8103;
  839. }
  840. /**
  841. * Provide information on Updaters (classes that can update Drupal).
  842. *
  843. * Drupal\Core\Updater\Updater is a class that knows how to update various parts
  844. * of the Drupal file system, for example to update modules that have newer
  845. * releases, or to install a new theme.
  846. *
  847. * @return
  848. * An associative array of information about the updater(s) being provided.
  849. * This array is keyed by a unique identifier for each updater, and the
  850. * values are subarrays that can contain the following keys:
  851. * - class: The name of the PHP class which implements this updater.
  852. * - name: Human-readable name of this updater.
  853. * - weight: Controls what order the Updater classes are consulted to decide
  854. * which one should handle a given task. When an update task is being run,
  855. * the system will loop through all the Updater classes defined in this
  856. * registry in weight order and let each class respond to the task and
  857. * decide if each Updater wants to handle the task. In general, this
  858. * doesn't matter, but if you need to override an existing Updater, make
  859. * sure your Updater has a lighter weight so that it comes first.
  860. *
  861. * @ingroup update_api
  862. *
  863. * @see drupal_get_updaters()
  864. * @see hook_updater_info_alter()
  865. */
  866. function hook_updater_info() {
  867. return [
  868. 'module' => [
  869. 'class' => 'Drupal\Core\Updater\Module',
  870. 'name' => t('Update modules'),
  871. 'weight' => 0,
  872. ],
  873. 'theme' => [
  874. 'class' => 'Drupal\Core\Updater\Theme',
  875. 'name' => t('Update themes'),
  876. 'weight' => 0,
  877. ],
  878. ];
  879. }
  880. /**
  881. * Alter the Updater information array.
  882. *
  883. * An Updater is a class that knows how to update various parts of the Drupal
  884. * file system, for example to update modules that have newer releases, or to
  885. * install a new theme.
  886. *
  887. * @param array $updaters
  888. * Associative array of updaters as defined through hook_updater_info().
  889. * Alter this array directly.
  890. *
  891. * @ingroup update_api
  892. *
  893. * @see drupal_get_updaters()
  894. * @see hook_updater_info()
  895. */
  896. function hook_updater_info_alter(&$updaters) {
  897. // Adjust weight so that the theme Updater gets a chance to handle a given
  898. // update task before module updaters.
  899. $updaters['theme']['weight'] = -1;
  900. }
  901. /**
  902. * Check installation requirements and do status reporting.
  903. *
  904. * This hook has three closely related uses, determined by the $phase argument:
  905. * - Checking installation requirements ($phase == 'install').
  906. * - Checking update requirements ($phase == 'update').
  907. * - Status reporting ($phase == 'runtime').
  908. *
  909. * Note that this hook, like all others dealing with installation and updates,
  910. * must reside in a module_name.install file, or it will not properly abort
  911. * the installation of the module if a critical requirement is missing.
  912. *
  913. * During the 'install' phase, modules can for example assert that
  914. * library or server versions are available or sufficient.
  915. * Note that the installation of a module can happen during installation of
  916. * Drupal itself (by install.php) with an installation profile or later by hand.
  917. * As a consequence, install-time requirements must be checked without access
  918. * to the full Drupal API, because it is not available during install.php.
  919. * If a requirement has a severity of REQUIREMENT_ERROR, install.php will abort
  920. * or at least the module will not install.
  921. * Other severity levels have no effect on the installation.
  922. * Module dependencies do not belong to these installation requirements,
  923. * but should be defined in the module's .info.yml file.
  924. *
  925. * During installation (when $phase == 'install'), if you need to load a class
  926. * from your module, you'll need to include the class file directly.
  927. *
  928. * The 'runtime' phase is not limited to pure installation requirements
  929. * but can also be used for more general status information like maintenance
  930. * tasks and security issues.
  931. * The returned 'requirements' will be listed on the status report in the
  932. * administration section, with indication of the severity level.
  933. * Moreover, any requirement with a severity of REQUIREMENT_ERROR severity will
  934. * result in a notice on the administration configuration page.
  935. *
  936. * @param $phase
  937. * The phase in which requirements are checked:
  938. * - install: The module is being installed.
  939. * - update: The module is enabled and update.php is run.
  940. * - runtime: The runtime requirements are being checked and shown on the
  941. * status report page.
  942. *
  943. * @return
  944. * An associative array where the keys are arbitrary but must be unique (it
  945. * is suggested to use the module short name as a prefix) and the values are
  946. * themselves associative arrays with the following elements:
  947. * - title: The name of the requirement.
  948. * - value: The current value (e.g., version, time, level, etc). During
  949. * install phase, this should only be used for version numbers, do not set
  950. * it if not applicable.
  951. * - description: The description of the requirement/status.
  952. * - severity: The requirement's result/severity level, one of:
  953. * - REQUIREMENT_INFO: For info only.
  954. * - REQUIREMENT_OK: The requirement is satisfied.
  955. * - REQUIREMENT_WARNING: The requirement failed with a warning.
  956. * - REQUIREMENT_ERROR: The requirement failed with an error.
  957. */
  958. function hook_requirements($phase) {
  959. $requirements = [];
  960. // Report Drupal version
  961. if ($phase == 'runtime') {
  962. $requirements['drupal'] = [
  963. 'title' => t('Drupal'),
  964. 'value' => \Drupal::VERSION,
  965. 'severity' => REQUIREMENT_INFO,
  966. ];
  967. }
  968. // Test PHP version
  969. $requirements['php'] = [
  970. 'title' => t('PHP'),
  971. 'value' => ($phase == 'runtime') ? Link::fromTextAndUrl(phpversion(), Url::fromRoute('system.php'))->toString() : phpversion(),
  972. ];
  973. if (version_compare(phpversion(), DRUPAL_MINIMUM_PHP) < 0) {
  974. $requirements['php']['description'] = t('Your PHP installation is too old. Drupal requires at least PHP %version.', ['%version' => DRUPAL_MINIMUM_PHP]);
  975. $requirements['php']['severity'] = REQUIREMENT_ERROR;
  976. }
  977. // Report cron status
  978. if ($phase == 'runtime') {
  979. $cron_last = \Drupal::state()->get('system.cron_last');
  980. if (is_numeric($cron_last)) {
  981. $requirements['cron']['value'] = t('Last run @time ago', ['@time' => \Drupal::service('date.formatter')->formatTimeDiffSince($cron_last)]);
  982. }
  983. else {
  984. $requirements['cron'] = [
  985. 'description' => t('Cron has not run. It appears cron jobs have not been setup on your system. Check the help pages for <a href=":url">configuring cron jobs</a>.', [':url' => 'https://www.drupal.org/cron']),
  986. 'severity' => REQUIREMENT_ERROR,
  987. 'value' => t('Never run'),
  988. ];
  989. }
  990. $requirements['cron']['description'] .= ' ' . t('You can <a href=":cron">run cron manually</a>.', [':cron' => Url::fromRoute('system.run_cron')->toString()]);
  991. $requirements['cron']['title'] = t('Cron maintenance tasks');
  992. }
  993. return $requirements;
  994. }
  995. /**
  996. * @} End of "addtogroup hooks".
  997. */