Project

General

Profile

Paste
Download (18.4 KB) Statistics
| Branch: | Revision:

root / drupal7 / sites / all / modules / field_permissions / field_permissions.admin.inc @ a8cee257

1
<?php
2

    
3
/**
4
 * @file
5
 * Administrative interface for the Field Permissions module.
6
 */
7

    
8
/**
9
 * Obtain the list of field permissions.
10
 *
11
 * @param string $field_label
12
 *   The human readable name of the field to use when constructing permission
13
 *   names. Usually this will be derived from one or more of the field instance
14
 *   labels.
15
 */
16
function field_permissions_list($field_label = '') {
17
  $permissions = array(
18
    'create' => array(
19
      'label' => t('Create field'),
20
      'title' => t('Create own value for field %field', array('%field' => $field_label)),
21
    ),
22
    'edit own' => array(
23
      'label' => t('Edit own field'),
24
      'title' => t('Edit own value for field %field', array('%field' => $field_label)),
25
    ),
26
    'edit' => array(
27
      'label' => t('Edit field'),
28
      'title' => t("Edit anyone's value for field %field", array('%field' => $field_label)),
29
    ),
30
    'view own' => array(
31
      'label' => t('View own field'),
32
      'title' => t('View own value for field %field', array('%field' => $field_label)),
33
    ),
34
    'view' => array(
35
      'label' => t('View field'),
36
      'title' => t("View anyone's value for field %field", array('%field' => $field_label)),
37
    ),
38
  );
39

    
40
  drupal_alter('field_permissions_list', $permissions, $field_label);
41

    
42
  return $permissions;
43
}
44

    
45
/**
46
 * Returns field permissions in a format suitable for use in hook_permission().
47
 *
48
 * @param array $field
49
 *   The field to return permissions for.
50
 * @param mixed $label
51
 *   (optional) The human readable name of the field to use when constructing
52
 *   permission names; for example, this might be the label of one of the
53
 *   corresponding field instances. If not provided, an appropriate label will
54
 *   be automatically derived from all the field's instances.
55
 *
56
 * @return array
57
 *   An array of permission information, suitable for use in hook_permission().
58
 */
59
function field_permissions_list_field_permissions($field, $label = NULL) {
60
  if (!isset($label)) {
61
    $label = $field['field_name'];
62
  }
63
  $instances = array();
64
  $description = '';
65
  foreach ($field['bundles'] as $entity_type => $bundles) {
66
    foreach ($bundles as $bundle_name) {
67
      $instance = field_info_instance($entity_type, $field['field_name'], $bundle_name);
68
      $entity = entity_get_info($entity_type);
69
      if (!isset($entity['bundles'][$bundle_name])) {
70
        continue;
71
      }
72
      $instance_desc_tokens = array(
73
        $entity['label'],
74
        $entity['bundles'][$bundle_name]['label'],
75
        $instance['label'],
76
      );
77
      $instances[] = '"' . implode(':', $instance_desc_tokens) . '"';
78
    }
79
    $description = t('This field appears as: %instances.', array('%instances' => implode(', ', $instances)));
80
  }
81

    
82
  $permissions = array();
83
  foreach (field_permissions_list($label) as $permission_type => $permission_info) {
84
    $permission = $permission_type . ' ' . $field['field_name'];
85
    $permissions[$permission] = array(
86
      'title' => $permission_info['title'],
87
      'description' => $description,
88
    );
89
  }
90

    
91
  return $permissions;
92
}
93

    
94
/**
95
 * Implements hook_permission().
96
 */
97
function _field_permissions_permission() {
98
  $perms = array(
99
    'administer field permissions' => array(
100
      'title' => t('Administer field permissions'),
101
      'description' => t('Manage field permissions and field permissions settings.'),
102
      'restrict access' => TRUE,
103
    ),
104
    'access private fields' => array(
105
      'title' => t("Access other users' private fields"),
106
      'description' => t('View and edit the stored values of all private fields.'),
107
      'restrict access' => TRUE,
108
    ),
109
  );
110

    
111
  foreach (field_info_fields() as $field) {
112
    if (isset($field['field_permissions']['type']) && $field['field_permissions']['type'] == FIELD_PERMISSIONS_CUSTOM) {
113
      $perms += field_permissions_list_field_permissions($field);
114
    }
115
  }
116

    
117
  return $perms;
118
}
119

    
120
/**
121
 * Alter the field settings form.
122
 */
