609 lines
21 KiB
PHP
609 lines
21 KiB
PHP
<?php
|
|
|
|
/**
|
|
* @file
|
|
* Hooks provided by Drupal core and the System module.
|
|
*/
|
|
|
|
use Drupal\Component\Utility\SafeMarkup;
|
|
use Drupal\Core\Mail\MailFormatHelper;
|
|
use Drupal\Core\Url;
|
|
use Drupal\taxonomy\Entity\Vocabulary;
|
|
|
|
/**
|
|
* @addtogroup hooks
|
|
* @{
|
|
*/
|
|
|
|
/**
|
|
* Flush all persistent and static caches.
|
|
*
|
|
* This hook asks your module to clear all of its static caches,
|
|
* in order to ensure a clean environment for subsequently
|
|
* invoked data rebuilds.
|
|
*
|
|
* Do NOT use this hook for rebuilding information. Only use it to flush custom
|
|
* caches.
|
|
*
|
|
* Static caches using drupal_static() do not need to be reset manually.
|
|
* However, all other static variables that do not use drupal_static() must be
|
|
* manually reset.
|
|
*
|
|
* This hook is invoked by drupal_flush_all_caches(). It runs before module data
|
|
* is updated and before hook_rebuild().
|
|
*
|
|
* @see drupal_flush_all_caches()
|
|
* @see hook_rebuild()
|
|
*/
|
|
function hook_cache_flush() {
|
|
if (defined('MAINTENANCE_MODE') && MAINTENANCE_MODE == 'update') {
|
|
_update_cache_clear();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Rebuild data based upon refreshed caches.
|
|
*
|
|
* This hook allows your module to rebuild its data based on the latest/current
|
|
* module data. It runs after hook_cache_flush() and after all module data has
|
|
* been updated.
|
|
*
|
|
* This hook is only invoked after the system has been completely cleared;
|
|
* i.e., all previously cached data is known to be gone and every API in the
|
|
* system is known to return current information, so your module can safely rely
|
|
* on all available data to rebuild its own.
|
|
*
|
|
* @see hook_cache_flush()
|
|
* @see drupal_flush_all_caches()
|
|
*/
|
|
function hook_rebuild() {
|
|
$themes = \Drupal::service('theme_handler')->listInfo();
|
|
foreach ($themes as $theme) {
|
|
_block_rehash($theme->getName());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Define the current version of the database schema.
|
|
*
|
|
* A Drupal schema definition is an array structure representing one or more
|
|
* tables and their related keys and indexes. A schema is defined by
|
|
* hook_schema() which must live in your module's .install file.
|
|
*
|
|
* The tables declared by this hook will be automatically created when the
|
|
* module is installed, and removed when the module is uninstalled. This happens
|
|
* before hook_install() is invoked, and after hook_uninstall() is invoked,
|
|
* respectively.
|
|
*
|
|
* By declaring the tables used by your module via an implementation of
|
|
* hook_schema(), these tables will be available on all supported database
|
|
* engines. You don't have to deal with the different SQL dialects for table
|
|
* creation and alteration of the supported database engines.
|
|
*
|
|
* See the Schema API Handbook at http://drupal.org/node/146843 for details on
|
|
* schema definition structures.
|
|
*
|
|
* @return array
|
|
* A schema definition structure array. For each element of the
|
|
* array, the key is a table name and the value is a table structure
|
|
* definition.
|
|
*
|
|
* @see hook_schema_alter()
|
|
*
|
|
* @ingroup schemaapi
|
|
*/
|
|
function hook_schema() {
|
|
$schema['node'] = array(
|
|
// Example (partial) specification for table "node".
|
|
'description' => 'The base table for nodes.',
|
|
'fields' => array(
|
|
'nid' => array(
|
|
'description' => 'The primary identifier for a node.',
|
|
'type' => 'serial',
|
|
'unsigned' => TRUE,
|
|
'not null' => TRUE,
|
|
),
|
|
'vid' => array(
|
|
'description' => 'The current {node_field_revision}.vid version identifier.',
|
|
'type' => 'int',
|
|
'unsigned' => TRUE,
|
|
'not null' => TRUE,
|
|
'default' => 0,
|
|
),
|
|
'type' => array(
|
|
'description' => 'The type of this node.',
|
|
'type' => 'varchar',
|
|
'length' => 32,
|
|
'not null' => TRUE,
|
|
'default' => '',
|
|
),
|
|
'title' => array(
|
|
'description' => 'The node title.',
|
|
'type' => 'varchar',
|
|
'length' => 255,
|
|
'not null' => TRUE,
|
|
'default' => '',
|
|
),
|
|
),
|
|
'indexes' => array(
|
|
'node_changed' => array('changed'),
|
|
'node_created' => array('created'),
|
|
),
|
|
'unique keys' => array(
|
|
'nid_vid' => array('nid', 'vid'),
|
|
'vid' => array('vid'),
|
|
),
|
|
'foreign keys' => array(
|
|
'node_revision' => array(
|
|
'table' => 'node_field_revision',
|
|
'columns' => array('vid' => 'vid'),
|
|
),
|
|
'node_author' => array(
|
|
'table' => 'users',
|
|
'columns' => array('uid' => 'uid'),
|
|
),
|
|
),
|
|
'primary key' => array('nid'),
|
|
);
|
|
return $schema;
|
|
}
|
|
|
|
/**
|
|
* Perform alterations to existing database schemas.
|
|
*
|
|
* When a module modifies the database structure of another module (by
|
|
* changing, adding or removing fields, keys or indexes), it should
|
|
* implement hook_schema_alter() to update the default $schema to take its
|
|
* changes into account.
|
|
*
|
|
* See hook_schema() for details on the schema definition structure.
|
|
*
|
|
* @param $schema
|
|
* Nested array describing the schemas for all modules.
|
|
*
|
|
* @ingroup schemaapi
|
|
*/
|
|
function hook_schema_alter(&$schema) {
|
|
// Add field to existing schema.
|
|
$schema['users']['fields']['timezone_id'] = array(
|
|
'type' => 'int',
|
|
'not null' => TRUE,
|
|
'default' => 0,
|
|
'description' => 'Per-user timezone configuration.',
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Perform alterations to a structured query.
|
|
*
|
|
* Structured (aka dynamic) queries that have tags associated may be altered by any module
|
|
* before the query is executed.
|
|
*
|
|
* @param $query
|
|
* A Query object describing the composite parts of a SQL query.
|
|
*
|
|
* @see hook_query_TAG_alter()
|
|
* @see node_query_node_access_alter()
|
|
* @see AlterableInterface
|
|
* @see SelectInterface
|
|
*/
|
|
function hook_query_alter(Drupal\Core\Database\Query\AlterableInterface $query) {
|
|
if ($query->hasTag('micro_limit')) {
|
|
$query->range(0, 2);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Perform alterations to a structured query for a given tag.
|
|
*
|
|
* @param $query
|
|
* An Query object describing the composite parts of a SQL query.
|
|
*
|
|
* @see hook_query_alter()
|
|
* @see node_query_node_access_alter()
|
|
* @see AlterableInterface
|
|
* @see SelectInterface
|
|
*/
|
|
function hook_query_TAG_alter(Drupal\Core\Database\Query\AlterableInterface $query) {
|
|
// Skip the extra expensive alterations if site has no node access control modules.
|
|
if (!node_access_view_all_nodes()) {
|
|
// Prevent duplicates records.
|
|
$query->distinct();
|
|
// The recognized operations are 'view', 'update', 'delete'.
|
|
if (!$op = $query->getMetaData('op')) {
|
|
$op = 'view';
|
|
}
|
|
// Skip the extra joins and conditions for node admins.
|
|
if (!\Drupal::currentUser()->hasPermission('bypass node access')) {
|
|
// The node_access table has the access grants for any given node.
|
|
$access_alias = $query->join('node_access', 'na', '%alias.nid = n.nid');
|
|
$or = db_or();
|
|
// If any grant exists for the specified user, then user has access to the node for the specified operation.
|
|
foreach (node_access_grants($op, $query->getMetaData('account')) as $realm => $gids) {
|
|
foreach ($gids as $gid) {
|
|
$or->condition(db_and()
|
|
->condition($access_alias . '.gid', $gid)
|
|
->condition($access_alias . '.realm', $realm)
|
|
);
|
|
}
|
|
}
|
|
|
|
if (count($or->conditions())) {
|
|
$query->condition($or);
|
|
}
|
|
|
|
$query->condition($access_alias . 'grant_' . $op, 1, '>=');
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Alters theme operation links.
|
|
*
|
|
* @param $theme_groups
|
|
* An associative array containing groups of themes.
|
|
*
|
|
* @see system_themes_page()
|
|
*/
|
|
function hook_system_themes_page_alter(&$theme_groups) {
|
|
foreach ($theme_groups as $state => &$group) {
|
|
foreach ($theme_groups[$state] as &$theme) {
|
|
// Add a foo link to each list of theme operations.
|
|
$theme->operations[] = array(
|
|
'title' => t('Foo'),
|
|
'url' => Url::fromRoute('system.themes_page'),
|
|
'query' => array('theme' => $theme->getName())
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Provide replacement values for placeholder tokens.
|
|
*
|
|
* This hook is invoked when someone calls
|
|
* \Drupal\Core\Utility\Token::replace(). That function first scans the text for
|
|
* [type:token] patterns, and splits the needed tokens into groups by type.
|
|
* Then hook_tokens() is invoked on each token-type group, allowing your module
|
|
* to respond by providing replacement text for any of the tokens in the group
|
|
* that your module knows how to process.
|
|
*
|
|
* A module implementing this hook should also implement hook_token_info() in
|
|
* order to list its available tokens on editing screens.
|
|
*
|
|
* @param $type
|
|
* The machine-readable name of the type (group) of token being replaced, such
|
|
* as 'node', 'user', or another type defined by a hook_token_info()
|
|
* implementation.
|
|
* @param $tokens
|
|
* An array of tokens to be replaced. The keys are the machine-readable token
|
|
* names, and the values are the raw [type:token] strings that appeared in the
|
|
* original text.
|
|
* @param $data
|
|
* (optional) An associative array of data objects to be used when generating
|
|
* replacement values, as supplied in the $data parameter to
|
|
* \Drupal\Core\Utility\Token::replace().
|
|
* @param $options
|
|
* (optional) An associative array of options for token replacement; see
|
|
* \Drupal\Core\Utility\Token::replace() for possible values.
|
|
*
|
|
* @return
|
|
* An associative array of replacement values, keyed by the raw [type:token]
|
|
* strings from the original text.
|
|
*
|
|
* @see hook_token_info()
|
|
* @see hook_tokens_alter()
|
|
*/
|
|
function hook_tokens($type, $tokens, array $data = array(), array $options = array()) {
|
|
$token_service = \Drupal::token();
|
|
|
|
$url_options = array('absolute' => TRUE);
|
|
if (isset($options['langcode'])) {
|
|
$url_options['language'] = \Drupal::languageManager()->getLanguage($options['langcode']);
|
|
$langcode = $options['langcode'];
|
|
}
|
|
else {
|
|
$langcode = NULL;
|
|
}
|
|
$sanitize = !empty($options['sanitize']);
|
|
|
|
$replacements = array();
|
|
|
|
if ($type == 'node' && !empty($data['node'])) {
|
|
/** @var \Drupal\node\NodeInterface $node */
|
|
$node = $data['node'];
|
|
|
|
foreach ($tokens as $name => $original) {
|
|
switch ($name) {
|
|
// Simple key values on the node.
|
|
case 'nid':
|
|
$replacements[$original] = $node->nid;
|
|
break;
|
|
|
|
case 'title':
|
|
$replacements[$original] = $sanitize ? SafeMarkup::checkPlain($node->getTitle()) : $node->getTitle();
|
|
break;
|
|
|
|
case 'edit-url':
|
|
$replacements[$original] = $node->url('edit-form', $url_options);
|
|
break;
|
|
|
|
// Default values for the chained tokens handled below.
|
|
case 'author':
|
|
$account = $node->getOwner() ? $node->getOwner() : user_load(0);
|
|
$replacements[$original] = $sanitize ? SafeMarkup::checkPlain($account->label()) : $account->label();
|
|
break;
|
|
|
|
case 'created':
|
|
$replacements[$original] = format_date($node->getCreatedTime(), 'medium', '', NULL, $langcode);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ($author_tokens = $token_service->findWithPrefix($tokens, 'author')) {
|
|
$replacements += $token_service->generate('user', $author_tokens, array('user' => $node->getOwner()), $options);
|
|
}
|
|
|
|
if ($created_tokens = $token_service->findWithPrefix($tokens, 'created')) {
|
|
$replacements += $token_service->generate('date', $created_tokens, array('date' => $node->getCreatedTime()), $options);
|
|
}
|
|
}
|
|
|
|
return $replacements;
|
|
}
|
|
|
|
/**
|
|
* Alter replacement values for placeholder tokens.
|
|
*
|
|
* @param $replacements
|
|
* An associative array of replacements returned by hook_tokens().
|
|
* @param $context
|
|
* The context in which hook_tokens() was called. An associative array with
|
|
* the following keys, which have the same meaning as the corresponding
|
|
* parameters of hook_tokens():
|
|
* - 'type'
|
|
* - 'tokens'
|
|
* - 'data'
|
|
* - 'options'
|
|
*
|
|
* @see hook_tokens()
|
|
*/
|
|
function hook_tokens_alter(array &$replacements, array $context) {
|
|
$options = $context['options'];
|
|
|
|
if (isset($options['langcode'])) {
|
|
$url_options['language'] = \Drupal::languageManager()->getLanguage($options['langcode']);
|
|
$langcode = $options['langcode'];
|
|
}
|
|
else {
|
|
$langcode = NULL;
|
|
}
|
|
|
|
if ($context['type'] == 'node' && !empty($context['data']['node'])) {
|
|
$node = $context['data']['node'];
|
|
|
|
// Alter the [node:title] token, and replace it with the rendered content
|
|
// of a field (field_title).
|
|
if (isset($context['tokens']['title'])) {
|
|
$title = $node->field_title->view('default');
|
|
$replacements[$context['tokens']['title']] = drupal_render($title);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Provide information about available placeholder tokens and token types.
|
|
*
|
|
* Tokens are placeholders that can be put into text by using the syntax
|
|
* [type:token], where type is the machine-readable name of a token type, and
|
|
* token is the machine-readable name of a token within this group. This hook
|
|
* provides a list of types and tokens to be displayed on text editing screens,
|
|
* so that people editing text can see what their token options are.
|
|
*
|
|
* The actual token replacement is done by
|
|
* \Drupal\Core\Utility\Token::replace(), which invokes hook_tokens(). Your
|
|
* module will need to implement that hook in order to generate token
|
|
* replacements from the tokens defined here.
|
|
*
|
|
* @return
|
|
* An associative array of available tokens and token types. The outer array
|
|
* has two components:
|
|
* - types: An associative array of token types (groups). Each token type is
|
|
* an associative array with the following components:
|
|
* - name: The translated human-readable short name of the token type.
|
|
* - description (optional): A translated longer description of the token
|
|
* type.
|
|
* - needs-data: The type of data that must be provided to
|
|
* \Drupal\Core\Utility\Token::replace() in the $data argument (i.e., the
|
|
* key name in $data) in order for tokens of this type to be used in the
|
|
* $text being processed. For instance, if the token needs a node object,
|
|
* 'needs-data' should be 'node', and to use this token in
|
|
* \Drupal\Core\Utility\Token::replace(), the caller needs to supply a
|
|
* node object as $data['node']. Some token data can also be supplied
|
|
* indirectly; for instance, a node object in $data supplies a user object
|
|
* (the author of the node), allowing user tokens to be used when only
|
|
* a node data object is supplied.
|
|
* - tokens: An associative array of tokens. The outer array is keyed by the
|
|
* group name (the same key as in the types array). Within each group of
|
|
* tokens, each token item is keyed by the machine name of the token, and
|
|
* each token item has the following components:
|
|
* - name: The translated human-readable short name of the token.
|
|
* - description (optional): A translated longer description of the token.
|
|
* - type (optional): A 'needs-data' data type supplied by this token, which
|
|
* should match a 'needs-data' value from another token type. For example,
|
|
* the node author token provides a user object, which can then be used
|
|
* for token replacement data in \Drupal\Core\Utility\Token::replace()
|
|
* without having to supply a separate user object.
|
|
*
|
|
* @see hook_token_info_alter()
|
|
* @see hook_tokens()
|
|
*/
|
|
function hook_token_info() {
|
|
$type = array(
|
|
'name' => t('Nodes'),
|
|
'description' => t('Tokens related to individual nodes.'),
|
|
'needs-data' => 'node',
|
|
);
|
|
|
|
// Core tokens for nodes.
|
|
$node['nid'] = array(
|
|
'name' => t("Node ID"),
|
|
'description' => t("The unique ID of the node."),
|
|
);
|
|
$node['title'] = array(
|
|
'name' => t("Title"),
|
|
);
|
|
$node['edit-url'] = array(
|
|
'name' => t("Edit URL"),
|
|
'description' => t("The URL of the node's edit page."),
|
|
);
|
|
|
|
// Chained tokens for nodes.
|
|
$node['created'] = array(
|
|
'name' => t("Date created"),
|
|
'type' => 'date',
|
|
);
|
|
$node['author'] = array(
|
|
'name' => t("Author"),
|
|
'type' => 'user',
|
|
);
|
|
|
|
return array(
|
|
'types' => array('node' => $type),
|
|
'tokens' => array('node' => $node),
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Alter the metadata about available placeholder tokens and token types.
|
|
*
|
|
* @param $data
|
|
* The associative array of token definitions from hook_token_info().
|
|
*
|
|
* @see hook_token_info()
|
|
*/
|
|
function hook_token_info_alter(&$data) {
|
|
// Modify description of node tokens for our site.
|
|
$data['tokens']['node']['nid'] = array(
|
|
'name' => t("Node ID"),
|
|
'description' => t("The unique ID of the article."),
|
|
);
|
|
$data['tokens']['node']['title'] = array(
|
|
'name' => t("Title"),
|
|
'description' => t("The title of the article."),
|
|
);
|
|
|
|
// Chained tokens for nodes.
|
|
$data['tokens']['node']['created'] = array(
|
|
'name' => t("Date created"),
|
|
'description' => t("The date the article was posted."),
|
|
'type' => 'date',
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Alter the parameters for links.
|
|
*
|
|
* @param array $variables
|
|
* An associative array of variables defining a link. The link may be either a
|
|
* "route link" using \Drupal\Core\Utility\LinkGenerator::link(), which is
|
|
* exposed as the 'link_generator' service or a link generated by _l(). If the
|
|
* link is a "route link", 'route_name' will be set, otherwise 'path' will be
|
|
* set. The following keys can be altered:
|
|
* - text: The link text for the anchor tag as a translated string.
|
|
* - url_is_active: Whether or not the link points to the currently active
|
|
* URL.
|
|
* - url: The \Drupal\Core\Url object.
|
|
* - options: An associative array of additional options that will be passed
|
|
* to either \Drupal\Core\Routing\UrlGenerator::generateFromPath() or
|
|
* \Drupal\Core\Routing\UrlGenerator::generateFromRoute() to generate the
|
|
* href attribute for this link, and also used when generating the link.
|
|
* Defaults to an empty array. It may contain the following elements:
|
|
* - 'query': An array of query key/value-pairs (without any URL-encoding) to
|
|
* append to the URL.
|
|
* - absolute: Whether to force the output to be an absolute link (beginning
|
|
* with http:). Useful for links that will be displayed outside the site,
|
|
* such as in an RSS feed. Defaults to FALSE.
|
|
* - language: An optional language object. May affect the rendering of
|
|
* the anchor tag, such as by adding a language prefix to the path.
|
|
* - attributes: An associative array of HTML attributes to apply to the
|
|
* anchor tag. If element 'class' is included, it must be an array; 'title'
|
|
* must be a string; other elements are more flexible, as they just need
|
|
* to work as an argument for the constructor of the class
|
|
* Drupal\Core\Template\Attribute($options['attributes']).
|
|
* - html: Whether or not HTML should be allowed as the link text. If FALSE,
|
|
* the text will be run through
|
|
* \Drupal\Component\Utility\SafeMarkup::checkPlain() before being output.
|
|
*
|
|
* @see \Drupal\Core\Routing\UrlGenerator::generateFromPath()
|
|
* @see \Drupal\Core\Routing\UrlGenerator::generateFromRoute()
|
|
*/
|
|
function hook_link_alter(&$variables) {
|
|
// Add a warning to the end of route links to the admin section.
|
|
if (isset($variables['route_name']) && strpos($variables['route_name'], 'admin') !== FALSE) {
|
|
$variables['text'] .= ' (Warning!)';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Alter the configuration synchronization steps.
|
|
*
|
|
* @param array $sync_steps
|
|
* A one-dimensional array of \Drupal\Core\Config\ConfigImporter method names
|
|
* or callables that are invoked to complete the import, in the order that
|
|
* they will be processed. Each callable item defined in $sync_steps should
|
|
* either be a global function or a public static method. The callable should
|
|
* accept a $context array by reference. For example:
|
|
* <code>
|
|
* function _additional_configuration_step(&$context) {
|
|
* // Do stuff.
|
|
* // If finished set $context['finished'] = 1.
|
|
* }
|
|
* </code>
|
|
* For more information on creating batches, see the
|
|
* @link batch Batch operations @endlink documentation.
|
|
*
|
|
* @see callback_batch_operation()
|
|
* @see \Drupal\Core\Config\ConfigImporter::initialize()
|
|
*/
|
|
function hook_config_import_steps_alter(&$sync_steps, \Drupal\Core\Config\ConfigImporter $config_importer) {
|
|
$deletes = $config_importer->getUnprocessedConfiguration('delete');
|
|
if (isset($deletes['field.storage.node.body'])) {
|
|
$sync_steps[] = '_additional_configuration_step';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Alter config typed data definitions.
|
|
*
|
|
* For example you can alter the typed data types representing each
|
|
* configuration schema type to change default labels or form element renderers
|
|
* used for configuration translation.
|
|
*
|
|
* If implementations of this hook add or remove configuration schema a
|
|
* ConfigSchemaAlterException will be thrown. Keep in mind that there are tools
|
|
* that may use the configuration schema for static analysis of configuration
|
|
* files, like the string extractor for the localization system. Such systems
|
|
* won't work with dynamically defined configuration schemas.
|
|
*
|
|
* For adding new data types use configuration schema YAML files instead.
|
|
*
|
|
* @param $definitions
|
|
* Associative array of configuration type definitions keyed by schema type
|
|
* names. The elements are themselves array with information about the type.
|
|
*
|
|
* @see \Drupal\Core\Config\TypedConfigManager
|
|
* @see \Drupal\Core\Config\Schema\ConfigSchemaAlterException
|
|
*/
|
|
function hook_config_schema_info_alter(&$definitions) {
|
|
// Enhance the text and date type definitions with classes to generate proper
|
|
// form elements in ConfigTranslationFormBase. Other translatable types will
|
|
// appear as a one line textfield.
|
|
$definitions['text']['form_element_class'] = '\Drupal\config_translation\FormElement\Textarea';
|
|
$definitions['date_format']['form_element_class'] = '\Drupal\config_translation\FormElement\DateFormat';
|
|
}
|
|
|
|
/**
|
|
* @} End of "addtogroup hooks".
|
|
*/
|