field_permission_example.module

Same filename in other branches
  1. 7.x-1.x field_permission_example/field_permission_example.module
  2. 4.0.x modules/field_permission_example/field_permission_example.module

An example field using the Field Types API.

File

modules/field_permission_example/field_permission_example.module

View source
<?php


/**
 * @file
 * An example field using the Field Types API.
 */

/**
 * @defgroup field_permission_example Example: Field Permissions
 * @ingroup examples
 * @{
 * Example using permissions on a Field API field.
 *
 * This example is a relatively simple text field you can attach to any
 * fieldable entity.
 *
 * In this module we demonstrate how to limit access to a field. Drupal's Field
 * API gives you two operations to permit or restrict: view and edit. So you can
 * then decide who gets to see fields, who can edit them, and who can manage
 * them.
 *
 * Our field is called field_permission_example_fieldnote. It has a simple
 * default widget of a text area, and a default formatter that applies a CSS
 * style to make it look like a sticky note.
 *
 * In addition to demonstrating how to set up permissions-based access to a
 * field, this module also demonstrates the absolute minimum required to
 * implement a field, since it doesn't have any field settings.
 *
 * If you wish to use this code as skeleton code for a field without
 * permissions, you can simply omit field_permission_example.permissions.yml and
 * remove field_permission_example_entity_field_access().  In addition, our call
 * to field_permission_example_theme() is used to set up our description page
 * for the example, which you don't  need for a working field.
 *
 * How does it work?
 *
 * You can install this module and go to path /examples/field_permission_example
 * for an introduction on how to use this field.
 *
 * OK, how does the code work?
 *
 * As with any permission system, we create a MODULE_NAME.permissions.yml file
 * in order to define a few permissions. In our case, users will want to either
 * view or edit fieldnote fields. And, similar to the way node permissions work,
 * we'll also include a context of either their own content or any content. So
 * that gives us 4 permissions which administrators can assign to various roles.
 * See field_permission_example.permissions.yml for the list.
 *
 * With our permissions defined in the YAML file, we can now handle requests for
 * access. Those come in through hook_entity_field_access(), which we've
 * implemented as field_permission_example_entity_field_access(). This function
 * determines whether the user has the ability to view or edit the field in
 * question by calling $account->hasPermission(). We also give special edit
 * access to users with the 'bypass node access', 'administer content types'
 * permissions, defined by the node module, and the 'administer the fieldnote
 * field' we define for the module.
 *
 * One tricky part is that our field won't always be attached to nodes. It could
 * be attached to any type of entity. Fortunately, most content entities
 * implement EntityOwnerInterface, which gives us a way to check this. An
 * exception to this is the User entity; here, we just check to see that the
 * account name matches that of $account.  We can get the entity itself by
 * calling $items->getEntity(), since these "know" what entity they belong to.
 *
 * In a real application, we'd have use-case specific permissions which might be
 * more complex than these. Or perhaps simpler.
 *
 * You can see a more complex field implementation in field_example.module.
 *
 * @see field_example
 * @see field_example.module
 * @see field_types
 * @see field
 */
// Use statements to support hook_entity_field_access.
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Access\AccessResult;
// Interfaces used by entities to declare "ownership".
use Drupal\user\EntityOwnerInterface;
use Drupal\user\UserInterface;
// Use statements for hook_entity_test_access.
use Drupal\Core\Entity\EntityInterface;

/**
 * Implements hook_entity_field_access().
 *
 * We want to make sure that fields aren't being seen or edited
 * by those who shouldn't.
 */
function field_permission_example_entity_field_access($operation, FieldDefinitionInterface $field_definition, AccountInterface $account, FieldItemListInterface $items = NULL) {
    $messenger = \Drupal::messenger();
    // Find out what field we're looking at.  If it isn't
    // our sticky note widget, tell Drupal we don't care about its access.
    if ($field_definition->getType() != 'field_permission_example_fieldnote') {
        return AccessResult::neutral();
    }
    // First we'll check if the user has the 'superuser'
    // permissions that node provides. This way administrators
    // will be able to administer the content types.
    if ($account->hasPermission('bypass node access')) {
        $messenger->addMessage(t('User can bypass node access.'));
        return AccessResult::allowed();
    }
    if ($account->hasPermission('administer content types', $account)) {
        $messenger->addMessage(t('User can administer content types.'));
        return AccessResult::allowed();
    }
    if ($account->hasPermission('administer the fieldnote field', $account)) {
        $messenger->addMessage(t('User can administer this field.'));
        return AccessResult::allowed();
    }
    // For anyone else, it depends on the desired operation.
    if ($operation == 'view' and $account->hasPermission('view any fieldnote')) {
        $messenger->addMessage(t('User can view any field note.'));
        return AccessResult::allowed();
    }
    if ($operation == 'edit' and $account->hasPermission('edit any fieldnote')) {
        $messenger->addMessage(t('User can edit any field note.'));
        return AccessResult::allowed();
    }
    // At this point, we need to know if the user "owns" the entity we're attached
    // to. If it's a user, we'll use the account name to test. Otherwise rely on
    // the entity implementing the EntityOwnerInterface. Anything else can't be
    // owned, and we'll refuse access.
    if ($items) {
        $entity = $items->getEntity();
        if ($entity instanceof EntityOwnerInterface and $entity->getOwner()
            ->getAccountName() == $account->getAccountName() or $entity instanceof UserInterface and $entity->name->value == $account->getAccountName()) {
            if ($operation == 'view' and $account->hasPermission('view own fieldnote')) {
                $messenger->addMessage(t('User can view their own field note.'));
                return AccessResult::allowed();
            }
            if ($operation == 'edit' and $account->hasPermission('edit own fieldnote')) {
                $messenger->addMessage(t('User can edit their own field note.'));
                return AccessResult::allowed();
            }
        }
    }
    // Anything else on this field is forbidden.
    return AccessResult::forbidden();
}

/**
 * Implements hook_ENTITY_TYPE_access().
 *
 * Note: this routine is added so we can more easily test our access code. Core
 * defines an entity_test entity that is used for testing fields in core. We add
 * this routine to make the entity_test entity editable by our tests.
 */
function field_permission_example_entity_test_access(EntityInterface $entity, $operation, AccountInterface $account, $langcode) {
    if ($operation == 'edit') {
        $perms = [
            'administer the fieldnote field',
            'edit any fieldnote',
            'edit own fieldnote',
        ];
        foreach ($perms as $perm) {
            if ($account->hasPermission($perm)) {
                return AccessResult::allowed();
            }
        }
    }
    return AccessResult::neutral();
}

/**
 * @} End of "defgroup field_permission_example".
 */

/**
 * Implements hook_theme().
 *
 * Since we have a lot to explain, we're going to use Twig to do it.
 */
function field_permission_example_theme() {
    return [
        'field_permission_description' => [
            'template' => 'description',
            'variables' => [
                'admin_link' => NULL,
            ],
        ],
    ];
}

Functions

Title Deprecated Summary
field_permission_example_entity_field_access Implements hook_entity_field_access().
field_permission_example_entity_test_access Implements hook_ENTITY_TYPE_access().
field_permission_example_theme Implements hook_theme().