node.install 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. <?php
  2. /**
  3. * @file
  4. * Install, update and uninstall functions for the node module.
  5. */
  6. use Drupal\Core\Field\BaseFieldDefinition;
  7. use Drupal\user\RoleInterface;
  8. /**
  9. * Implements hook_requirements().
  10. */
  11. function node_requirements($phase) {
  12. $requirements = array();
  13. if ($phase === 'runtime') {
  14. // Only show rebuild button if there are either 0, or 2 or more, rows
  15. // in the {node_access} table, or if there are modules that
  16. // implement hook_node_grants().
  17. $grant_count = \Drupal::entityManager()->getAccessControlHandler('node')->countGrants();
  18. if ($grant_count != 1 || count(\Drupal::moduleHandler()->getImplementations('node_grants')) > 0) {
  19. $value = \Drupal::translation()->formatPlural($grant_count, 'One permission in use', '@count permissions in use', array('@count' => $grant_count));
  20. }
  21. else {
  22. $value = t('Disabled');
  23. }
  24. $requirements['node_access'] = array(
  25. 'title' => t('Node Access Permissions'),
  26. 'value' => $value,
  27. 'description' => t('If the site is experiencing problems with permissions to content, you may have to rebuild the permissions cache. Rebuilding will remove all privileges to content and replace them with permissions based on the current modules and settings. Rebuilding may take some time if there is a lot of content or complex permission settings. After rebuilding has completed, content will automatically use the new permissions. <a href=":rebuild">Rebuild permissions</a>', array(
  28. ':rebuild' => \Drupal::url('node.configure_rebuild_confirm'),
  29. )),
  30. );
  31. }
  32. return $requirements;
  33. }
  34. /**
  35. * Implements hook_schema().
  36. */
  37. function node_schema() {
  38. $schema['node_access'] = array(
  39. 'description' => 'Identifies which realm/grant pairs a user must possess in order to view, update, or delete specific nodes.',
  40. 'fields' => array(
  41. 'nid' => array(
  42. 'description' => 'The {node}.nid this record affects.',
  43. 'type' => 'int',
  44. 'unsigned' => TRUE,
  45. 'not null' => TRUE,
  46. 'default' => 0,
  47. ),
  48. 'langcode' => array(
  49. 'description' => 'The {language}.langcode of this node.',
  50. 'type' => 'varchar_ascii',
  51. 'length' => 12,
  52. 'not null' => TRUE,
  53. 'default' => '',
  54. ),
  55. 'fallback' => array(
  56. 'description' => 'Boolean indicating whether this record should be used as a fallback if a language condition is not provided.',
  57. 'type' => 'int',
  58. 'unsigned' => TRUE,
  59. 'not null' => TRUE,
  60. 'default' => 1,
  61. ),
  62. 'gid' => array(
  63. 'description' => "The grant ID a user must possess in the specified realm to gain this row's privileges on the node.",
  64. 'type' => 'int',
  65. 'unsigned' => TRUE,
  66. 'not null' => TRUE,
  67. 'default' => 0,
  68. ),
  69. 'realm' => array(
  70. 'description' => 'The realm in which the user must possess the grant ID. Each node access node can define one or more realms.',
  71. 'type' => 'varchar_ascii',
  72. 'length' => 255,
  73. 'not null' => TRUE,
  74. 'default' => '',
  75. ),
  76. 'grant_view' => array(
  77. 'description' => 'Boolean indicating whether a user with the realm/grant pair can view this node.',
  78. 'type' => 'int',
  79. 'unsigned' => TRUE,
  80. 'not null' => TRUE,
  81. 'default' => 0,
  82. 'size' => 'tiny',
  83. ),
  84. 'grant_update' => array(
  85. 'description' => 'Boolean indicating whether a user with the realm/grant pair can edit this node.',
  86. 'type' => 'int',
  87. 'unsigned' => TRUE,
  88. 'not null' => TRUE,
  89. 'default' => 0,
  90. 'size' => 'tiny',
  91. ),
  92. 'grant_delete' => array(
  93. 'description' => 'Boolean indicating whether a user with the realm/grant pair can delete this node.',
  94. 'type' => 'int',
  95. 'unsigned' => TRUE,
  96. 'not null' => TRUE,
  97. 'default' => 0,
  98. 'size' => 'tiny',
  99. ),
  100. ),
  101. 'primary key' => array('nid', 'gid', 'realm', 'langcode'),
  102. 'foreign keys' => array(
  103. 'affected_node' => array(
  104. 'table' => 'node',
  105. 'columns' => array('nid' => 'nid'),
  106. ),
  107. ),
  108. );
  109. return $schema;
  110. }
  111. /**
  112. * Implements hook_install().
  113. */
  114. function node_install() {
  115. // Enable default permissions for system roles.
  116. // IMPORTANT: Modules SHOULD NOT automatically grant any user role access
  117. // permissions in hook_install().
  118. // However, the 'access content' permission is a very special case, since
  119. // there is hardly a point in installing the Node module without granting
  120. // these permissions. Doing so also allows tests to continue to operate as
  121. // expected without first having to manually grant these default permissions.
  122. if (\Drupal::moduleHandler()->moduleExists('user')) {
  123. user_role_grant_permissions(RoleInterface::ANONYMOUS_ID, array('access content'));
  124. user_role_grant_permissions(RoleInterface::AUTHENTICATED_ID, array('access content'));
  125. }
  126. // Populate the node access table.
  127. db_insert('node_access')
  128. ->fields(array(
  129. 'nid' => 0,
  130. 'gid' => 0,
  131. 'realm' => 'all',
  132. 'grant_view' => 1,
  133. 'grant_update' => 0,
  134. 'grant_delete' => 0,
  135. ))
  136. ->execute();
  137. }
  138. /**
  139. * Implements hook_uninstall().
  140. */
  141. function node_uninstall() {
  142. // Delete remaining general module variables.
  143. \Drupal::state()->delete('node.node_access_needs_rebuild');
  144. }
  145. /**
  146. * Add 'revision_translation_affected' field to 'node' entities.
  147. */
  148. function node_update_8001() {
  149. // Install the definition that this field had in
  150. // \Drupal\node\Entity\Node::baseFieldDefinitions()
  151. // at the time that this update function was written. If/when code is
  152. // deployed that changes that definition, the corresponding module must
  153. // implement an update function that invokes
  154. // \Drupal::entityDefinitionUpdateManager()->updateFieldStorageDefinition()
  155. // with the new definition.
  156. $storage_definition = BaseFieldDefinition::create('boolean')
  157. ->setLabel(t('Revision translation affected'))
  158. ->setDescription(t('Indicates if the last edit of a translation belongs to current revision.'))
  159. ->setReadOnly(TRUE)
  160. ->setRevisionable(TRUE)
  161. ->setTranslatable(TRUE);
  162. \Drupal::entityDefinitionUpdateManager()
  163. ->installFieldStorageDefinition('revision_translation_affected', 'node', 'node', $storage_definition);
  164. }
  165. /**
  166. * Remove obsolete indexes from the node schema.
  167. */
  168. function node_update_8002() {
  169. // The "node__default_langcode" and "node_field__langcode" indexes were
  170. // removed from \Drupal\node\NodeStorageSchema in
  171. // https://www.drupal.org/node/2261669, but this update function wasn't
  172. // added until https://www.drupal.org/node/2542748. Regenerate the related
  173. // schemas to ensure they match the currently expected status.
  174. $manager = \Drupal::entityDefinitionUpdateManager();
  175. // Regenerate entity type indexes, this should drop "node__default_langcode".
  176. $manager->updateEntityType($manager->getEntityType('node'));
  177. // Regenerate "langcode" indexes, this should drop "node_field__langcode".
  178. $manager->updateFieldStorageDefinition($manager->getFieldStorageDefinition('langcode', 'node'));
  179. }
  180. /**
  181. * Promote 'status' and 'uid' fields to entity keys.
  182. */
  183. function node_update_8003() {
  184. // The 'status' and 'uid' fields were added to the 'entity_keys' annotation
  185. // of \Drupal\node\Entity\Node in https://www.drupal.org/node/2498919, but
  186. // this update function wasn't added until
  187. // https://www.drupal.org/node/2542748.
  188. $manager = \Drupal::entityDefinitionUpdateManager();
  189. $entity_type = $manager->getEntityType('node');
  190. $entity_keys = $entity_type->getKeys();
  191. $entity_keys['status'] = 'status';
  192. $entity_keys['uid'] = 'uid';
  193. $entity_type->set('entity_keys', $entity_keys);
  194. $manager->updateEntityType($entity_type);
  195. // @todo The above should be enough, since that is the only definition that
  196. // changed. But \Drupal\Core\Entity\Sql\SqlContentEntityStorageSchema varies
  197. // field schema by whether a field is an entity key, so invoke
  198. // EntityDefinitionUpdateManagerInterface::updateFieldStorageDefinition()
  199. // with an unmodified field storage definition to trigger the necessary
  200. // changes. SqlContentEntityStorageSchema::onEntityTypeUpdate() should be
  201. // fixed to automatically handle this.
  202. // See https://www.drupal.org/node/2554245.
  203. foreach (array('status', 'uid') as $field_name) {
  204. $manager->updateFieldStorageDefinition($manager->getFieldStorageDefinition($field_name, 'node'));
  205. }
  206. }