Code Coverage |
||||||||||
Classes and Traits |
Functions and Methods |
Lines |
||||||||
Total | |
0 / 0 |
|
100.00% |
0 / 0 |
CRAP | |
0.00% |
0 / 107 |
|
hook_node_grants | |
0.00% |
0 / 1 |
0 | |
0.00% |
0 / 8 |
|||
hook_node_access_records | |
0.00% |
0 / 1 |
0 | |
0.00% |
0 / 25 |
|||
hook_node_access_records_alter | |
0.00% |
0 / 1 |
0 | |
0.00% |
0 / 5 |
|||
hook_node_grants_alter | |
0.00% |
0 / 1 |
0 | |
0.00% |
0 / 9 |
|||
hook_node_access | |
0.00% |
0 / 1 |
0 | |
0.00% |
0 / 22 |
|||
hook_node_search_result | |
0.00% |
0 / 1 |
0 | |
0.00% |
0 / 3 |
|||
hook_node_update_index | |
0.00% |
0 / 1 |
0 | |
0.00% |
0 / 7 |
|||
hook_ranking | |
0.00% |
0 / 1 |
0 | |
0.00% |
0 / 16 |
|||
hook_node_links_alter | |
0.00% |
0 / 1 |
0 | |
0.00% |
0 / 12 |
<?php | |
use Drupal\node\NodeInterface; | |
use Drupal\Component\Utility\Html; | |
use Drupal\Component\Utility\Xss; | |
use Drupal\Core\Access\AccessResult; | |
/** | |
* @file | |
* Hooks specific to the Node module. | |
*/ | |
/** | |
* @addtogroup hooks | |
* @{ | |
*/ | |
/** | |
* Inform the node access system what permissions the user has. | |
* | |
* This hook is for implementation by node access modules. In this hook, | |
* the module grants a user different "grant IDs" within one or more | |
* "realms". In hook_node_access_records(), the realms and grant IDs are | |
* associated with permission to view, edit, and delete individual nodes. | |
* | |
* The realms and grant IDs can be arbitrarily defined by your node access | |
* module; it is common to use role IDs as grant IDs, but that is not required. | |
* Your module could instead maintain its own list of users, where each list has | |
* an ID. In that case, the return value of this hook would be an array of the | |
* list IDs that this user is a member of. | |
* | |
* A node access module may implement as many realms as necessary to properly | |
* define the access privileges for the nodes. Note that the system makes no | |
* distinction between published and unpublished nodes. It is the module's | |
* responsibility to provide appropriate realms to limit access to unpublished | |
* content. | |
* | |
* Node access records are stored in the {node_access} table and define which | |
* grants are required to access a node. There is a special case for the view | |
* operation -- a record with node ID 0 corresponds to a "view all" grant for | |
* the realm and grant ID of that record. If there are no node access modules | |
* enabled, the core node module adds a node ID 0 record for realm 'all'. Node | |
* access modules can also grant "view all" permission on their custom realms; | |
* for example, a module could create a record in {node_access} with: | |
* @code | |
* $record = array( | |
* 'nid' => 0, | |
* 'gid' => 888, | |
* 'realm' => 'example_realm', | |
* 'grant_view' => 1, | |
* 'grant_update' => 0, | |
* 'grant_delete' => 0, | |
* ); | |
* db_insert('node_access')->fields($record)->execute(); | |
* @endcode | |
* And then in its hook_node_grants() implementation, it would need to return: | |
* @code | |
* if ($op == 'view') { | |
* $grants['example_realm'] = array(888); | |
* } | |
* @endcode | |
* If you decide to do this, be aware that the node_access_rebuild() function | |
* will erase any node ID 0 entry when it is called, so you will need to make | |
* sure to restore your {node_access} record after node_access_rebuild() is | |
* called. | |
* | |
* @param \Drupal\Core\Session\AccountInterface $account | |
* The account object whose grants are requested. | |
* @param string $op | |
* The node operation to be performed, such as 'view', 'update', or 'delete'. | |
* | |
* @return array | |
* An array whose keys are "realms" of grants, and whose values are arrays of | |
* the grant IDs within this realm that this user is being granted. | |
* | |
* For a detailed example, see node_access_example.module. | |
* | |
* @see node_access_view_all_nodes() | |
* @see node_access_rebuild() | |
* @ingroup node_access | |
*/ | |
function hook_node_grants(\Drupal\Core\Session\AccountInterface $account, $op) { | |
if ($account->hasPermission('access private content')) { | |
$grants['example'] = array(1); | |
} | |
if ($account->id()) { | |
$grants['example_author'] = array($account->id()); | |
} | |
return $grants; | |
} | |
/** | |
* Set permissions for a node to be written to the database. | |
* | |
* When a node is saved, a module implementing hook_node_access_records() will | |
* be asked if it is interested in the access permissions for a node. If it is | |
* interested, it must respond with an array of permissions arrays for that | |
* node. | |
* | |
* Node access grants apply regardless of the published or unpublished status | |
* of the node. Implementations must make sure not to grant access to | |
* unpublished nodes if they don't want to change the standard access control | |
* behavior. Your module may need to create a separate access realm to handle | |
* access to unpublished nodes. | |
* | |
* Note that the grant values in the return value from your hook must be | |
* integers and not boolean TRUE and FALSE. | |
* | |
* Each permissions item in the array is an array with the following elements: | |
* - 'realm': The name of a realm that the module has defined in | |
* hook_node_grants(). | |
* - 'gid': A 'grant ID' from hook_node_grants(). | |
* - 'grant_view': If set to 1 a user that has been identified as a member | |
* of this gid within this realm can view this node. This should usually be | |
* set to $node->isPublished(). Failure to do so may expose unpublished content | |
* to some users. | |
* - 'grant_update': If set to 1 a user that has been identified as a member | |
* of this gid within this realm can edit this node. | |
* - 'grant_delete': If set to 1 a user that has been identified as a member | |
* of this gid within this realm can delete this node. | |
* - langcode: (optional) The language code of a specific translation of the | |
* node, if any. Modules may add this key to grant different access to | |
* different translations of a node, such that (e.g.) a particular group is | |
* granted access to edit the Catalan version of the node, but not the | |
* Hungarian version. If no value is provided, the langcode is set | |
* automatically from the $node parameter and the node's original language (if | |
* specified) is used as a fallback. Only specify multiple grant records with | |
* different languages for a node if the site has those languages configured. | |
* | |
* A "deny all" grant may be used to deny all access to a particular node or | |
* node translation: | |
* @code | |
* $grants[] = array( | |
* 'realm' => 'all', | |
* 'gid' => 0, | |
* 'grant_view' => 0, | |
* 'grant_update' => 0, | |
* 'grant_delete' => 0, | |
* 'langcode' => 'ca', | |
* ); | |
* @endcode | |
* Note that another module node access module could override this by granting | |
* access to one or more nodes, since grants are additive. To enforce that | |
* access is denied in a particular case, use hook_node_access_records_alter(). | |
* Also note that a deny all is not written to the database; denies are | |
* implicit. | |
* | |
* @param \Drupal\node\NodeInterface $node | |
* The node that has just been saved. | |
* | |
* @return array | |
* An array of grants as defined above. | |
* | |
* @see hook_node_access_records_alter() | |
* @ingroup node_access | |
*/ | |
function hook_node_access_records(\Drupal\node\NodeInterface $node) { | |
// We only care about the node if it has been marked private. If not, it is | |
// treated just like any other node and we completely ignore it. | |
if ($node->private->value) { | |
$grants = array(); | |
// Only published Catalan translations of private nodes should be viewable | |
// to all users. If we fail to check $node->isPublished(), all users would be able | |
// to view an unpublished node. | |
if ($node->isPublished()) { | |
$grants[] = array( | |
'realm' => 'example', | |
'gid' => 1, | |
'grant_view' => 1, | |
'grant_update' => 0, | |
'grant_delete' => 0, | |
'langcode' => 'ca' | |
); | |
} | |
// For the example_author array, the GID is equivalent to a UID, which | |
// means there are many groups of just 1 user. | |
// Note that an author can always view his or her nodes, even if they | |
// have status unpublished. | |
if ($node->getOwnerId()) { | |
$grants[] = array( | |
'realm' => 'example_author', | |
'gid' => $node->getOwnerId(), | |
'grant_view' => 1, | |
'grant_update' => 1, | |
'grant_delete' => 1, | |
'langcode' => 'ca' | |
); | |
} | |
return $grants; | |
} | |
} | |
/** | |
* Alter permissions for a node before it is written to the database. | |
* | |
* Node access modules establish rules for user access to content. Node access | |
* records are stored in the {node_access} table and define which permissions | |
* are required to access a node. This hook is invoked after node access modules | |
* returned their requirements via hook_node_access_records(); doing so allows | |
* modules to modify the $grants array by reference before it is stored, so | |
* custom or advanced business logic can be applied. | |
* | |
* Upon viewing, editing or deleting a node, hook_node_grants() builds a | |
* permissions array that is compared against the stored access records. The | |
* user must have one or more matching permissions in order to complete the | |
* requested operation. | |
* | |
* A module may deny all access to a node by setting $grants to an empty array. | |
* | |
* @param array $grants | |
* The $grants array returned by hook_node_access_records(). | |
* @param \Drupal\node\NodeInterface $node | |
* The node for which the grants were acquired. | |
* | |
* The preferred use of this hook is in a module that bridges multiple node | |
* access modules with a configurable behavior, as shown in the example with the | |
* 'is_preview' field. | |
* | |
* @see hook_node_access_records() | |
* @see hook_node_grants() | |
* @see hook_node_grants_alter() | |
* @ingroup node_access | |
*/ | |
function hook_node_access_records_alter(&$grants, Drupal\node\NodeInterface $node) { | |
// Our module allows editors to mark specific articles with the 'is_preview' | |
// field. If the node being saved has a TRUE value for that field, then only | |
// our grants are retained, and other grants are removed. Doing so ensures | |
// that our rules are enforced no matter what priority other grants are given. | |
if ($node->is_preview) { | |
// Our module grants are set in $grants['example']. | |
$temp = $grants['example']; | |
// Now remove all module grants but our own. | |
$grants = array('example' => $temp); | |
} | |
} | |
/** | |
* Alter user access rules when trying to view, edit or delete a node. | |
* | |
* Node access modules establish rules for user access to content. | |
* hook_node_grants() defines permissions for a user to view, edit or delete | |
* nodes by building a $grants array that indicates the permissions assigned to | |
* the user by each node access module. This hook is called to allow modules to | |
* modify the $grants array by reference, so the interaction of multiple node | |
* access modules can be altered or advanced business logic can be applied. | |
* | |
* The resulting grants are then checked against the records stored in the | |
* {node_access} table to determine if the operation may be completed. | |
* | |
* A module may deny all access to a user by setting $grants to an empty array. | |
* | |
* Developers may use this hook to either add additional grants to a user or to | |
* remove existing grants. These rules are typically based on either the | |
* permissions assigned to a user role, or specific attributes of a user | |
* account. | |
* | |
* @param array $grants | |
* The $grants array returned by hook_node_grants(). | |
* @param \Drupal\Core\Session\AccountInterface $account | |
* The account requesting access to content. | |
* @param string $op | |
* The operation being performed, 'view', 'update' or 'delete'. | |
* | |
* @see hook_node_grants() | |
* @see hook_node_access_records() | |
* @see hook_node_access_records_alter() | |
* @ingroup node_access | |
*/ | |
function hook_node_grants_alter(&$grants, \Drupal\Core\Session\AccountInterface $account, $op) { | |
// Our sample module never allows certain roles to edit or delete | |
// content. Since some other node access modules might allow this | |
// permission, we expressly remove it by returning an empty $grants | |
// array for roles specified in our variable setting. | |
// Get our list of banned roles. | |
$restricted = \Drupal::config('example.settings')->get('restricted_roles'); | |
if ($op != 'view' && !empty($restricted)) { | |
// Now check the roles for this account against the restrictions. | |
foreach ($account->getRoles() as $rid) { | |
if (in_array($rid, $restricted)) { | |
$grants = array(); | |
} | |
} | |
} | |
} | |
/** | |
* Controls access to a node. | |
* | |
* Modules may implement this hook if they want to have a say in whether or not | |
* a given user has access to perform a given operation on a node. | |
* | |
* The administrative account (user ID #1) always passes any access check, so | |
* this hook is not called in that case. Users with the "bypass node access" | |
* permission may always view and edit content through the administrative | |
* interface. | |
* | |
* Note that not all modules will want to influence access on all node types. If | |
* your module does not want to explicitly allow or forbid access, return an | |
* AccessResultInterface object with neither isAllowed() nor isForbidden() | |
* equaling TRUE. Blindly returning an object with isForbidden() equaling TRUE | |
* will break other node access modules. | |
* | |
* Also note that this function isn't called for node listings (e.g., RSS feeds, | |
* the default home page at path 'node', a recent content block, etc.) See | |
* @link node_access Node access rights @endlink for a full explanation. | |
* | |
* @param \Drupal\node\NodeInterface|string $node | |
* Either a node entity or the machine name of the content type on which to | |
* perform the access check. | |
* @param string $op | |
* The operation to be performed. Possible values: | |
* - "create" | |
* - "delete" | |
* - "update" | |
* - "view" | |
* @param \Drupal\Core\Session\AccountInterface $account | |
* The user object to perform the access check operation on. | |
* | |
* @return \Drupal\Core\Access\AccessResultInterface | |
* The access result. | |
* | |
* @ingroup node_access | |
*/ | |
function hook_node_access(\Drupal\node\NodeInterface $node, $op, \Drupal\Core\Session\AccountInterface $account) { | |
$type = $node->bundle(); | |
switch ($op) { | |
case 'create': | |
return AccessResult::allowedIfHasPermission($account, 'create ' . $type . ' content'); | |
case 'update': | |
if ($account->hasPermission('edit any ' . $type . ' content', $account)) { | |
return AccessResult::allowed()->cachePerPermissions(); | |
} | |
else { | |
return AccessResult::allowedIf($account->hasPermission('edit own ' . $type . ' content', $account) && ($account->id() == $node->getOwnerId()))->cachePerPermissions()->cachePerUser()->cacheUntilEntityChanges($node); | |
} | |
case 'delete': | |
if ($account->hasPermission('delete any ' . $type . ' content', $account)) { | |
return AccessResult::allowed()->cachePerPermissions(); | |
} | |
else { | |
return AccessResult::allowedIf($account->hasPermission('delete own ' . $type . ' content', $account) && ($account->id() == $node->getOwnerId()))->cachePerPermissions()->cachePerUser()->cacheUntilEntityChanges($node); | |
} | |
default: | |
// No opinion. | |
return AccessResult::neutral(); | |
} | |
} | |
/** | |
* Act on a node being displayed as a search result. | |
* | |
* This hook is invoked from the node search plugin during search execution, | |
* after loading and rendering the node. | |
* | |
* @param \Drupal\node\NodeInterface $node | |
* The node being displayed in a search result. | |
* | |
* @return array | |
* Extra information to be displayed with search result. This information | |
* should be presented as an associative array. It will be concatenated with | |
* the post information (last updated, author) in the default search result | |
* theming. | |
* | |
* @see template_preprocess_search_result() | |
* @see search-result.html.twig | |
* | |
* @ingroup entity_crud | |
*/ | |
function hook_node_search_result(\Drupal\node\NodeInterface $node) { | |
$rating = db_query('SELECT SUM(points) FROM {my_rating} WHERE nid = :nid', array('nid' => $node->id()))->fetchField(); | |
return array('rating' => \Drupal::translation()->formatPlural($rating, '1 point', '@count points')); | |
} | |
/** | |
* Act on a node being indexed for searching. | |
* | |
* This hook is invoked during search indexing, after loading, and after the | |
* result of rendering is added as $node->rendered to the node object. | |
* | |
* @param \Drupal\node\NodeInterface $node | |
* The node being indexed. | |
* | |
* @return string | |
* Additional node information to be indexed. | |
* | |
* @ingroup entity_crud | |
*/ | |
function hook_node_update_index(\Drupal\node\NodeInterface $node) { | |
$text = ''; | |
$ratings = db_query('SELECT title, description FROM {my_ratings} WHERE nid = :nid', array(':nid' => $node->id())); | |
foreach ($ratings as $rating) { | |
$text .= '<h2>' . Html::escape($rating->title) . '</h2>' . Xss::filter($rating->description); | |
} | |
return $text; | |
} | |
/** | |
* Provide additional methods of scoring for core search results for nodes. | |
* | |
* A node's search score is used to rank it among other nodes matched by the | |
* search, with the highest-ranked nodes appearing first in the search listing. | |
* | |
* For example, a module allowing users to vote on content could expose an | |
* option to allow search results' rankings to be influenced by the average | |
* voting score of a node. | |
* | |
* All scoring mechanisms are provided as options to site administrators, and | |
* may be tweaked based on individual sites or disabled altogether if they do | |
* not make sense. Individual scoring mechanisms, if enabled, are assigned a | |
* weight from 1 to 10. The weight represents the factor of magnification of | |
* the ranking mechanism, with higher-weighted ranking mechanisms having more | |
* influence. In order for the weight system to work, each scoring mechanism | |
* must return a value between 0 and 1 for every node. That value is then | |
* multiplied by the administrator-assigned weight for the ranking mechanism, | |
* and then the weighted scores from all ranking mechanisms are added, which | |
* brings about the same result as a weighted average. | |
* | |
* @return array | |
* An associative array of ranking data. The keys should be strings, | |
* corresponding to the internal name of the ranking mechanism, such as | |
* 'recent', or 'comments'. The values should be arrays themselves, with the | |
* following keys available: | |
* - title: (required) The human readable name of the ranking mechanism. | |
* - join: (optional) An array with information to join any additional | |
* necessary table. This is not necessary if the table required is already | |
* joined to by the base query, such as for the {node} table. Other tables | |
* should use the full table name as an alias to avoid naming collisions. | |
* - score: (required) The part of a query string to calculate the score for | |
* the ranking mechanism based on values in the database. This does not need | |
* to be wrapped in parentheses, as it will be done automatically; it also | |
* does not need to take the weighted system into account, as it will be | |
* done automatically. It does, however, need to calculate a decimal between | |
* 0 and 1; be careful not to cast the entire score to an integer by | |
* inadvertently introducing a variable argument. | |
* - arguments: (optional) If any arguments are required for the score, they | |
* can be specified in an array here. | |
* | |
* @ingroup entity_crud | |
*/ | |
function hook_ranking() { | |
// If voting is disabled, we can avoid returning the array, no hard feelings. | |
if (\Drupal::config('vote.settings')->get('node_enabled')) { | |
return array( | |
'vote_average' => array( | |
'title' => t('Average vote'), | |
// Note that we use i.sid, the search index's search item id, rather than | |
// n.nid. | |
'join' => array( | |
'type' => 'LEFT', | |
'table' => 'vote_node_data', | |
'alias' => 'vote_node_data', | |
'on' => 'vote_node_data.nid = i.sid', | |
), | |
// The highest possible score should be 1, and the lowest possible score, | |
// always 0, should be 0. | |
'score' => 'vote_node_data.average / CAST(%f AS DECIMAL)', | |
// Pass in the highest possible voting score as a decimal argument. | |
'arguments' => array(\Drupal::config('vote.settings')->get('score_max')), | |
), | |
); | |
} | |
} | |
/** | |
* Alter the links of a node. | |
* | |
* @param array &$links | |
* A renderable array representing the node links. | |
* @param \Drupal\node\NodeInterface $entity | |
* The node being rendered. | |
* @param array &$context | |
* Various aspects of the context in which the node links are going to be | |
* displayed, with the following keys: | |
* - 'view_mode': the view mode in which the node is being viewed | |
* - 'langcode': the language in which the node is being viewed | |
* | |
* @see \Drupal\node\NodeViewBuilder::renderLinks() | |
* @see \Drupal\node\NodeViewBuilder::buildLinks() | |
* @see entity_crud | |
*/ | |
function hook_node_links_alter(array &$links, NodeInterface $entity, array &$context) { | |
$links['mymodule'] = array( | |
'#theme' => 'links__node__mymodule', | |
'#attributes' => array('class' => array('links', 'inline')), | |
'#links' => array( | |
'node-report' => array( | |
'title' => t('Report'), | |
'href' => "node/{$entity->id()}/report", | |
'query' => array('token' => \Drupal::getContainer()->get('csrf_token')->get("node/{$entity->id()}/report")), | |
), | |
), | |
); | |
} | |
/** | |
* @} End of "addtogroup hooks". | |
*/ |