123
function _field_permissions_field_settings_form_alter(&$form, $form_state, $form_id) {
124
  // Put the field permissions extensions at the top of the field settings
125
  // fieldset.
126
  $form['field']['field_permissions'] = array(
127
    '#weight' => -10,
128
    '#access' => user_access('administer field permissions'),
129
  );
130

    
131
  $form['field']['field_permissions']['type'] = array(
132
    '#title' => t('Field visibility and permissions'),
133
    '#type' => 'radios',
134
    '#options' => array(
135
      FIELD_PERMISSIONS_PUBLIC => t('Public (author and administrators can edit, everyone can view)'),
136
      FIELD_PERMISSIONS_PRIVATE => t('Private (only author and administrators can edit and view)'),
137
      FIELD_PERMISSIONS_CUSTOM => t('Custom permissions'),
138
    ),
139
    '#default_value' => isset($form['#field']['field_permissions']['type']) ? $form['#field']['field_permissions']['type'] : FIELD_PERMISSIONS_PUBLIC,
140
  );
141

    
142
  // Add the container in which the field permissions matrix will be displayed.
143
  // (and make it so that it is only visible when custom permissions are being
144
  // used).
145
  $form['field']['field_permissions']['permissions'] = array(
146
    '#type' => 'container',
147
    '#states' => array(
148
      'visible' => array(
149
        ':input[name="field[field_permissions][type]"]' => array('value' => FIELD_PERMISSIONS_CUSTOM),
150
      ),
151
    ),
152
    // Custom styling for the permissions matrix on the field settings page.
153
    '#attached' => array(
154
      'css' => array(drupal_get_path('module', 'field_permissions') . '/field_permissions.admin.css'),
155
    ),
156
  );
157

    
158
  $form['field']['field_permissions']['permission_warning'] = array(
159
    '#type' => 'item',
160
    '#markup' => '<div class="messages error"><b>'
161
    . t('Field permissions error')
162
    . '</b><br />'
163
    . t('If you are seeing this message and are not seeing a table of permissions, something is wrong! See !link for more information.', array(
164
      '!link' => l(t('the Field Permission documentation'), 'https://www.drupal.org/node/2802067#known-issues', array(
165
        'attributes' => array('target' => '_blank'),
166
      )),
167
    )) . '</div>',
168
    '#states' => array(
169
      'visible' => array(
170
        ':input[name="field[field_permissions][type]"]' => array('value' => FIELD_PERMISSIONS_CUSTOM),
171
      ),
172
    ),
173
  );
174

    
175
  // Add the field permissions matrix itself. Wait until the #pre_render stage
176
  // to move it to the above container, to avoid having the permissions data
177
  // saved as part of the field record.
178
  $form['field_permissions']['#tree'] = TRUE;
179
  $form['field_permissions']['#access'] = user_access('administer field permissions');
180
  $form['field_permissions']['permissions'] = field_permissions_permissions_matrix($form['#field'], $form['#instance']);
181
  $form['#pre_render'][] = '_field_permissions_field_settings_form_pre_render';
182

    
183
  // Add a submit handler to process the field permissions settings. Note that
184
  // it is important for this to run *after* the main field UI submit handler
185
  // (which saves the field itself), since when a new field is being created,
186
  // our submit handler will try to assign any new custom permissions
187
  // immediately, and our hook_permission() implementation relies on the field
188
  // info being up-to-date in order for that to work correctly.
189
  $form['#submit'][] = '_field_permissions_field_settings_form_submit';
190
}
191

    
192
/**
193
 * Returns a field permissions matrix that can be inserted into a form.
194
 *
195
 * The matrix's display is based on that of Drupal's default permissions page.
196
 *
197
 * Note that this matrix must be accompanied by an appropriate submit handler
198
 * (attached to the top level of the form) in order for the permissions in it
199
 * to actually be saved. For an example submit handler, see
200
 * _field_permissions_field_settings_form_submit().
201
 *
202
 * @param array $field
203
 *   The field whose permissions will be displayed in the matrix.
204
 * @param array $instance
205
 *   The field instance for which the permissions will be displayed. Although
206
 *   the permissions are per-field rather than per-instance, the instance label
207
 *   will be used to display an appropriate human-readable name for each
208
 *   permission.
209
 *
210
 * @return array
211
 *   A form array defining the permissions matrix.
212
 *
213
 * @see user_admin_permissions()
214
 * @see _field_permissions_field_settings_form_submit()
215
 */
