784 lines
34 KiB
PHP
784 lines
34 KiB
PHP
<?php
|
|
|
|
/**
|
|
* @file
|
|
* Hooks related to module and update systems.
|
|
*/
|
|
|
|
use Drupal\Core\Utility\UpdateException;
|
|
use Drupal\Core\Url;
|
|
|
|
/**
|
|
* @addtogroup hooks
|
|
* @{
|
|
*/
|
|
|
|
/**
|
|
* Defines one or more hooks that are exposed by a module.
|
|
*
|
|
* Normally hooks do not need to be explicitly defined. However, by declaring a
|
|
* hook explicitly, a module may define a "group" for it. Modules that implement
|
|
* a hook may then place their implementation in either $module.module or in
|
|
* $module.$group.inc. If the hook is located in $module.$group.inc, then that
|
|
* file will be automatically loaded when needed.
|
|
* In general, hooks that are rarely invoked and/or are very large should be
|
|
* placed in a separate include file, while hooks that are very short or very
|
|
* frequently called should be left in the main module file so that they are
|
|
* always available.
|
|
*
|
|
* @return
|
|
* An associative array whose keys are hook names and whose values are an
|
|
* associative array containing:
|
|
* - group: A string defining the group to which the hook belongs. The module
|
|
* system will determine whether a file with the name $module.$group.inc
|
|
* exists, and automatically load it when required.
|
|
*
|
|
* See system_hook_info() for all hook groups defined by Drupal core.
|
|
*
|
|
* @see hook_hook_info_alter().
|
|
*/
|
|
function hook_hook_info() {
|
|
$hooks['token_info'] = array(
|
|
'group' => 'tokens',
|
|
);
|
|
$hooks['tokens'] = array(
|
|
'group' => 'tokens',
|
|
);
|
|
return $hooks;
|
|
}
|
|
|
|
/**
|
|
* Alter the registry of modules implementing a hook.
|
|
*
|
|
* This hook is invoked during \Drupal::moduleHandler()->getImplementations().
|
|
* A module may implement this hook in order to reorder the implementing
|
|
* modules, which are otherwise ordered by the module's system weight.
|
|
*
|
|
* Note that hooks invoked using \Drupal::moduleHandler->alter() can have
|
|
* multiple variations(such as hook_form_alter() and hook_form_FORM_ID_alter()).
|
|
* \Drupal::moduleHandler->alter() will call all such variants defined by a
|
|
* single module in turn. For the purposes of hook_module_implements_alter(),
|
|
* these variants are treated as a single hook. Thus, to ensure that your
|
|
* implementation of hook_form_FORM_ID_alter() is called at the right time,
|
|
* you will have to change the order of hook_form_alter() implementation in
|
|
* hook_module_implements_alter().
|
|
*
|
|
* @param $implementations
|
|
* An array keyed by the module's name. The value of each item corresponds
|
|
* to a $group, which is usually FALSE, unless the implementation is in a
|
|
* file named $module.$group.inc.
|
|
* @param $hook
|
|
* The name of the module hook being implemented.
|
|
*/
|
|
function hook_module_implements_alter(&$implementations, $hook) {
|
|
if ($hook == 'form_alter') {
|
|
// Move my_module_form_alter() to the end of the list.
|
|
// \Drupal::moduleHandler()->getImplementations()
|
|
// iterates through $implementations with a foreach loop which PHP iterates
|
|
// in the order that the items were added, so to move an item to the end of
|
|
// the array, we remove it and then add it.
|
|
$group = $implementations['my_module'];
|
|
unset($implementations['my_module']);
|
|
$implementations['my_module'] = $group;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Alter the information parsed from module and theme .info.yml files
|
|
*
|
|
* This hook is invoked in _system_rebuild_module_data() and in
|
|
* \Drupal\Core\Extension\ThemeHandlerInterface::rebuildThemeData(). A module
|
|
* may implement this hook in order to add to or alter the data generated by
|
|
* reading the .info.yml file with \Drupal\Core\Extension\InfoParser.
|
|
*
|
|
* @param array $info
|
|
* The .info.yml file contents, passed by reference so that it can be altered.
|
|
* @param \Drupal\Core\Extension\Extension $file
|
|
* Full information about the module or theme.
|
|
* @param string $type
|
|
* Either 'module' or 'theme', depending on the type of .info.yml file that
|
|
* was passed.
|
|
*/
|
|
function hook_system_info_alter(array &$info, \Drupal\Core\Extension\Extension $file, $type) {
|
|
// Only fill this in if the .info.yml file does not define a 'datestamp'.
|
|
if (empty($info['datestamp'])) {
|
|
$info['datestamp'] = $file->getMTime();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Perform necessary actions before a module is installed.
|
|
*
|
|
* @param string $module
|
|
* The name of the module about to be installed.
|
|
*/
|
|
function hook_module_preinstall($module) {
|
|
mymodule_cache_clear();
|
|
}
|
|
|
|
/**
|
|
* Perform necessary actions after modules are installed.
|
|
*
|
|
* This function differs from hook_install() in that it gives all other modules
|
|
* a chance to perform actions when a module is installed, whereas
|
|
* hook_install() is only called on the module actually being installed. See
|
|
* \Drupal\Core\Extension\ModuleHandler::install() for a detailed description of
|
|
* the order in which install hooks are invoked.
|
|
*
|
|
* @param $modules
|
|
* An array of the modules that were installed.
|
|
*
|
|
* @see \Drupal\Core\Extension\ModuleHandler::install()
|
|
* @see hook_install()
|
|
*/
|
|
function hook_modules_installed($modules) {
|
|
if (in_array('lousy_module', $modules)) {
|
|
\Drupal::state()->set('mymodule.lousy_module_compatibility', TRUE);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Perform setup tasks when the module is installed.
|
|
*
|
|
* If the module implements hook_schema(), the database tables will
|
|
* be created before this hook is fired.
|
|
*
|
|
* Implementations of this hook are by convention declared in the module's
|
|
* .install file. The implementation can rely on the .module file being loaded.
|
|
* The hook will only be called when a module is installed. The module's schema
|
|
* version will be set to the module's greatest numbered update hook. Because of
|
|
* this, any time a hook_update_N() is added to the module, this function needs
|
|
* to be updated to reflect the current version of the database schema.
|
|
*
|
|
* See the @link http://drupal.org/node/146843 Schema API documentation @endlink
|
|
* for details on hook_schema and how database tables are defined.
|
|
*
|
|
* Note that since this function is called from a full bootstrap, all functions
|
|
* (including those in modules enabled by the current page request) are
|
|
* available when this hook is called. Use cases could be displaying a user
|
|
* message, or calling a module function necessary for initial setup, etc.
|
|
*
|
|
* Please be sure that anything added or modified in this function that can
|
|
* be removed during uninstall should be removed with hook_uninstall().
|
|
*
|
|
* @see hook_schema()
|
|
* @see \Drupal\Core\Extension\ModuleHandler::install()
|
|
* @see hook_uninstall()
|
|
* @see hook_modules_installed()
|
|
*/
|
|
function hook_install() {
|
|
// Create the styles directory and ensure it's writable.
|
|
$directory = file_default_scheme() . '://styles';
|
|
$mode = isset($GLOBALS['install_state']['mode']) ? $GLOBALS['install_state']['mode'] : NULL;
|
|
file_prepare_directory($directory, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS, $mode);
|
|
}
|
|
|
|
/**
|
|
* Perform necessary actions before a module is uninstalled.
|
|
*
|
|
* @param string $module
|
|
* The name of the module about to be uninstalled.
|
|
*/
|
|
function hook_module_preuninstall($module) {
|
|
mymodule_cache_clear();
|
|
}
|
|
|
|
/**
|
|
* Perform necessary actions after modules are uninstalled.
|
|
*
|
|
* This function differs from hook_uninstall() in that it gives all other
|
|
* modules a chance to perform actions when a module is uninstalled, whereas
|
|
* hook_uninstall() is only called on the module actually being uninstalled.
|
|
*
|
|
* It is recommended that you implement this hook if your module stores
|
|
* data that may have been set by other modules.
|
|
*
|
|
* @param $modules
|
|
* An array of the modules that were uninstalled.
|
|
*
|
|
* @see hook_uninstall()
|
|
*/
|
|
function hook_modules_uninstalled($modules) {
|
|
if (in_array('lousy_module', $modules)) {
|
|
\Drupal::state()->delete('mymodule.lousy_module_compatibility');
|
|
}
|
|
mymodule_cache_rebuild();
|
|
}
|
|
|
|
/**
|
|
* Remove any information that the module sets.
|
|
*
|
|
* The information that the module should remove includes:
|
|
* - state that the module has set using \Drupal::state()
|
|
* - modifications to existing tables
|
|
*
|
|
* The module should not remove its entry from the module configuration.
|
|
* Database tables defined by hook_schema() will be removed automatically.
|
|
*
|
|
* The uninstall hook must be implemented in the module's .install file. It
|
|
* will fire when the module gets uninstalled but before the module's database
|
|
* tables are removed, allowing your module to query its own tables during
|
|
* this routine.
|
|
*
|
|
* @see hook_install()
|
|
* @see hook_schema()
|
|
* @see hook_modules_uninstalled()
|
|
*/
|
|
function hook_uninstall() {
|
|
// Remove the styles directory and generated images.
|
|
file_unmanaged_delete_recursive(file_default_scheme() . '://styles');
|
|
}
|
|
|
|
/**
|
|
* Return an array of tasks to be performed by an installation profile.
|
|
*
|
|
* Any tasks you define here will be run, in order, after the installer has
|
|
* finished the site configuration step but before it has moved on to the
|
|
* final import of languages and the end of the installation. This is invoked
|
|
* by install_tasks(). You can have any number of custom tasks to perform
|
|
* during this phase.
|
|
*
|
|
* Each task you define here corresponds to a callback function which you must
|
|
* separately define and which is called when your task is run. This function
|
|
* will receive the global installation state variable, $install_state, as
|
|
* input, and has the opportunity to access or modify any of its settings. See
|
|
* the install_state_defaults() function in the installer for the list of
|
|
* $install_state settings used by Drupal core.
|
|
*
|
|
* At the end of your task function, you can indicate that you want the
|
|
* installer to pause and display a page to the user by returning any themed
|
|
* output that should be displayed on that page (but see below for tasks that
|
|
* use the form API or batch API; the return values of these task functions are
|
|
* handled differently). You should also use #title within the task
|
|
* callback function to set a custom page title. For some tasks, however, you
|
|
* may want to simply do some processing and pass control to the next task
|
|
* without ending the page request; to indicate this, simply do not send back
|
|
* a return value from your task function at all. This can be used, for
|
|
* example, by installation profiles that need to configure certain site
|
|
* settings in the database without obtaining any input from the user.
|
|
*
|
|
* The task function is treated specially if it defines a form or requires
|
|
* batch processing; in that case, you should return either the form API
|
|
* definition or batch API array, as appropriate. See below for more
|
|
* information on the 'type' key that you must define in the task definition
|
|
* to inform the installer that your task falls into one of those two
|
|
* categories. It is important to use these APIs directly, since the installer
|
|
* may be run non-interactively (for example, via a command line script), all
|
|
* in one page request; in that case, the installer will automatically take
|
|
* care of submitting forms and processing batches correctly for both types of
|
|
* installations. You can inspect the $install_state['interactive'] boolean to
|
|
* see whether or not the current installation is interactive, if you need
|
|
* access to this information.
|
|
*
|
|
* Remember that a user installing Drupal interactively will be able to reload
|
|
* an installation page multiple times, so you should use \Drupal::state() to
|
|
* store any data that you may need later in the installation process. Any
|
|
* temporary state must be removed using \Drupal::state()->delete() before
|
|
* your last task has completed and control is handed back to the installer.
|
|
*
|
|
* @param array $install_state
|
|
* An array of information about the current installation state.
|
|
*
|
|
* @return array
|
|
* A keyed array of tasks the profile will perform during the final stage of
|
|
* the installation. Each key represents the name of a function (usually a
|
|
* function defined by this profile, although that is not strictly required)
|
|
* that is called when that task is run. The values are associative arrays
|
|
* containing the following key-value pairs (all of which are optional):
|
|
* - display_name: The human-readable name of the task. This will be
|
|
* displayed to the user while the installer is running, along with a list
|
|
* of other tasks that are being run. Leave this unset to prevent the task
|
|
* from appearing in the list.
|
|
* - display: This is a boolean which can be used to provide finer-grained
|
|
* control over whether or not the task will display. This is mostly useful
|
|
* for tasks that are intended to display only under certain conditions;
|
|
* for these tasks, you can set 'display_name' to the name that you want to
|
|
* display, but then use this boolean to hide the task only when certain
|
|
* conditions apply.
|
|
* - type: A string representing the type of task. This parameter has three
|
|
* possible values:
|
|
* - normal: (default) This indicates that the task will be treated as a
|
|
* regular callback function, which does its processing and optionally
|
|
* returns HTML output.
|
|
* - batch: This indicates that the task function will return a batch API
|
|
* definition suitable for batch_set() or an array of batch definitions
|
|
* suitable for consecutive batch_set() calls. The installer will then
|
|
* take care of automatically running the task via batch processing.
|
|
* - form: This indicates that the task function will return a standard
|
|
* form API definition (and separately define validation and submit
|
|
* handlers, as appropriate). The installer will then take care of
|
|
* automatically directing the user through the form submission process.
|
|
* - run: A constant representing the manner in which the task will be run.
|
|
* This parameter has three possible values:
|
|
* - INSTALL_TASK_RUN_IF_NOT_COMPLETED: (default) This indicates that the
|
|
* task will run once during the installation of the profile.
|
|
* - INSTALL_TASK_SKIP: This indicates that the task will not run during
|
|
* the current installation page request. It can be used to skip running
|
|
* an installation task when certain conditions are met, even though the
|
|
* task may still show on the list of installation tasks presented to the
|
|
* user.
|
|
* - INSTALL_TASK_RUN_IF_REACHED: This indicates that the task will run on
|
|
* each installation page request that reaches it. This is rarely
|
|
* necessary for an installation profile to use; it is primarily used by
|
|
* the Drupal installer for bootstrap-related tasks.
|
|
* - function: Normally this does not need to be set, but it can be used to
|
|
* force the installer to call a different function when the task is run
|
|
* (rather than the function whose name is given by the array key). This
|
|
* could be used, for example, to allow the same function to be called by
|
|
* two different tasks.
|
|
*
|
|
* @see install_state_defaults()
|
|
* @see batch_set()
|
|
* @see hook_install_tasks_alter()
|
|
* @see install_tasks()
|
|
*/
|
|
function hook_install_tasks(&$install_state) {
|
|
// Here, we define a variable to allow tasks to indicate that a particular,
|
|
// processor-intensive batch process needs to be triggered later on in the
|
|
// installation.
|
|
$myprofile_needs_batch_processing = \Drupal::state()->get('myprofile.needs_batch_processing', FALSE);
|
|
$tasks = array(
|
|
// This is an example of a task that defines a form which the user who is
|
|
// installing the site will be asked to fill out. To implement this task,
|
|
// your profile would define a function named myprofile_data_import_form()
|
|
// as a normal form API callback function, with associated validation and
|
|
// submit handlers. In the submit handler, in addition to saving whatever
|
|
// other data you have collected from the user, you might also call
|
|
// \Drupal::state()->set('myprofile.needs_batch_processing', TRUE) if the
|
|
// user has entered data which requires that batch processing will need to
|
|
// occur later on.
|
|
'myprofile_data_import_form' => array(
|
|
'display_name' => t('Data import options'),
|
|
'type' => 'form',
|
|
),
|
|
// Similarly, to implement this task, your profile would define a function
|
|
// named myprofile_settings_form() with associated validation and submit
|
|
// handlers. This form might be used to collect and save additional
|
|
// information from the user that your profile needs. There are no extra
|
|
// steps required for your profile to act as an "installation wizard"; you
|
|
// can simply define as many tasks of type 'form' as you wish to execute,
|
|
// and the forms will be presented to the user, one after another.
|
|
'myprofile_settings_form' => array(
|
|
'display_name' => t('Additional options'),
|
|
'type' => 'form',
|
|
),
|
|
// This is an example of a task that performs batch operations. To
|
|
// implement this task, your profile would define a function named
|
|
// myprofile_batch_processing() which returns a batch API array definition
|
|
// that the installer will use to execute your batch operations. Due to the
|
|
// 'myprofile.needs_batch_processing' variable used here, this task will be
|
|
// hidden and skipped unless your profile set it to TRUE in one of the
|
|
// previous tasks.
|
|
'myprofile_batch_processing' => array(
|
|
'display_name' => t('Import additional data'),
|
|
'display' => $myprofile_needs_batch_processing,
|
|
'type' => 'batch',
|
|
'run' => $myprofile_needs_batch_processing ? INSTALL_TASK_RUN_IF_NOT_COMPLETED : INSTALL_TASK_SKIP,
|
|
),
|
|
// This is an example of a task that will not be displayed in the list that
|
|
// the user sees. To implement this task, your profile would define a
|
|
// function named myprofile_final_site_setup(), in which additional,
|
|
// automated site setup operations would be performed. Since this is the
|
|
// last task defined by your profile, you should also use this function to
|
|
// call \Drupal::state()->delete('myprofile.needs_batch_processing') and
|
|
// clean up the state that was used above. If you want the user to pass
|
|
// to the final Drupal installation tasks uninterrupted, return no output
|
|
// from this function. Otherwise, return themed output that the user will
|
|
// see (for example, a confirmation page explaining that your profile's
|
|
// tasks are complete, with a link to reload the current page and therefore
|
|
// pass on to the final Drupal installation tasks when the user is ready to
|
|
// do so).
|
|
'myprofile_final_site_setup' => array(
|
|
),
|
|
);
|
|
return $tasks;
|
|
}
|
|
|
|
/**
|
|
* Alter the full list of installation tasks.
|
|
*
|
|
* You can use this hook to change or replace any part of the Drupal
|
|
* installation process that occurs after the installation profile is selected.
|
|
*
|
|
* This hook is invoked on the install profile in install_tasks().
|
|
*
|
|
* @param $tasks
|
|
* An array of all available installation tasks, including those provided by
|
|
* Drupal core. You can modify this array to change or replace individual
|
|
* steps within the installation process.
|
|
* @param $install_state
|
|
* An array of information about the current installation state.
|
|
*
|
|
* @see hook_install_tasks()
|
|
* @see install_tasks()
|
|
*/
|
|
function hook_install_tasks_alter(&$tasks, $install_state) {
|
|
// Replace the entire site configuration form provided by Drupal core
|
|
// with a custom callback function defined by this installation profile.
|
|
$tasks['install_configure_form']['function'] = 'myprofile_install_configure_form';
|
|
}
|
|
|
|
/**
|
|
* Perform a single update.
|
|
*
|
|
* For each change that requires one or more actions to be performed when
|
|
* updating a site, add a new hook_update_N(), which will be called by
|
|
* update.php. The documentation block preceding this function is stripped of
|
|
* newlines and used as the description for the update on the pending updates
|
|
* task list. Schema updates should adhere to the
|
|
* @link http://drupal.org/node/150215 Schema API. @endlink
|
|
*
|
|
* Implementations of hook_update_N() are named (module name)_update_(number).
|
|
* The numbers are composed of three parts:
|
|
* - 1 digit for Drupal core compatibility.
|
|
* - 1 digit for your module's major release version (e.g., is this the 8.x-1.*
|
|
* (1) or 8.x-2.* (2) series of your module).
|
|
* - 2 digits for sequential counting, starting with 01.
|
|
*
|
|
* Examples:
|
|
* - mymodule_update_8100(): This is the first update to get the database ready
|
|
* to run mymodule 8.x-1.*.
|
|
* - mymodule_update_8200(): This is the first update to get the database ready
|
|
* to run mymodule 8.x-2.*.
|
|
*
|
|
* As of Drupal 8.0, the database upgrade system no longer supports updating a
|
|
* database from an earlier major version of Drupal: update.php can be used to
|
|
* upgrade from 7.x-1.x to 7.x-2.x, or 8.x-1.x to 8.x-2.x, but not from 7.x to
|
|
* 8.x. Therefore, only update hooks numbered 8001 or later will run for
|
|
* Drupal 8. 8000 is reserved for the minimum core schema version and defining
|
|
* mymodule_update_8000() will result in an exception. Use the
|
|
* @link https://drupal.org/node/2127611 Migration API @endlink instead to
|
|
* migrate data from an earlier major version of Drupal.
|
|
*
|
|
* For further information about releases and release numbers see:
|
|
* @link http://drupal.org/node/711070 Maintaining a drupal.org project with Git @endlink
|
|
*
|
|
* Never renumber update functions.
|
|
*
|
|
* Implementations of this hook should be placed in a mymodule.install file in
|
|
* the same directory as mymodule.module. Drupal core's updates are implemented
|
|
* using the system module as a name and stored in database/updates.inc.
|
|
*
|
|
* Not all module functions are available from within a hook_update_N() function.
|
|
* In order to call a function from your mymodule.module or an include file,
|
|
* you need to explicitly load that file first.
|
|
*
|
|
* During database updates the schema of any module could be out of date. For
|
|
* this reason, caution is needed when using any API function within an update
|
|
* function - particularly CRUD functions, functions that depend on the schema
|
|
* (for example by using drupal_write_record()), and any functions that invoke
|
|
* hooks.
|
|
*
|
|
* The $sandbox parameter should be used when a multipass update is needed, in
|
|
* circumstances where running the whole update at once could cause PHP to
|
|
* timeout. Each pass is run in a way that avoids PHP timeouts, provided each
|
|
* pass remains under the timeout limit. To signify that an update requires
|
|
* at least one more pass, set $sandbox['#finished'] to a number less than 1
|
|
* (you need to do this each pass). The value of $sandbox['#finished'] will be
|
|
* unset between passes but all other data in $sandbox will be preserved. The
|
|
* system will stop iterating this update when $sandbox['#finished'] is left
|
|
* unset or set to a number higher than 1. It is recommended that
|
|
* $sandbox['#finished'] is initially set to 0, and then updated each pass to a
|
|
* number between 0 and 1 that represents the overall % completed for this
|
|
* update, finishing with 1.
|
|
*
|
|
* See the @link batch Batch operations topic @endlink for more information on
|
|
* how to use the Batch API.
|
|
*
|
|
* @param array $sandbox
|
|
* Stores information for multipass updates. See above for more information.
|
|
*
|
|
* @throws \Drupal\Core\Utility\UpdateException|PDOException
|
|
* In case of error, update hooks should throw an instance of
|
|
* Drupal\Core\Utility\UpdateException with a meaningful message for the user.
|
|
* If a database query fails for whatever reason, it will throw a
|
|
* PDOException.
|
|
*
|
|
* @return string|null
|
|
* Optionally, update hooks may return a translated string that will be
|
|
* displayed to the user after the update has completed. If no message is
|
|
* returned, no message will be presented to the user.
|
|
*
|
|
* @see batch
|
|
* @see schemaapi
|
|
* @see hook_update_last_removed()
|
|
* @see update_get_update_list()
|
|
*/
|
|
function hook_update_N(&$sandbox) {
|
|
// For non-multipass updates, the signature can simply be;
|
|
// function hook_update_N() {
|
|
|
|
// For most updates, the following is sufficient.
|
|
db_add_field('mytable1', 'newcol', array('type' => 'int', 'not null' => TRUE, 'description' => 'My new integer column.'));
|
|
|
|
// However, for more complex operations that may take a long time,
|
|
// you may hook into Batch API as in the following example.
|
|
|
|
// Update 3 users at a time to have an exclamation point after their names.
|
|
// (They're really happy that we can do batch API in this hook!)
|
|
if (!isset($sandbox['progress'])) {
|
|
$sandbox['progress'] = 0;
|
|
$sandbox['current_uid'] = 0;
|
|
// We'll -1 to disregard the uid 0...
|
|
$sandbox['max'] = db_query('SELECT COUNT(DISTINCT uid) FROM {users}')->fetchField() - 1;
|
|
}
|
|
|
|
$users = db_select('users', 'u')
|
|
->fields('u', array('uid', 'name'))
|
|
->condition('uid', $sandbox['current_uid'], '>')
|
|
->range(0, 3)
|
|
->orderBy('uid', 'ASC')
|
|
->execute();
|
|
|
|
foreach ($users as $user) {
|
|
$user->setUsername($user->getUsername() . '!');
|
|
db_update('users')
|
|
->fields(array('name' => $user->getUsername()))
|
|
->condition('uid', $user->id())
|
|
->execute();
|
|
|
|
$sandbox['progress']++;
|
|
$sandbox['current_uid'] = $user->id();
|
|
}
|
|
|
|
$sandbox['#finished'] = empty($sandbox['max']) ? 1 : ($sandbox['progress'] / $sandbox['max']);
|
|
|
|
if ($some_error_condition_met) {
|
|
// In case of an error, simply throw an exception with an error message.
|
|
throw new UpdateException('Something went wrong; here is what you should do.');
|
|
}
|
|
|
|
// To display a message to the user when the update is completed, return it.
|
|
// If you do not want to display a completion message, simply return nothing.
|
|
return t('The update did what it was supposed to do.');
|
|
}
|
|
|
|
/**
|
|
* Return an array of information about module update dependencies.
|
|
*
|
|
* This can be used to indicate update functions from other modules that your
|
|
* module's update functions depend on, or vice versa. It is used by the update
|
|
* system to determine the appropriate order in which updates should be run, as
|
|
* well as to search for missing dependencies.
|
|
*
|
|
* Implementations of this hook should be placed in a mymodule.install file in
|
|
* the same directory as mymodule.module.
|
|
*
|
|
* @return
|
|
* A multidimensional array containing information about the module update
|
|
* dependencies. The first two levels of keys represent the module and update
|
|
* number (respectively) for which information is being returned, and the
|
|
* value is an array of information about that update's dependencies. Within
|
|
* this array, each key represents a module, and each value represents the
|
|
* number of an update function within that module. In the event that your
|
|
* update function depends on more than one update from a particular module,
|
|
* you should always list the highest numbered one here (since updates within
|
|
* a given module always run in numerical order).
|
|
*
|
|
* @see update_resolve_dependencies()
|
|
* @see hook_update_N()
|
|
*/
|
|
function hook_update_dependencies() {
|
|
// Indicate that the mymodule_update_8001() function provided by this module
|
|
// must run after the another_module_update_8003() function provided by the
|
|
// 'another_module' module.
|
|
$dependencies['mymodule'][8001] = array(
|
|
'another_module' => 8003,
|
|
);
|
|
// Indicate that the mymodule_update_8002() function provided by this module
|
|
// must run before the yet_another_module_update_8005() function provided by
|
|
// the 'yet_another_module' module. (Note that declaring dependencies in this
|
|
// direction should be done only in rare situations, since it can lead to the
|
|
// following problem: If a site has already run the yet_another_module
|
|
// module's database updates before it updates its codebase to pick up the
|
|
// newest mymodule code, then the dependency declared here will be ignored.)
|
|
$dependencies['yet_another_module'][8005] = array(
|
|
'mymodule' => 8002,
|
|
);
|
|
return $dependencies;
|
|
}
|
|
|
|
/**
|
|
* Return a number which is no longer available as hook_update_N().
|
|
*
|
|
* If you remove some update functions from your mymodule.install file, you
|
|
* should notify Drupal of those missing functions. This way, Drupal can
|
|
* ensure that no update is accidentally skipped.
|
|
*
|
|
* Implementations of this hook should be placed in a mymodule.install file in
|
|
* the same directory as mymodule.module.
|
|
*
|
|
* @return
|
|
* An integer, corresponding to hook_update_N() which has been removed from
|
|
* mymodule.install.
|
|
*
|
|
* @see hook_update_N()
|
|
*/
|
|
function hook_update_last_removed() {
|
|
// We've removed the 8.x-1.x version of mymodule, including database updates.
|
|
// The next update function is mymodule_update_8200().
|
|
return 8103;
|
|
}
|
|
|
|
/**
|
|
* Provide information on Updaters (classes that can update Drupal).
|
|
*
|
|
* Drupal\Core\Updater\Updater is a class that knows how to update various parts
|
|
* of the Drupal file system, for example to update modules that have newer
|
|
* releases, or to install a new theme.
|
|
*
|
|
* @return
|
|
* An associative array of information about the updater(s) being provided.
|
|
* This array is keyed by a unique identifier for each updater, and the
|
|
* values are subarrays that can contain the following keys:
|
|
* - class: The name of the PHP class which implements this updater.
|
|
* - name: Human-readable name of this updater.
|
|
* - weight: Controls what order the Updater classes are consulted to decide
|
|
* which one should handle a given task. When an update task is being run,
|
|
* the system will loop through all the Updater classes defined in this
|
|
* registry in weight order and let each class respond to the task and
|
|
* decide if each Updater wants to handle the task. In general, this
|
|
* doesn't matter, but if you need to override an existing Updater, make
|
|
* sure your Updater has a lighter weight so that it comes first.
|
|
*
|
|
* @see drupal_get_updaters()
|
|
* @see hook_updater_info_alter()
|
|
*/
|
|
function hook_updater_info() {
|
|
return array(
|
|
'module' => array(
|
|
'class' => 'Drupal\Core\Updater\Module',
|
|
'name' => t('Update modules'),
|
|
'weight' => 0,
|
|
),
|
|
'theme' => array(
|
|
'class' => 'Drupal\Core\Updater\Theme',
|
|
'name' => t('Update themes'),
|
|
'weight' => 0,
|
|
),
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Alter the Updater information array.
|
|
*
|
|
* An Updater is a class that knows how to update various parts of the Drupal
|
|
* file system, for example to update modules that have newer releases, or to
|
|
* install a new theme.
|
|
*
|
|
* @param array $updaters
|
|
* Associative array of updaters as defined through hook_updater_info().
|
|
* Alter this array directly.
|
|
*
|
|
* @see drupal_get_updaters()
|
|
* @see hook_updater_info()
|
|
*/
|
|
function hook_updater_info_alter(&$updaters) {
|
|
// Adjust weight so that the theme Updater gets a chance to handle a given
|
|
// update task before module updaters.
|
|
$updaters['theme']['weight'] = -1;
|
|
}
|
|
|
|
/**
|
|
* Check installation requirements and do status reporting.
|
|
*
|
|
* This hook has three closely related uses, determined by the $phase argument:
|
|
* - Checking installation requirements ($phase == 'install').
|
|
* - Checking update requirements ($phase == 'update').
|
|
* - Status reporting ($phase == 'runtime').
|
|
*
|
|
* Note that this hook, like all others dealing with installation and updates,
|
|
* must reside in a module_name.install file, or it will not properly abort
|
|
* the installation of the module if a critical requirement is missing.
|
|
*
|
|
* During the 'install' phase, modules can for example assert that
|
|
* library or server versions are available or sufficient.
|
|
* Note that the installation of a module can happen during installation of
|
|
* Drupal itself (by install.php) with an installation profile or later by hand.
|
|
* As a consequence, install-time requirements must be checked without access
|
|
* to the full Drupal API, because it is not available during install.php.
|
|
* If a requirement has a severity of REQUIREMENT_ERROR, install.php will abort
|
|
* or at least the module will not install.
|
|
* Other severity levels have no effect on the installation.
|
|
* Module dependencies do not belong to these installation requirements,
|
|
* but should be defined in the module's .info.yml file.
|
|
*
|
|
* The 'runtime' phase is not limited to pure installation requirements
|
|
* but can also be used for more general status information like maintenance
|
|
* tasks and security issues.
|
|
* The returned 'requirements' will be listed on the status report in the
|
|
* administration section, with indication of the severity level.
|
|
* Moreover, any requirement with a severity of REQUIREMENT_ERROR severity will
|
|
* result in a notice on the administration configuration page.
|
|
*
|
|
* @param $phase
|
|
* The phase in which requirements are checked:
|
|
* - install: The module is being installed.
|
|
* - update: The module is enabled and update.php is run.
|
|
* - runtime: The runtime requirements are being checked and shown on the
|
|
* status report page.
|
|
*
|
|
* @return
|
|
* An associative array where the keys are arbitrary but must be unique (it
|
|
* is suggested to use the module short name as a prefix) and the values are
|
|
* themselves associative arrays with the following elements:
|
|
* - title: The name of the requirement.
|
|
* - value: The current value (e.g., version, time, level, etc). During
|
|
* install phase, this should only be used for version numbers, do not set
|
|
* it if not applicable.
|
|
* - description: The description of the requirement/status.
|
|
* - severity: The requirement's result/severity level, one of:
|
|
* - REQUIREMENT_INFO: For info only.
|
|
* - REQUIREMENT_OK: The requirement is satisfied.
|
|
* - REQUIREMENT_WARNING: The requirement failed with a warning.
|
|
* - REQUIREMENT_ERROR: The requirement failed with an error.
|
|
*/
|
|
function hook_requirements($phase) {
|
|
$requirements = array();
|
|
|
|
// Report Drupal version
|
|
if ($phase == 'runtime') {
|
|
$requirements['drupal'] = array(
|
|
'title' => t('Drupal'),
|
|
'value' => \Drupal::VERSION,
|
|
'severity' => REQUIREMENT_INFO
|
|
);
|
|
}
|
|
|
|
// Test PHP version
|
|
$requirements['php'] = array(
|
|
'title' => t('PHP'),
|
|
'value' => ($phase == 'runtime') ? \Drupal::l(phpversion(), new Url('system.php')) : phpversion(),
|
|
);
|
|
if (version_compare(phpversion(), DRUPAL_MINIMUM_PHP) < 0) {
|
|
$requirements['php']['description'] = t('Your PHP installation is too old. Drupal requires at least PHP %version.', array('%version' => DRUPAL_MINIMUM_PHP));
|
|
$requirements['php']['severity'] = REQUIREMENT_ERROR;
|
|
}
|
|
|
|
// Report cron status
|
|
if ($phase == 'runtime') {
|
|
$cron_last = \Drupal::state()->get('system.cron_last');
|
|
|
|
if (is_numeric($cron_last)) {
|
|
$requirements['cron']['value'] = t('Last run !time ago', array('!time' => \Drupal::service('date.formatter')->formatInterval(REQUEST_TIME - $cron_last)));
|
|
}
|
|
else {
|
|
$requirements['cron'] = array(
|
|
'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>.', array('@url' => 'http://drupal.org/cron')),
|
|
'severity' => REQUIREMENT_ERROR,
|
|
'value' => t('Never run'),
|
|
);
|
|
}
|
|
|
|
$requirements['cron']['description'] .= ' ' . t('You can <a href="@cron">run cron manually</a>.', array('@cron' => \Drupal::url('system.run_cron')));
|
|
|
|
$requirements['cron']['title'] = t('Cron maintenance tasks');
|
|
}
|
|
|
|
return $requirements;
|
|
}
|
|
|
|
/**
|
|
* @} End of "addtogroup hooks".
|
|
*/
|