field_permission_example.module 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. <?php
  2. /**
  3. * @file
  4. * An example field using the Field Types API.
  5. */
  6. /**
  7. * @defgroup field_permission_example Example: Field Permissions
  8. * @ingroup examples
  9. * @{
  10. * Example using permissions on a Field API field.
  11. *
  12. * This example is a relatively simple text field you can attach to any
  13. * fieldable entity.
  14. *
  15. * In this module we demonstrate how to limit access to a field. Drupal's Field
  16. * API gives you two operations to permit or restrict: view and edit. So you can
  17. * then decide who gets to see fields, who can edit them, and who can manage
  18. * them.
  19. *
  20. * Our field is called field_permission_example_fieldnote. It has a simple
  21. * default widget of a text area, and a default formatter that applies a CSS
  22. * style to make it look like a sticky note.
  23. *
  24. * In addition to demonstrating how to set up permissions-based access to a
  25. * field, this module also demonstrates the absolute minimum required to
  26. * implement a field, since it doesn't have any field settings.
  27. *
  28. * If you wish to use this code as skeleton code for a field without
  29. * permissions, you can simply omit field_permission_example.permissions.yml and
  30. * remove field_permission_example_entity_field_access(). In addition, our call
  31. * to field_permission_example_theme() is used to set up our description page
  32. * for the example, which you don't need for a working field.
  33. *
  34. * How does it work?
  35. *
  36. * You can install this module and go to path /examples/field_permission_example
  37. * for an introduction on how to use this field.
  38. *
  39. * OK, how does the code work?
  40. *
  41. * As with any permission system, we create a MODULE_NAME.permissions.yml file
  42. * in order to define a few permissions. In our case, users will want to either
  43. * view or edit fieldnote fields. And, similar to the way node permissions work,
  44. * we'll also include a context of either their own content or any content. So
  45. * that gives us 4 permissions which administrators can assign to various roles.
  46. * See field_permission_example.permissions.yml for the list.
  47. *
  48. * With our permissions defined in the YAML file, we can now handle requests for
  49. * access. Those come in through hook_entity_field_access(), which we've
  50. * implemented as field_permission_example_entity_field_access(). This function
  51. * determines whether the user has the ability to view or edit the field in
  52. * question by calling $account->hasPermission(). We also give special edit
  53. * access to users with the 'bypass node access', 'administer content types'
  54. * permissions, defined by the node module, and the 'administer the fieldnote
  55. * field' we define for the module.
  56. *
  57. * One tricky part is that our field won't always be attached to nodes. It could
  58. * be attached to any type of entity. Fortunately, most content entities
  59. * implement EntityOwnerInterface, which gives us a way to check this. An
  60. * exception to this is the User entity; here, we just check to see that the
  61. * account name matches that of $account. We can get the entity itself by
  62. * calling $items->getEntity(), since these "know" what entity they belong to.
  63. *
  64. * In a real application, we'd have use-case specific permissions which might be
  65. * more complex than these. Or perhaps simpler.
  66. *
  67. * You can see a more complex field implementation in field_example.module.
  68. *
  69. * @see field_example
  70. * @see field_example.module
  71. * @see field_types
  72. * @see field
  73. */
  74. // Use statements to support hook_entity_field_access.
  75. use Drupal\Core\Field\FieldDefinitionInterface;
  76. use Drupal\Core\Session\AccountInterface;
  77. use Drupal\Core\Field\FieldItemListInterface;
  78. use Drupal\Core\Access\AccessResult;
  79. // Interfaces used by entities to declare "ownership".
  80. use Drupal\user\EntityOwnerInterface;
  81. use Drupal\user\UserInterface;
  82. // Use statements for hook_entity_test_access.
  83. use Drupal\Core\Entity\EntityInterface;
  84. /**
  85. * Implements hook_entity_field_access().
  86. *
  87. * We want to make sure that fields aren't being seen or edited
  88. * by those who shouldn't.
  89. */
  90. function field_permission_example_entity_field_access($operation, FieldDefinitionInterface $field_definition, AccountInterface $account, FieldItemListInterface $items = NULL) {
  91. // Find out what field we're looking at. If it isn't
  92. // our sticky note widget, tell Drupal we don't care about its access.
  93. if ($field_definition->getType() != 'field_permission_example_fieldnote') {
  94. return AccessResult::neutral();
  95. }
  96. // First we'll check if the user has the 'superuser'
  97. // permissions that node provides. This way administrators
  98. // will be able to administer the content types.
  99. if ($account->hasPermission('bypass node access')) {
  100. drupal_set_message(t('User can bypass node access.'));
  101. return AccessResult::allowed();
  102. }
  103. if ($account->hasPermission('administer content types', $account)) {
  104. drupal_set_message(t('User can administer content types.'));
  105. return AccessResult::allowed();
  106. }
  107. if ($account->hasPermission('administer the fieldnote field', $account)) {
  108. drupal_set_message(t('User can administer this field.'));
  109. return AccessResult::allowed();
  110. }
  111. // For anyone else, it depends on the desired operation.
  112. if ($operation == 'view' and $account->hasPermission('view any fieldnote')) {
  113. drupal_set_message(t('User can view any field note.'));
  114. return AccessResult::allowed();
  115. }
  116. if ($operation == 'edit' and $account->hasPermission('edit any fieldnote')) {
  117. drupal_set_message(t('User can edit any field note.'));
  118. return AccessResult::allowed();
  119. }
  120. // At this point, we need to know if the user "owns" the entity we're attached
  121. // to. If it's a user, we'll use the account name to test. Otherwise rely on
  122. // the entity implementing the EntityOwnerInterface. Anything else can't be
  123. // owned, and we'll refuse access.
  124. if ($items) {
  125. $entity = $items->getEntity();
  126. if ((($entity instanceof EntityOwnerInterface) and
  127. $entity->getOwner()->getAccountName() == $account->getAccountName()) or
  128. (($entity instanceof UserInterface) and
  129. $entity->name->value == $account->getAccountName())
  130. ) {
  131. if ($operation == 'view' and $account->hasPermission('view own fieldnote')) {
  132. drupal_set_message(t('User can view their own field note.'));
  133. return AccessResult::allowed();
  134. }
  135. if ($operation == 'edit' and $account->hasPermission('edit own fieldnote')) {
  136. drupal_set_message(t('User can edit their own field note.'));
  137. return AccessResult::allowed();
  138. }
  139. }
  140. }
  141. // Anything else on this field is forbidden.
  142. return AccessResult::forbidden();
  143. }
  144. /**
  145. * Implements hook_ENTITY_TYPE_access().
  146. *
  147. * Note: this routine is added so we can more easily test our access code. Core
  148. * defines an entity_test entity that is used for testing fields in core. We add
  149. * this routine to make the entity_test entity editable by our tests.
  150. */
  151. function field_permission_example_entity_test_access(EntityInterface $entity, $operation, AccountInterface $account, $langcode) {
  152. if ($operation == 'edit') {
  153. $perms = [
  154. 'administer the fieldnote field',
  155. 'edit any fieldnote',
  156. 'edit own fieldnote',
  157. ];
  158. foreach ($perms as $perm) {
  159. if ($account->hasPermission($perm)) {
  160. return AccessResult::allowed();
  161. }
  162. }
  163. }
  164. return AccessResult::neutral();
  165. }
  166. /**
  167. * @} End of "defgroup field_permission_example".
  168. */
  169. /**
  170. * Implements hook_theme().
  171. *
  172. * Since we have a lot to explain, we're going to use Twig to do it.
  173. */
  174. function field_permission_example_theme() {
  175. return [
  176. 'field_permission_description' => [
  177. 'template' => 'description',
  178. 'variables' => [
  179. 'admin_link' => NULL,
  180. ],
  181. ],
  182. ];
  183. }