216
function field_permissions_permissions_matrix($field, $instance) {
217
  // This function primarily contains a simplified version of the code from
218
  // user_admin_permissions().
219
  $form['#theme'] = 'user_admin_permissions';
220
  $options = array();
221
  $status = array();
222

    
223
  // Retrieve all role names for use in the submit handler.
224
  $role_names = user_roles();
225
  $form['role_names'] = array(
226
    '#type' => 'value',
227
    '#value' => $role_names,
228
  );
229

    
230
  // Retrieve the permissions for each role, and the field permissions we will
231
  // be assigning here.
232
  $role_permissions = user_role_permissions($role_names);
233
  $field_permissions = field_permissions_list_field_permissions($field, $instance['label']);
234

    
235
  // Determine if it is safe to reset the default values for this field's
236
  // permissions. If this is a new field (never saved with field permission
237
  // data before), or if it's an existing field that is not currently using
238
  // custom permissions and doesn't have any previously-saved ones already in
239
  // the database, then it will be safe to reset them.
240
  $reset_permissions_defaults = FALSE;
241
  if (!isset($field['field_permissions']['type'])) {
242
    $reset_permissions_defaults = TRUE;
243
  }
244
  elseif ($field['field_permissions']['type'] != FIELD_PERMISSIONS_CUSTOM) {
245
    $all_assigned_permissions = call_user_func_array('array_merge_recursive', $role_permissions);
246
    $assigned_field_permissions = array_intersect_key($all_assigned_permissions, $field_permissions);
247
    $reset_permissions_defaults = empty($assigned_field_permissions);
248
  }
249
  // Store this information on the form so that other modules can use it (for
250
  // example, if they want to set default permissions for other roles besides
251
  // the admin role which we use it for below).
252
  $form['#field_permissions_are_new'] = $reset_permissions_defaults;
253

    
254
  // Go through each field permission we will display.
255
  foreach ($field_permissions as $permission => $info) {
256
    // Display the name of the permission as a form item.
257
    $form['permission'][$permission] = array(
258
      '#type' => 'item',
259
      '#markup' => $info['title'],
260
    );
261
    // Save it to be displayed as one of the role checkboxes.
262
    $options[$permission] = '';
263
    // If we are in a situation where we can reset the field permissions
264
    // defaults, we do so by pre-checking the admin role's checkbox for this
265
    // permission.
266
    if ($reset_permissions_defaults) {
267
      if (($admin_rid = variable_get('user_admin_role', 0)) && isset($role_names[$admin_rid])) {
268
        $status[$admin_rid][] = $permission;
269
      }
270
      // For fields attached to users, we also pre-check the anonymous user's
271
      // checkbox for the permission to create the field, since that is the
272
      // most common way in which new user entities are created.
273
      if ($instance['entity_type'] == 'user' && $permission == 'create ' . $field['field_name']) {
274
        $status[DRUPAL_ANONYMOUS_RID][] = $permission;
275
      }
276
    }
277
    // Otherwise (e.g., for fields with custom permissions already saved),
278
    // determine whether the permission is already assigned and check each
279
    // checkbox accordingly.
280
    else {
281
      foreach ($role_names as $rid => $name) {
282
        if (isset($role_permissions[$rid][$permission])) {
283
          $status[$rid][] = $permission;
284
        }
285
      }
286
    }
287
  }
288

    
289
  // Build the checkboxes for each role.
290
  foreach ($role_names as $rid => $name) {
291
    $form['checkboxes'][$rid] = array(
292
      '#type' => 'checkboxes',
293
      '#options' => $options,
294
      '#default_value' => isset($status[$rid]) ? $status[$rid] : array(),
295
      '#attributes' => array('class' => array('rid-' . $rid)),
296
    );
297
    $form['role_names'][$rid] = array('#markup' => check_plain($name), '#tree' => TRUE);
298
  }
299

    
300
  // Attach the default permissions page JavaScript.
301
  $form['#attached']['js'][] = drupal_get_path('module', 'user') . '/user.permissions.js';
302

    
303
  // Attach our custom JavaScript for the permission matrix.
304
  $form['#attached']['js'][] = drupal_get_path('module', 'field_permissions') . '/field_permissions.admin.js';
305

    
306
  return $form;
307
}
308

    
309
/**
310
 * Pre-render function for the permissions matrix on the field settings form.
311
 */
