UncacheableEntityAccessControlHandler.php 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. <?php
  2. namespace Drupal\entity;
  3. use Drupal\Core\Access\AccessResult;
  4. use Drupal\Core\Entity\EntityAccessControlHandler as CoreEntityAccessControlHandler;
  5. use Drupal\Core\Entity\EntityInterface;
  6. use Drupal\Core\Entity\EntityPublishedInterface;
  7. use Drupal\Core\Entity\EntityTypeInterface;
  8. use Drupal\Core\Session\AccountInterface;
  9. use Drupal\user\EntityOwnerInterface;
  10. /**
  11. * Controls access based on the uncacheable entity permissions.
  12. *
  13. * @see \Drupal\entity\UncacheableEntityPermissionProvider
  14. *
  15. * Note: this access control handler will cause pages to be cached per user.
  16. */
  17. class UncacheableEntityAccessControlHandler extends CoreEntityAccessControlHandler {
  18. /**
  19. * {@inheritdoc}
  20. */
  21. public function __construct(EntityTypeInterface $entity_type) {
  22. parent::__construct($entity_type);
  23. if (!$entity_type->hasHandlerClass('permission_provider') || !is_a($entity_type->getHandlerClass('permission_provider'), UncacheableEntityPermissionProvider::class, TRUE)) {
  24. throw new \Exception("This entity access control handler requires the entity permissions provider: {EntityPermissionProvider::class}");
  25. }
  26. }
  27. /**
  28. * {@inheritdoc}
  29. */
  30. protected function checkAccess(EntityInterface $entity, $operation, AccountInterface $account) {
  31. $account = $this->prepareUser($account);
  32. /** @var \Drupal\Core\Access\AccessResult $result */
  33. $result = parent::checkAccess($entity, $operation, $account);
  34. if ($result->isNeutral()) {
  35. if ($entity instanceof EntityOwnerInterface) {
  36. $result = $this->checkEntityOwnerPermissions($entity, $operation, $account);
  37. }
  38. else {
  39. $result = $this->checkEntityPermissions($entity, $operation, $account);
  40. }
  41. }
  42. // Ensure that access is evaluated again when the entity changes.
  43. return $result->addCacheableDependency($entity);
  44. }
  45. /**
  46. * Checks the entity operation and bundle permissions.
  47. *
  48. * @param \Drupal\Core\Entity\EntityInterface $entity
  49. * The entity for which to check access.
  50. * @param string $operation
  51. * The entity operation. Usually one of 'view', 'view label', 'update' or
  52. * 'delete'.
  53. * @param \Drupal\Core\Session\AccountInterface $account
  54. * The user for which to check access.
  55. *
  56. * @return \Drupal\Core\Access\AccessResultInterface
  57. * The access result.
  58. */
  59. protected function checkEntityPermissions(EntityInterface $entity, $operation, AccountInterface $account) {
  60. return AccessResult::allowedIfHasPermissions($account, [
  61. "$operation {$entity->getEntityTypeId()}",
  62. "$operation {$entity->bundle()} {$entity->getEntityTypeId()}",
  63. ], 'OR');
  64. }
  65. /**
  66. * Checks the entity operation and bundle permissions, with owners.
  67. *
  68. * @param \Drupal\Core\Entity\EntityInterface $entity
  69. * The entity for which to check access.
  70. * @param string $operation
  71. * The entity operation. Usually one of 'view', 'view label', 'update' or
  72. * 'delete'.
  73. * @param \Drupal\Core\Session\AccountInterface $account
  74. * The user for which to check access.
  75. *
  76. * @return \Drupal\Core\Access\AccessResultInterface
  77. * The access result.
  78. */
  79. protected function checkEntityOwnerPermissions(EntityInterface $entity, $operation, AccountInterface $account) {
  80. /** @var \Drupal\Core\Entity\EntityInterface|\Drupal\user\EntityOwnerInterface $entity */
  81. if (($account->id() == $entity->getOwnerId())) {
  82. if ($operation === 'view' && $entity instanceof EntityPublishedInterface && !$entity->isPublished()) {
  83. $permissions = [
  84. "view own unpublished {$entity->getEntityTypeId()}",
  85. ];
  86. }
  87. else {
  88. $permissions = [
  89. "$operation own {$entity->getEntityTypeId()}",
  90. "$operation any {$entity->getEntityTypeId()}",
  91. "$operation own {$entity->bundle()} {$entity->getEntityTypeId()}",
  92. "$operation any {$entity->bundle()} {$entity->getEntityTypeId()}",
  93. ];
  94. }
  95. $result = AccessResult::allowedIfHasPermissions($account, $permissions, 'OR');
  96. }
  97. else {
  98. $result = AccessResult::allowedIfHasPermissions($account, [
  99. "$operation any {$entity->getEntityTypeId()}",
  100. "$operation any {$entity->bundle()} {$entity->getEntityTypeId()}",
  101. ], 'OR');
  102. }
  103. return $result->cachePerUser();
  104. }
  105. /**
  106. * {@inheritdoc}
  107. */
  108. protected function checkCreateAccess(AccountInterface $account, array $context, $entity_bundle = NULL) {
  109. $result = parent::checkCreateAccess($account, $context, $entity_bundle);
  110. if ($result->isNeutral()) {
  111. $permissions = [
  112. 'administer ' . $this->entityTypeId,
  113. 'create ' . $this->entityTypeId,
  114. ];
  115. if ($entity_bundle) {
  116. $permissions[] = 'create ' . $entity_bundle . ' ' . $this->entityTypeId;
  117. }
  118. $result = AccessResult::allowedIfHasPermissions($account, $permissions, 'OR');
  119. }
  120. return $result;
  121. }
  122. }