summaryrefslogtreecommitdiffstats
path: root/core/modules/node/node.install
blob: 6469245c49bc47f484b4599936724c7a2e361e85 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
<?php

/**
 * @file
 * Install, update and uninstall functions for the node module.
 */

use Drupal\Core\Database\Database;
use Drupal\Core\Field\BaseFieldDefinition;
use Drupal\user\RoleInterface;

/**
 * Implements hook_requirements().
 */
function node_requirements($phase) {
  $requirements = [];
  if ($phase === 'runtime') {
    // Only show rebuild button if there are either 0, or 2 or more, rows
    // in the {node_access} table, or if there are modules that
    // implement hook_node_grants().
    $grant_count = \Drupal::entityManager()->getAccessControlHandler('node')->countGrants();
    if ($grant_count != 1 || count(\Drupal::moduleHandler()->getImplementations('node_grants')) > 0) {
      $value = \Drupal::translation()->formatPlural($grant_count, 'One permission in use', '@count permissions in use', ['@count' => $grant_count]);
    }
    else {
      $value = t('Disabled');
    }

    $requirements['node_access'] = [
      'title' => t('Node Access Permissions'),
      'value' => $value,
      '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>', [
        ':rebuild' => \Drupal::url('node.configure_rebuild_confirm'),
      ]),
    ];
  }
  return $requirements;
}

/**
 * Implements hook_schema().
 */
function node_schema() {
  $schema['node_access'] = [
    'description' => 'Identifies which realm/grant pairs a user must possess in order to view, update, or delete specific nodes.',
    'fields' => [
      'nid' => [
        'description' => 'The {node}.nid this record affects.',
        'type' => 'int',
        'unsigned' => TRUE,
        'not null' => TRUE,
        'default' => 0,
      ],
      'langcode' => [
        'description' => 'The {language}.langcode of this node.',
        'type' => 'varchar_ascii',
        'length' => 12,
        'not null' => TRUE,
        'default' => '',
      ],
      'fallback' => [
        'description' => 'Boolean indicating whether this record should be used as a fallback if a language condition is not provided.',
        'type' => 'int',
        'unsigned' => TRUE,
        'not null' => TRUE,
        'default' => 1,
        'size' => 'tiny',
      ],
      'gid' => [
        'description' => "The grant ID a user must possess in the specified realm to gain this row's privileges on the node.",
        'type' => 'int',
        'unsigned' => TRUE,
        'not null' => TRUE,
        'default' => 0,
      ],
      'realm' => [
        'description' => 'The realm in which the user must possess the grant ID. Modules can define one or more realms by implementing hook_node_grants().',
        'type' => 'varchar_ascii',
        'length' => 255,
        'not null' => TRUE,
        'default' => '',
      ],
      'grant_view' => [
        'description' => 'Boolean indicating whether a user with the realm/grant pair can view this node.',
        'type' => 'int',
        'unsigned' => TRUE,
        'not null' => TRUE,
        'default' => 0,
        'size' => 'tiny',
      ],
      'grant_update' => [
        'description' => 'Boolean indicating whether a user with the realm/grant pair can edit this node.',
        'type' => 'int',
        'unsigned' => TRUE,
        'not null' => TRUE,
        'default' => 0,
        'size' => 'tiny',
      ],
      'grant_delete' => [
        'description' => 'Boolean indicating whether a user with the realm/grant pair can delete this node.',
        'type' => 'int',
        'unsigned' => TRUE,
        'not null' => TRUE,
        'default' => 0,
        'size' => 'tiny',
      ],
    ],
    'primary key' => ['nid', 'gid', 'realm', 'langcode'],
    'foreign keys' => [
      'affected_node' => [
        'table' => 'node',
        'columns' => ['nid' => 'nid'],
      ],
    ],
  ];

  return $schema;
}

/**
 * Implements hook_install().
 */
function node_install() {
  // Enable default permissions for system roles.
  // IMPORTANT: Modules SHOULD NOT automatically grant any user role access
  // permissions in hook_install().
  // However, the 'access content' permission is a very special case, since
  // there is hardly a point in installing the Node module without granting
  // these permissions. Doing so also allows tests to continue to operate as
  // expected without first having to manually grant these default permissions.
  if (\Drupal::moduleHandler()->moduleExists('user')) {
    user_role_grant_permissions(RoleInterface::ANONYMOUS_ID, ['access content']);
    user_role_grant_permissions(RoleInterface::AUTHENTICATED_ID, ['access content']);
  }

  // Populate the node access table.
  db_insert('node_access')
    ->fields([
      'nid' => 0,
      'gid' => 0,
      'realm' => 'all',
      'grant_view' => 1,
      'grant_update' => 0,
      'grant_delete' => 0,
    ])
    ->execute();
}