312
function _field_permissions_field_settings_form_pre_render($form) {
313
  // Move the permissions matrix to its final location.
314
  $form['field']['field_permissions']['permissions']['matrix'] = $form['field_permissions']['permissions'];
315
  unset($form['field_permissions']);
316
  return $form;
317
}
318

    
319
/**
320
 * Form callback; Submit handler for the Field Settings form.
321
 */
322
function _field_permissions_field_settings_form_submit($form, &$form_state) {
323
  // Save the field permissions when appropriate to do so.
324
  $new_field_permissions_type = $form_state['values']['field']['field_permissions']['type'];
325
  if ($new_field_permissions_type == FIELD_PERMISSIONS_CUSTOM && isset($form_state['values']['field_permissions']['permissions'])) {
326
    $field_permissions = $form_state['values']['field_permissions']['permissions'];
327
    foreach ($field_permissions['role_names'] as $rid => $name) {
328
      user_role_change_permissions($rid, $field_permissions['checkboxes'][$rid]);
329
    }
330
  }
331

    
332
  // We must clear the page and block caches whenever the field permission type
333
  // setting has changed (because users may now be allowed to see a different
334
  // set of fields). For similar reasons, we must clear these caches whenever
335
  // custom field permissions are being used, since those may have changed too;
336
  // see user_admin_permissions_submit().
337
  if (!isset($form['#field']['field_permissions']['type']) || $new_field_permissions_type != $form['#field']['field_permissions']['type'] || $new_field_permissions_type == FIELD_PERMISSIONS_CUSTOM) {
338
    cache_clear_all();
339
  }
340
}
341

    
342
/**
343
 * Menu callback; Field permissions overview.
344
 */
