class FileAccessControlHandler
Same name in other branches
- 9 core/modules/file/src/FileAccessControlHandler.php \Drupal\file\FileAccessControlHandler
- 8.9.x core/modules/file/src/FileAccessControlHandler.php \Drupal\file\FileAccessControlHandler
- 10 core/modules/file/src/FileAccessControlHandler.php \Drupal\file\FileAccessControlHandler
Provides a File access control handler.
Hierarchy
- class \Drupal\Core\Entity\EntityHandlerBase uses \Drupal\Core\StringTranslation\StringTranslationTrait, \Drupal\Core\DependencyInjection\DependencySerializationTrait
- class \Drupal\Core\Entity\EntityAccessControlHandler extends \Drupal\Core\Entity\EntityHandlerBase implements \Drupal\Core\Entity\EntityAccessControlHandlerInterface
- class \Drupal\file\FileAccessControlHandler extends \Drupal\Core\Entity\EntityAccessControlHandler
- class \Drupal\Core\Entity\EntityAccessControlHandler extends \Drupal\Core\Entity\EntityHandlerBase implements \Drupal\Core\Entity\EntityAccessControlHandlerInterface
Expanded class hierarchy of FileAccessControlHandler
1 file declares its use of FileAccessControlHandler
- FileTestAccessControlHandler.php in core/
modules/ file/ tests/ file_test/ src/ FileTestAccessControlHandler.php
File
-
core/
modules/ file/ src/ FileAccessControlHandler.php, line 16
Namespace
Drupal\fileView source
class FileAccessControlHandler extends EntityAccessControlHandler {
/**
* {@inheritdoc}
*/
protected function checkAccess(EntityInterface $entity, $operation, AccountInterface $account) {
/** @var \Drupal\file\FileInterface $entity */
if ($operation == 'download' || $operation == 'view') {
if (\Drupal::service('stream_wrapper_manager')->getScheme($entity->getFileUri()) === 'public') {
if ($operation === 'download') {
return AccessResult::allowed();
}
else {
return AccessResult::allowedIfHasPermission($account, 'access content');
}
}
elseif ($references = $this->getFileReferences($entity)) {
foreach ($references as $field_name => $entity_map) {
foreach ($entity_map as $referencing_entities) {
/** @var \Drupal\Core\Entity\EntityInterface $referencing_entity */
foreach ($referencing_entities as $referencing_entity) {
$entity_and_field_access = $referencing_entity->access('view', $account, TRUE)
->andIf($referencing_entity->{$field_name}
->access('view', $account, TRUE));
if ($entity_and_field_access->isAllowed()) {
return $entity_and_field_access;
}
}
}
}
}
elseif ($entity->getOwnerId() == $account->id()) {
// This case handles new nodes, or detached files. The user who uploaded
// the file can access it even if it's not yet used.
if ($account->isAnonymous()) {
// For anonymous users, only the browser session that uploaded the
// file is positively allowed access to it. See file_save_upload().
// @todo Implement \Drupal\Core\Entity\EntityHandlerInterface so that
// services can be more properly injected.
$allowed_fids = \Drupal::service('session')->get('anonymous_allowed_file_ids', []);
if (!empty($allowed_fids[$entity->id()])) {
return AccessResult::allowed()->addCacheContexts([
'session',
'user',
]);
}
}
else {
return AccessResult::allowed()->addCacheContexts([
'user',
]);
}
}
}
elseif ($operation == 'update') {
$account = $this->prepareUser($account);
$file_uid = $entity->get('uid')
->getValue();
// Only the file owner can update the file entity.
if (isset($file_uid[0]['target_id']) && $account->id() == $file_uid[0]['target_id']) {
return AccessResult::allowed();
}
return AccessResult::forbidden('Only the file owner can update the file entity.');
}
elseif ($operation == 'delete') {
$access = AccessResult::allowedIfHasPermission($account, 'delete any file');
if (!$access->isAllowed() && $account->hasPermission('delete own files')) {
$access = $access->orIf(AccessResult::allowedIf($account->id() == $entity->getOwnerId()))
->cachePerUser()
->addCacheableDependency($entity);
}
return $access;
}
// No opinion.
return AccessResult::neutral();
}
/**
* Wrapper for file_get_file_references().
*
* @param \Drupal\file\FileInterface $file
* The file object for which to get references.
*
* @return array
* A multidimensional array. The keys are field_name, entity_type,
* entity_id and the value is an entity referencing this file.
*
* @see file_get_file_references()
*/
protected function getFileReferences(FileInterface $file) {
return file_get_file_references($file, NULL, EntityStorageInterface::FIELD_LOAD_REVISION, NULL);
}
/**
* {@inheritdoc}
*/
protected function checkFieldAccess($operation, FieldDefinitionInterface $field_definition, AccountInterface $account, ?FieldItemListInterface $items = NULL) {
// Deny access to fields that should only be set on file creation, and
// "status" which should only be changed based on a file's usage.
$create_only_fields = [
'uri',
'filemime',
'filesize',
];
// The operation is 'edit' when the entity is being created or updated.
// Determine if the entity is being updated by checking if it is new.
$field_name = $field_definition->getName();
if ($operation === 'edit' && $items && ($entity = $items->getEntity()) && !$entity->isNew() && in_array($field_name, $create_only_fields, TRUE)) {
return AccessResult::forbidden();
}
// Regardless of whether the entity exists access should be denied to the
// status field as this is managed via other APIs, for example:
// - \Drupal\file\FileUsage\FileUsageBase::add()
// - \Drupal\file\Plugin\EntityReferenceSelection\FileSelection::createNewEntity()
if ($operation === 'edit' && $field_name === 'status') {
return AccessResult::forbidden();
}
return parent::checkFieldAccess($operation, $field_definition, $account, $items);
}
/**
* {@inheritdoc}
*/
protected function checkCreateAccess(AccountInterface $account, array $context, $entity_bundle = NULL) {
// The file entity has no "create" permission because by default Drupal core
// does not allow creating file entities independently. It allows you to
// create file entities that are referenced from another entity
// (e.g. an image for an article). A contributed module is free to alter
// this to allow file entities to be created directly.
return AccessResult::neutral();
}
}
Members
Title Sort descending | Modifiers | Object type | Summary | Overriden Title | Overrides |
---|---|---|---|---|---|
DependencySerializationTrait::$_entityStorages | protected | property | |||
DependencySerializationTrait::$_serviceIds | protected | property | |||
DependencySerializationTrait::__sleep | public | function | 1 | ||
DependencySerializationTrait::__wakeup | public | function | 2 | ||
EntityAccessControlHandler::$accessCache | protected | property | Stores calculated access check results. | ||
EntityAccessControlHandler::$entityType | protected | property | Information about the entity type. | ||
EntityAccessControlHandler::$entityTypeId | protected | property | The entity type ID of the access control handler instance. | ||
EntityAccessControlHandler::$viewLabelOperation | protected | property | Allows to grant access to just the labels. | 7 | |
EntityAccessControlHandler::access | public | function | Overrides EntityAccessControlHandlerInterface::access | 1 | |
EntityAccessControlHandler::createAccess | public | function | Overrides EntityAccessControlHandlerInterface::createAccess | 1 | |
EntityAccessControlHandler::fieldAccess | public | function | Overrides EntityAccessControlHandlerInterface::fieldAccess | ||
EntityAccessControlHandler::getCache | protected | function | Tries to retrieve a previously cached access value from the static cache. | ||
EntityAccessControlHandler::prepareUser | protected | function | Loads the current account object, if it does not exist yet. | ||
EntityAccessControlHandler::processAccessHookResults | protected | function | Determines entity access. | ||
EntityAccessControlHandler::resetCache | public | function | Overrides EntityAccessControlHandlerInterface::resetCache | ||
EntityAccessControlHandler::setCache | protected | function | Statically caches whether the given user has access. | ||
EntityAccessControlHandler::__construct | public | function | Constructs an access control handler instance. | 8 | |
EntityHandlerBase::$moduleHandler | protected | property | The module handler to invoke hooks on. | 5 | |
EntityHandlerBase::moduleHandler | protected | function | Gets the module handler. | 5 | |
EntityHandlerBase::setModuleHandler | public | function | Sets the module handler for this handler. | ||
FileAccessControlHandler::checkAccess | protected | function | Overrides EntityAccessControlHandler::checkAccess | 1 | |
FileAccessControlHandler::checkCreateAccess | protected | function | Overrides EntityAccessControlHandler::checkCreateAccess | ||
FileAccessControlHandler::checkFieldAccess | protected | function | Overrides EntityAccessControlHandler::checkFieldAccess | ||
FileAccessControlHandler::getFileReferences | protected | function | Wrapper for file_get_file_references(). | ||
StringTranslationTrait::$stringTranslation | protected | property | The string translation service. | 3 | |
StringTranslationTrait::formatPlural | protected | function | Formats a string containing a count of items. | ||
StringTranslationTrait::getNumberOfPlurals | protected | function | Returns the number of plurals supported by a given language. | ||
StringTranslationTrait::getStringTranslation | protected | function | Gets the string translation service. | ||
StringTranslationTrait::setStringTranslation | public | function | Sets the string translation service to use. | 2 | |
StringTranslationTrait::t | protected | function | Translates a string to the current language or to a given language. |
Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.