/**
 * Implements hook_uninstall().
 */
function node_uninstall() {
  // Delete remaining general module variables.
  \Drupal::state()->delete('node.node_access_needs_rebuild');
}

/**
 * Add 'revision_translation_affected' field to 'node' entities.
 */
function node_update_8001() {
  // Install the definition that this field had in
  // \Drupal\node\Entity\Node::baseFieldDefinitions()
  // at the time that this update function was written. If/when code is
  // deployed that changes that definition, the corresponding module must
  // implement an update function that invokes
  // \Drupal::entityDefinitionUpdateManager()->updateFieldStorageDefinition()
  // with the new definition.
  $storage_definition = BaseFieldDefinition::create('boolean')
    ->setLabel(t('Revision translation affected'))
    ->setDescription(t('Indicates if the last edit of a translation belongs to current revision.'))
    ->setReadOnly(TRUE)
    ->setRevisionable(TRUE)
    ->setTranslatable(TRUE);

  \Drupal::entityDefinitionUpdateManager()
    ->installFieldStorageDefinition('revision_translation_affected', 'node', 'node', $storage_definition);
}

/**
 * Remove obsolete indexes from the node schema.
 */
function node_update_8002() {
  // The "node__default_langcode" and "node_field__langcode" indexes were
  // removed from \Drupal\node\NodeStorageSchema in
  // https://www.drupal.org/node/2261669, but this update function wasn't
  // added until https://www.drupal.org/node/2542748. Regenerate the related
  // schemas to ensure they match the currently expected status.
  $manager = \Drupal::entityDefinitionUpdateManager();
  // Regenerate entity type indexes, this should drop "node__default_langcode".
  $manager->updateEntityType($manager->getEntityType('node'));
  // Regenerate "langcode" indexes, this should drop "node_field__langcode".
  $manager->updateFieldStorageDefinition($manager->getFieldStorageDefinition('langcode', 'node'));
}

/**
 * Promote 'status' and 'uid' fields to entity keys.
 */
function node_update_8003() {
  // The 'status' and 'uid' fields were added to the 'entity_keys' annotation
  // of \Drupal\node\Entity\Node in https://www.drupal.org/node/2498919, but
  // this update function wasn't added until
  // https://www.drupal.org/node/2542748.
  $manager = \Drupal::entityDefinitionUpdateManager();
  $entity_type = $manager->getEntityType('node');
  $entity_keys = $entity_type->getKeys();
  $entity_keys['status'] = 'status';
  $entity_keys['uid'] = 'uid';
  $entity_type->set('entity_keys', $entity_keys);
  $manager->updateEntityType($entity_type);

  // @todo The above should be enough, since that is the only definition that
  //   changed. But \Drupal\Core\Entity\Sql\SqlContentEntityStorageSchema varies
  //   field schema by whether a field is an entity key, so invoke
  //   EntityDefinitionUpdateManagerInterface::updateFieldStorageDefinition()
  //   with an unmodified field storage definition to trigger the necessary
  //   changes. SqlContentEntityStorageSchema::onEntityTypeUpdate() should be
  //   fixed to automatically handle this.
  //   See https://www.drupal.org/node/2554245.
  foreach (['status', 'uid'] as $field_name) {
    $manager->updateFieldStorageDefinition($manager->getFieldStorageDefinition($field_name, 'node'));
  }
}

/**
 * Change {node_access}.fallback from an int to a tinyint as it is a boolean.
 */
function node_update_8300() {
  Database::getConnection()->schema()->changeField('node_access', 'fallback', 'fallback', [
    'description' => 'Boolean indicating whether this record should be used as a fallback if a language condition is not provided.',
    'type' => 'int',
    'unsigned' => TRUE,
    'not null' => TRUE,
    'default' => 1,
    'size' => 'tiny',
  ]);
}

/**
 * Set the 'published' entity key.
 */
function node_update_8301() {
  $definition_update_manager = \Drupal::entityDefinitionUpdateManager();
  $entity_type = $definition_update_manager->getEntityType('node');
  $keys = $entity_type->getKeys();
  $keys['published'] = 'status';
  $entity_type->set('entity_keys', $keys);
  $definition_update_manager->updateEntityType($entity_type);
}

/**
 * Fix realm column description on the node_access table.
 */
function node_update_8400() {
  $schema = drupal_get_module_schema('node', 'node_access');
  $schema['fields']['realm']['description'] = 'The realm in which the user must possess the grant ID. Modules can define one or more realms by implementing hook_node_grants().';
  Database::getConnection()->schema()->changeField('node_access', 'realm', 'realm', $schema['fields']['realm']);
}