345
function field_permissions_overview() {
346
  drupal_add_css(drupal_get_path('module', 'field_permissions') . '/field_permissions.admin.css');
347

    
348
  $headers = array(
349
    t('Field name'),
350
    t('Field type'),
351
    t('Entity type'),
352
    t('Used in'),
353
  );
354
  foreach (field_permissions_list() as $permission_type => $permission_info) {
355
    $headers[] = array('data' => $permission_info['label'], 'class' => 'field-permissions-header');
356
  }
357
  $destination = drupal_get_destination();
358

    
359
  // Load list of fields, field types and bundles in the system.
360
  $field_types = field_info_field_types();
361
  $bundles_info = field_info_bundles();
362

    
363
  // Retrieve the permissions for each role.
364
  $role_permissions = user_role_permissions(user_roles());
365

    
366
  // Based on field_ui_fields_list() in field_ui.admin.inc.
367
  $rows = array();
368
  foreach (field_info_fields() as $field_name => $field) {
369
    foreach ($field['bundles'] as $entity_type => $bundles) {
370
      foreach ($bundles as $bundle) {
371
        // Some fields might belong to bundles that are disabled (which are not
372
        // returned by field_info_bundles()).
373
        // @see https://www.drupal.org/node/1351506
374
        if (!isset($bundles_info[$entity_type][$bundle])) {
375
          continue;
376
        }
377
        // Each field will have a row in the table.
378
        if (module_exists('field_ui')) {
379
          $admin_path = _field_ui_bundle_admin_path($entity_type, $bundle);
380
          $field_admin_path = l($bundles_info[$entity_type][$bundle]['label'], $admin_path . '/fields/' . $field_name, array(
381
            'query' => $destination,
382
            'fragment' => 'edit-field-field-permissions-type',
383
          ));
384
        }
385
        else {
386
          $field_admin_path = $bundles_info[$entity_type][$bundle]['label'];
387
        }
388
        $rows[$field_name]['data'][0] = $field['locked'] ? t('@field_name (Locked)', array('@field_name' => $field_name)) : $field_name;
389
        $rows[$field_name]['data'][1] = $field_types[$field['type']]['label'];
390
        $rows[$field_name]['data'][2] = $entity_type;
391
        $rows[$field_name]['data'][3][] = $field_admin_path;
392
        $rows[$field_name]['class'] = $field['locked'] ? array('menu-disabled') : array('');
393

    
394
        // Append field permissions information to the report.
395
        $type = isset($field['field_permissions']['type']) ? $field['field_permissions']['type'] : FIELD_PERMISSIONS_PUBLIC;
396
        foreach (array_keys(field_permissions_list_field_permissions($field)) as $index => $permission) {
397
          // Put together the data value for the cell.
398
          $data = '';
399
          $full_colspan = FALSE;
400
          if ($type == FIELD_PERMISSIONS_PUBLIC) {
401
            $data = t('Public field (author and administrators can edit, everyone can view)');
402
            $full_colspan = TRUE;
403
          }
404
          elseif ($type == FIELD_PERMISSIONS_PRIVATE) {
405
            $data = t('Private field (only author and administrators can edit and view)');
406
            $full_colspan = TRUE;
407
          }
408
          else {
409
            // This is a field with custom permissions. Link the field to the
410
            // appropriate row of the permissions page, and theme it based on
411
            // whether all users have access.
412
            $all_users_have_access = isset($role_permissions[DRUPAL_ANONYMOUS_RID][$permission]) && isset($role_permissions[DRUPAL_AUTHENTICATED_RID][$permission]);
413
            $status_class = $all_users_have_access ? 'field-permissions-status-on' : 'field-permissions-status-off';
414
            $title = $all_users_have_access ? t('All users have this permission') : t('Not all users have this permission');
415
            $data = l(NULL, 'admin/people/permissions', array(
416
              'attributes' => array(
417
                'class' => array('field-permissions-status', $status_class),
418
                'title' => $title,
419
              ),
420
              'query' => $destination,
421
              'fragment' => drupal_html_class("edit $permission"),
422
            ));
423
          }
424

    
425
          // Construct the cell.
426
          $rows[$field_name]['data'][4 + $index] = array(
427
            'data' => $data,
428
            'class' => array('field-permissions-cell'),
429
          );
430
          if ($full_colspan) {
431
            $rows[$field_name]['data'][4 + $index]['colspan'] = 5;
432
            break;
433
          }
434
        }
435
      }
436
    }
437
  }
438
  foreach ($rows as $field_name => $cell) {
439
    $rows[$field_name]['data'][3] = implode(', ', $cell['data'][3]);
440
  }
441
  if (empty($rows)) {
442
    $output = t('No fields have been defined for any content type yet.');
443
  }
444
  else {
445
    // Sort rows by field name.
446
    ksort($rows);
447

    
448
    // Allow external modules alter the table headers and rows.
449
    foreach (module_implements('field_permissions_overview_alter') as $module) {
450
      $function = $module . '_field_permissions_overview_alter';
451
      $function($headers, $rows);
452
    }
453

    
454
    $output = theme('table', array('header' => $headers, 'rows' => $rows));
455
  }
456
  return $output;
457
}