Commit acedc33b authored by bojanz's avatar bojanz

Issue #2817077 by bojanz: Replace the permission code with the Entity API version

parent ca260b92
'access commerce administration pages':
title: 'Use the commerce administration pages'
permission_callbacks:
- \Drupal\commerce\EntityPermissions::buildPermissions
......@@ -29,8 +29,8 @@ use Drupal\profile\Entity\ProfileInterface;
* handlers = {
* "event" = "Drupal\commerce_order\Event\OrderEvent",
* "storage" = "Drupal\commerce_order\OrderStorage",
* "access" = "\Drupal\commerce\EntityAccessControlHandler",
* "permission_provider" = "\Drupal\commerce\EntityPermissionProvider",
* "access" = "Drupal\commerce\EntityAccessControlHandler",
* "permission_provider" = "Drupal\commerce\EntityPermissionProvider",
* "list_builder" = "Drupal\commerce_order\OrderListBuilder",
* "views_data" = "Drupal\views\EntityViewsData",
* "form" = {
......
......@@ -25,8 +25,8 @@ use Drupal\Core\Field\BaseFieldDefinition;
* handlers = {
* "event" = "Drupal\commerce_product\Event\ProductEvent",
* "storage" = "Drupal\commerce\CommerceContentEntityStorage",
* "access" = "\Drupal\commerce\EntityAccessControlHandler",
* "permission_provider" = "\Drupal\commerce\EntityPermissionProvider",
* "access" = "Drupal\commerce\EntityAccessControlHandler",
* "permission_provider" = "Drupal\commerce\EntityPermissionProvider",
* "view_builder" = "Drupal\commerce_product\ProductViewBuilder",
* "list_builder" = "Drupal\commerce_product\ProductListBuilder",
* "views_data" = "Drupal\views\EntityViewsData",
......
......@@ -18,8 +18,8 @@ use Drupal\Core\Entity\EntityStorageInterface;
* plural = "@count product attributes",
* ),
* handlers = {
* "access" = "\Drupal\commerce\EntityAccessControlHandler",
* "permission_provider" = "\Drupal\commerce\EntityPermissionProvider",
* "access" = "Drupal\commerce\EntityAccessControlHandler",
* "permission_provider" = "Drupal\commerce\EntityPermissionProvider",
* "list_builder" = "Drupal\commerce_product\ProductAttributeListBuilder",
* "form" = {
* "add" = "Drupal\commerce_product\Form\ProductAttributeForm",
......
......@@ -25,8 +25,8 @@ use Drupal\Core\Plugin\Context\ContextDefinition;
* handlers = {
* "event" = "Drupal\commerce_promotion\Event\PromotionEvent",
* "storage" = "Drupal\commerce_promotion\PromotionStorage",
* "access" = "\Drupal\commerce\EntityAccessControlHandler",
* "permission_provider" = "\Drupal\commerce\EntityPermissionProvider",
* "access" = "Drupal\commerce\EntityAccessControlHandler",
* "permission_provider" = "Drupal\commerce\EntityPermissionProvider",
* "view_builder" = "Drupal\Core\Entity\EntityViewBuilder",
* "list_builder" = "Drupal\commerce_promotion\PromotionListBuilder",
* "views_data" = "Drupal\views\EntityViewsData",
......
......@@ -26,8 +26,8 @@ use Drupal\Core\Field\BaseFieldDefinition;
* handlers = {
* "event" = "Drupal\commerce_store\Event\StoreEvent",
* "storage" = "Drupal\commerce_store\StoreStorage",
* "access" = "\Drupal\commerce\EntityAccessControlHandler",
* "permission_provider" = "\Drupal\commerce\EntityPermissionProvider",
* "access" = "Drupal\commerce\EntityAccessControlHandler",
* "permission_provider" = "Drupal\commerce\EntityPermissionProvider",
* "view_builder" = "Drupal\Core\Entity\EntityViewBuilder",
* "list_builder" = "Drupal\commerce_store\StoreListBuilder",
* "views_data" = "Drupal\views\EntityViewsData",
......
......@@ -2,108 +2,11 @@
namespace Drupal\commerce;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Entity\EntityAccessControlHandler as CoreEntityAccessControlHandler;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\user\EntityOwnerInterface;
use Drupal\entity\EntityAccessControlHandler as BaseEntityAccessControlHandler;
/**
* Provides per-bundle entity CRUD permissions.
* Controls access based on the Commerce entity permissions.
*
* @see \Drupal\commerce\EntityPermissionProvider
*/
class EntityAccessControlHandler extends CoreEntityAccessControlHandler {
/**
* {@inheritdoc}
*/
protected function checkAccess(EntityInterface $entity, $operation, AccountInterface $account) {
$account = $this->prepareUser($account);
/** @var \Drupal\Core\Access\AccessResult $result */
$result = parent::checkAccess($entity, $operation, $account);
if ($result->isNeutral()) {
if ($entity instanceof EntityOwnerInterface) {
$result = $this->checkEntityOwnerPermissions($entity, $operation, $account);
}
else {
$result = $this->checkEntityPermissions($entity, $operation, $account);
}
}
// Ensure that access is evaluated again when the entity changes.
return $result->addCacheableDependency($entity);
}
/**
* Checks the entity operation and bundle permissions.
*
* @param \Drupal\Core\Entity\EntityInterface $entity
* The entity for which to check access.
* @param string $operation
* The entity operation. Usually one of 'view', 'view label', 'update' or
* 'delete'.
* @param \Drupal\Core\Session\AccountInterface $account
* The user for which to check access.
*
* @return \Drupal\Core\Access\AccessResultInterface
* The access result.
*/
protected function checkEntityPermissions(EntityInterface $entity, $operation, AccountInterface $account) {
return AccessResult::allowedIfHasPermissions($account, [
"$operation {$entity->getEntityTypeId()}",
"$operation {$entity->bundle()} {$entity->getEntityTypeId()}",
], 'OR');
}
/**
* Checks the entity operation and bundle permissions, with owners.
*
* @param \Drupal\Core\Entity\EntityInterface $entity
* The entity for which to check access.
* @param string $operation
* The entity operation. Usually one of 'view', 'view label', 'update' or
* 'delete'.
* @param \Drupal\Core\Session\AccountInterface $account
* The user for which to check access.
*
* @return \Drupal\Core\Access\AccessResultInterface
* The access result.
*/
protected function checkEntityOwnerPermissions(EntityInterface $entity, $operation, AccountInterface $account) {
/** @var \Drupal\Core\Entity\EntityInterface|\Drupal\user\EntityOwnerInterface $entity */
if (($account->id() == $entity->getOwnerId())) {
$result = AccessResult::allowedIfHasPermissions($account, [
"$operation own {$entity->getEntityTypeId()}",
"$operation any {$entity->getEntityTypeId()}",
"$operation own {$entity->bundle()} {$entity->getEntityTypeId()}",
"$operation any {$entity->bundle()} {$entity->getEntityTypeId()}",
], 'OR');
}
else {
$result = AccessResult::allowedIfHasPermissions($account, [
"$operation any {$entity->getEntityTypeId()}",
"$operation any {$entity->bundle()} {$entity->getEntityTypeId()}",
], 'OR');
}
return $result->cachePerUser();
}
/**
* {@inheritdoc}
*/
protected function checkCreateAccess(AccountInterface $account, array $context, $entity_bundle = NULL) {
$result = parent::checkCreateAccess($account, $context, $entity_bundle);
if ($result->isNeutral()) {
$result = AccessResult::allowedIfHasPermissions($account, [
'administer ' . $this->entityTypeId,
'create ' . $entity_bundle . ' ' . $this->entityTypeId,
'create any ' . $entity_bundle . ' ' . $this->entityTypeId,
'create own ' . $entity_bundle . ' ' . $this->entityTypeId,
], 'OR');
}
return $result;
}
}
class EntityAccessControlHandler extends BaseEntityAccessControlHandler {}
......@@ -2,255 +2,11 @@
namespace Drupal\commerce;
use Drupal\Core\Entity\ContentEntityTypeInterface;
use Drupal\Core\Entity\EntityHandlerInterface;
use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\user\EntityOwnerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\entity\EntityPermissionProvider as BaseEntityPermissionProvider;
/**
* Provides permissions for entities.
* Provides Commerce entity permissions.
*
* @see \Drupal\entity\EntityPermissionProvider
*/
class EntityPermissionProvider implements EntityPermissionProviderInterface, EntityHandlerInterface {
use StringTranslationTrait;
/**
* The entity type bundle info.
*
* @var \Drupal\Core\Entity\EntityTypeBundleInfoInterface
*/
protected $entityTypeBundleInfo;
/**
* Constructs a new EntityPermissionProvider object.
*
* @param \Drupal\Core\Entity\EntityTypeBundleInfoInterface $entity_type_bundle_info
* The entity type bundle info.
*/
public function __construct(EntityTypeBundleInfoInterface $entity_type_bundle_info) {
$this->entityTypeBundleInfo = $entity_type_bundle_info;
}
/**
* {@inheritdoc}
*/
public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type) {
return new static(
$container->get('entity_type.bundle.info')
);
}
/**
* {@inheritdoc}
*/
public function buildPermissions(EntityTypeInterface $entity_type) {
$entity_type_id = $entity_type->id();
$has_owner = $entity_type->isSubclassOf(EntityOwnerInterface::class);
$singular_label = $entity_type->getSingularLabel();
$plural_label = $entity_type->getPluralLabel();
$permissions = [];
$permissions["administer {$entity_type_id}"] = [
'title' => $this->t('Administer @type', ['@type' => $plural_label]),
'restrict access' => TRUE,
];
// Config entity types use the administer permission for listings, while
// content entity types use a separate "access overview" permission.
if ($entity_type instanceof ContentEntityTypeInterface) {
$permissions["access {$entity_type_id} overview"] = [
'title' => $this->t('Access the @type overview page', ['@type' => $plural_label]),
];
}
// View permissions are the same for both granularities, for now.
if ($has_owner) {
$permissions["view any {$entity_type_id}"] = [
'title' => $this->t('View any @type', [
'@type' => $singular_label,
]),
];
$permissions["view own {$entity_type_id}"] = [
'title' => $this->t('View own @type', [
'@type' => $plural_label,
]),
];
}
else {
$permissions["view {$entity_type_id}"] = [
'title' => $this->t('View @type', [
'@type' => $plural_label,
]),
];
}
// Generate the other permissions based on granularity.
if ($entity_type->getPermissionGranularity() == 'entity_type') {
$permissions += $this->buildEntityTypePermissions($entity_type);
}
else {
$permissions += $this->buildBundlePermissions($entity_type);
}
foreach ($permissions as $name => $permission) {
// Permissions are grouped by provider on admin/people/permissions.
$permissions[$name]['provider'] = $entity_type->getProvider();
// TranslatableMarkup objects don't sort properly.
$permissions[$name]['title'] = (string) $permission['title'];
}
return $permissions;
}
/**
* Builds permissions for the entity_type granularity.
*
* @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
* The entity type.
*
* @return array
* The permissions.
*/
protected function buildEntityTypePermissions(EntityTypeInterface $entity_type) {
$entity_type_id = $entity_type->id();
$has_owner = $entity_type->isSubclassOf(EntityOwnerInterface::class);
$singular_label = $entity_type->getSingularLabel();
$plural_label = $entity_type->getPluralLabel();
$permissions = [];
if ($has_owner) {
$permissions["create any {$entity_type_id}"] = [
'title' => $this->t('Create any @type', [
'@type' => $singular_label,
]),
];
$permissions["create own {$entity_type_id}"] = [
'title' => $this->t('Create own @type', [
'@type' => $plural_label,
]),
];
$permissions["update any {$entity_type_id}"] = [
'title' => $this->t('Update any @type', [
'@type' => $singular_label,
]),
];
$permissions["update own {$entity_type_id}"] = [
'title' => $this->t('Update own @type', [
'@type' => $plural_label,
]),
];
$permissions["delete any {$entity_type_id}"] = [
'title' => $this->t('Delete any @type', [
'@type' => $singular_label,
]),
];
$permissions["delete own {$entity_type_id}"] = [
'title' => $this->t('Delete own @type', [
'@type' => $plural_label,
]),
];
}
else {
$permissions["create {$entity_type_id}"] = [
'title' => $this->t('Create @type', [
'@type' => $plural_label,
]),
];
$permissions["update {$entity_type_id}"] = [
'title' => $this->t('Update @type', [
'@type' => $plural_label,
]),
];
$permissions["delete {$entity_type_id}"] = [
'title' => $this->t('Delete @type', [
'@type' => $plural_label,
]),
];
}
return $permissions;
}
/**
* Builds permissions for the bundle granularity.
*
* @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
* The entity type.
*
* @return array
* The permissions.
*/
protected function buildBundlePermissions(EntityTypeInterface $entity_type) {
$entity_type_id = $entity_type->id();
$bundles = $this->entityTypeBundleInfo->getBundleInfo($entity_type_id);
$has_owner = $entity_type->isSubclassOf(EntityOwnerInterface::class);
$singular_label = $entity_type->getSingularLabel();
$plural_label = $entity_type->getPluralLabel();
$permissions = [];
foreach ($bundles as $bundle_name => $bundle_info) {
if ($has_owner) {
$permissions["create any {$bundle_name} {$entity_type_id}"] = [
'title' => $this->t('@bundle: Create any @type', [
'@bundle' => $bundle_info['label'],
'@type' => $singular_label,
]),
];
$permissions["create own {$bundle_name} {$entity_type_id}"] = [
'title' => $this->t('@bundle: Create own @type', [
'@bundle' => $bundle_info['label'],
'@type' => $plural_label,
]),
];
$permissions["update any {$bundle_name} {$entity_type_id}"] = [
'title' => $this->t('@bundle: Update any @type', [
'@bundle' => $bundle_info['label'],
'@type' => $singular_label,
]),
];
$permissions["update own {$bundle_name} {$entity_type_id}"] = [
'title' => $this->t('@bundle: Update own @type', [
'@bundle' => $bundle_info['label'],
'@type' => $plural_label,
]),
];
$permissions["delete any {$bundle_name} {$entity_type_id}"] = [
'title' => $this->t('@bundle: Delete any @type', [
'@bundle' => $bundle_info['label'],
'@type' => $singular_label,
]),
];
$permissions["delete own {$bundle_name} {$entity_type_id}"] = [
'title' => $this->t('@bundle: Delete own @type', [
'@bundle' => $bundle_info['label'],
'@type' => $plural_label,
]),
];
}
else {
$permissions["create {$bundle_name} {$entity_type_id}"] = [
'title' => $this->t('@bundle: Create @type', [
'@bundle' => $bundle_info['label'],
'@type' => $plural_label,
]),
];
$permissions["update {$bundle_name} {$entity_type_id}"] = [
'title' => $this->t('@bundle: Update @type', [
'@bundle' => $bundle_info['label'],
'@type' => $plural_label,
]),
];
$permissions["delete {$bundle_name} {$entity_type_id}"] = [
'title' => $this->t('@bundle: Delete @type', [
'@bundle' => $bundle_info['label'],
'@type' => $plural_label,
]),
];
}
}
return $permissions;
}
}
class EntityPermissionProvider extends BaseEntityPermissionProvider {}
<?php
namespace Drupal\commerce;
use Drupal\Core\Entity\EntityTypeInterface;
/**
* Allows entity types to provide permissions.
*/
interface EntityPermissionProviderInterface {
/**
* Builds permissions for the given entity type.
*
* @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
* The entity type.
*
* @return array
* The permissions.
*/
public function buildPermissions(EntityTypeInterface $entity_type);
}
<?php
namespace Drupal\commerce;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Class for generating per-bundle CRUD permissions.
*/
class EntityPermissions implements ContainerInjectionInterface {
/**
* The entity type manager.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected $entityTypeManager;
/**
* Constructs a new EntityPermissions object.
*
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* The entity type manager.
*/
public function __construct(EntityTypeManagerInterface $entity_type_manager) {
$this->entityTypeManager = $entity_type_manager;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('entity_type.manager')
);
}
/**
* Builds a list of permissions for the participating entity types.
*
* @return array
* The permissions.
*/
public function buildPermissions() {
$permissions = [];
/** @var \Drupal\Core\Entity\EntityTypeInterface[] $entity_types */
foreach ($this->entityTypeManager->getDefinitions() as $entity_type) {
if ($entity_type->hasHandlerClass('permission_provider')) {
$permission_provider_class = $entity_type->getHandlerClass('permission_provider');
$permission_provider = $this->entityTypeManager->createHandlerInstance($permission_provider_class, $entity_type);
$permissions += $permission_provider->buildPermissions($entity_type);
}
}
return $permissions;
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment