updated contrib modules : pathauto, token, entity_api, search_api, redirect, features
This commit is contained in:
+14
-1
@@ -69,6 +69,20 @@ class EntityRevisionRouteAccessChecker implements AccessInterface {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs access checks.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\ContentEntityInterface $entity
|
||||
* The entity for which to check access.
|
||||
* @param \Drupal\Core\Session\AccountInterface $account
|
||||
* The user for which to check access.
|
||||
* @param string $operation
|
||||
* The entity operation. Usually one of 'view', 'view label', 'update' or
|
||||
* 'delete'.
|
||||
*
|
||||
* @return bool
|
||||
* The access result.
|
||||
*/
|
||||
protected function checkAccess(ContentEntityInterface $entity, AccountInterface $account, $operation = 'view') {
|
||||
$entity_type = $entity->getEntityType();
|
||||
$entity_type_id = $entity->getEntityTypeId();
|
||||
@@ -126,7 +140,6 @@ class EntityRevisionRouteAccessChecker implements AccessInterface {
|
||||
return $this->accessCache[$cid];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Counts the number of revisions in the default language.
|
||||
*
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\entity;
|
||||
|
||||
use Drupal\Core\Access\AccessResult;
|
||||
use Drupal\Core\Entity\EntityAccessControlHandler as CoreEntityAccessControlHandler;
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
|
||||
/**
|
||||
* Controls access to bundle entities.
|
||||
*
|
||||
* Allows the bundle entity label to be viewed if the account has
|
||||
* access to view entities of that bundle.
|
||||
*/
|
||||
class BundleEntityAccessControlHandler extends CoreEntityAccessControlHandler {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $viewLabelOperation = TRUE;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function checkAccess(EntityInterface $entity, $operation, AccountInterface $account) {
|
||||
if ($operation === 'view label') {
|
||||
$bundle = $entity->id();
|
||||
$entity_type_id = $this->entityType->getBundleOf();
|
||||
$permissions = [
|
||||
"administer $entity_type_id",
|
||||
// View permissions provided by EntityPermissionProvider.
|
||||
"view $entity_type_id",
|
||||
"view $bundle $entity_type_id",
|
||||
// View permissions provided by UncacheableEntityPermissionProvider.
|
||||
"view own $entity_type_id",
|
||||
"view any $entity_type_id",
|
||||
"view own $bundle $entity_type_id",
|
||||
"view any $bundle $entity_type_id",
|
||||
];
|
||||
|
||||
return AccessResult::allowedIfHasPermissions($account, $permissions, 'OR');
|
||||
}
|
||||
else {
|
||||
return parent::checkAccess($entity, $operation, $account);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+1
-1
@@ -60,7 +60,7 @@ class BundlePluginUninstallValidator implements ModuleUninstallValidatorInterfac
|
||||
});
|
||||
|
||||
$bundles_with_content = array_intersect_key($bundles_filtered_by_module, array_flip($bundle_keys_with_content));
|
||||
|
||||
|
||||
foreach ($bundles_with_content as $bundle) {
|
||||
$reasons[] = $this->t('There is data for the bundle @bundle on the entity type @entity_type. Please remove all content before uninstalling the module.', [
|
||||
'@bundle' => $bundle['label'],
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\entity\Entity;
|
||||
|
||||
use Drupal\Core\Entity\RevisionableEntityBundleInterface as CoreRevisionableEntityBundleInterface;
|
||||
|
||||
@trigger_error('\Drupal\entity\Entity\RevisionableEntityBundleInterface has been deprecated in favor of \Drupal\Core\Entity\RevisionableEntityBundleInterface. Use that instead.');
|
||||
|
||||
/**
|
||||
* @deprecated in favor of
|
||||
* \Drupal\Core\Entity\RevisionableEntityBundleInterface. Use that instead.
|
||||
*/
|
||||
interface RevisionableEntityBundleInterface extends CoreRevisionableEntityBundleInterface {
|
||||
}
|
||||
@@ -3,19 +3,17 @@
|
||||
namespace Drupal\entity;
|
||||
|
||||
use Drupal\Core\Access\AccessResult;
|
||||
use Drupal\Core\Entity\EntityAccessControlHandler as CoreEntityAccessControlHandler;
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\Core\Entity\EntityPublishedInterface;
|
||||
use Drupal\Core\Entity\EntityTypeInterface;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Drupal\user\EntityOwnerInterface;
|
||||
|
||||
/**
|
||||
* Controls access based on the generic entity permissions.
|
||||
*
|
||||
* @see \Drupal\entity\UncacheableEntityPermissionProvider
|
||||
*/
|
||||
class EntityAccessControlHandler extends CoreEntityAccessControlHandler {
|
||||
class EntityAccessControlHandler extends EntityAccessControlHandlerBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
@@ -24,126 +22,36 @@ class EntityAccessControlHandler extends CoreEntityAccessControlHandler {
|
||||
parent::__construct($entity_type);
|
||||
|
||||
if (!$entity_type->hasHandlerClass('permission_provider') || !is_a($entity_type->getHandlerClass('permission_provider'), EntityPermissionProvider::class, TRUE)) {
|
||||
throw new \Exception("This entity access control handler requires the entity permissions provider: {EntityPermissionProvider::class}");
|
||||
throw new \Exception('\Drupal\entity\EntityAccessControlHandler requires the \Drupal\entity\EntityPermissionProvider permission provider.');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@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) {
|
||||
if ($operation === 'view') {
|
||||
$permissions = [
|
||||
"view {$entity->getEntityTypeId()}"
|
||||
];
|
||||
}
|
||||
else {
|
||||
$permissions = [
|
||||
"$operation {$entity->getEntityTypeId()}",
|
||||
"$operation {$entity->bundle()} {$entity->getEntityTypeId()}",
|
||||
];
|
||||
}
|
||||
return AccessResult::allowedIfHasPermissions($account, $permissions, '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\user\EntityOwnerInterface $entity */
|
||||
if ($operation === 'view') {
|
||||
if ($entity instanceof EntityPublishedInterface && !$entity->isPublished()) {
|
||||
if (($account->id() == $entity->getOwnerId())) {
|
||||
$permissions = [
|
||||
"view own unpublished {$entity->getEntityTypeId()}",
|
||||
];
|
||||
return AccessResult::allowedIfHasPermissions($account, $permissions)->cachePerUser();
|
||||
if ($account->id() != $entity->getOwnerId()) {
|
||||
// There's no permission for viewing other user's unpublished entity.
|
||||
return AccessResult::neutral()->cachePerUser();
|
||||
}
|
||||
return AccessResult::neutral()->cachePerUser();
|
||||
|
||||
$permissions = [
|
||||
"view own unpublished {$entity->getEntityTypeId()}",
|
||||
];
|
||||
$result = AccessResult::allowedIfHasPermissions($account, $permissions)->cachePerUser();
|
||||
}
|
||||
else {
|
||||
return AccessResult::allowedIfHasPermissions($account, [
|
||||
$result = AccessResult::allowedIfHasPermissions($account, [
|
||||
"view {$entity->getEntityTypeId()}",
|
||||
]);
|
||||
"view {$entity->bundle()} {$entity->getEntityTypeId()}",
|
||||
], 'OR');
|
||||
}
|
||||
}
|
||||
else {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function checkCreateAccess(AccountInterface $account, array $context, $entity_bundle = NULL) {
|
||||
$result = parent::checkCreateAccess($account, $context, $entity_bundle);
|
||||
if ($result->isNeutral()) {
|
||||
$permissions = [
|
||||
'administer ' . $this->entityTypeId,
|
||||
'create ' . $this->entityTypeId,
|
||||
];
|
||||
if ($entity_bundle) {
|
||||
$permissions[] = 'create ' . $entity_bundle . ' ' . $this->entityTypeId;
|
||||
}
|
||||
|
||||
$result = AccessResult::allowedIfHasPermissions($account, $permissions, 'OR');
|
||||
$result = parent::checkEntityOwnerPermissions($entity, $operation, $account);
|
||||
}
|
||||
|
||||
return $result;
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\entity;
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
class EntityAccessControlHandlerBase 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) {
|
||||
$permissions = [
|
||||
"$operation {$entity->getEntityTypeId()}",
|
||||
"$operation {$entity->bundle()} {$entity->getEntityTypeId()}",
|
||||
];
|
||||
|
||||
return AccessResult::allowedIfHasPermissions($account, $permissions, '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\user\EntityOwnerInterface $entity */
|
||||
if ($account->id() == $entity->getOwnerId()) {
|
||||
$permissions = [
|
||||
"$operation own {$entity->getEntityTypeId()}",
|
||||
"$operation any {$entity->getEntityTypeId()}",
|
||||
"$operation own {$entity->bundle()} {$entity->getEntityTypeId()}",
|
||||
"$operation any {$entity->bundle()} {$entity->getEntityTypeId()}",
|
||||
];
|
||||
}
|
||||
else {
|
||||
$permissions = [
|
||||
"$operation any {$entity->getEntityTypeId()}",
|
||||
"$operation any {$entity->bundle()} {$entity->getEntityTypeId()}",
|
||||
];
|
||||
}
|
||||
$result = AccessResult::allowedIfHasPermissions($account, $permissions, 'OR')->cachePerUser();
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function checkCreateAccess(AccountInterface $account, array $context, $entity_bundle = NULL) {
|
||||
$result = parent::checkCreateAccess($account, $context, $entity_bundle);
|
||||
if ($result->isNeutral()) {
|
||||
$permissions = [
|
||||
'administer ' . $this->entityTypeId,
|
||||
'create ' . $this->entityTypeId,
|
||||
];
|
||||
if ($entity_bundle) {
|
||||
$permissions[] = 'create ' . $entity_bundle . ' ' . $this->entityTypeId;
|
||||
}
|
||||
|
||||
$result = AccessResult::allowedIfHasPermissions($account, $permissions, 'OR');
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -5,24 +5,25 @@ namespace Drupal\entity;
|
||||
use Drupal\Core\Entity\EntityTypeInterface;
|
||||
|
||||
/**
|
||||
* Provides generic entity permissions which are still cacheable.
|
||||
* Provides generic entity permissions.
|
||||
*
|
||||
* This includes:
|
||||
* Intended for content entity types, since config entity types usually rely
|
||||
* on a single "administer" permission.
|
||||
*
|
||||
* Provided permissions:
|
||||
* - administer $entity_type
|
||||
* - access $entity_type overview
|
||||
* - view $entity_type
|
||||
* - view ($bundle) $entity_type
|
||||
* - view own unpublished $entity_type
|
||||
* - update (own|any) ($bundle) $entity_type
|
||||
* - delete (own|any) ($bundle) $entity_type
|
||||
* - create $bundle $entity_type
|
||||
*
|
||||
* This class does not support "view own ($bundle) $entity_type", because this
|
||||
* results in caching per user. If you need this use case, please use
|
||||
* \Drupal\entity\UncacheableEntityPermissionProvider instead.
|
||||
* Does not provide "view own ($bundle) $entity_type" permissions, because
|
||||
* they require caching pages per user. Please use
|
||||
* \Drupal\entity\UncacheableEntityPermissionProvider if those permissions
|
||||
* are necessary.
|
||||
*
|
||||
* Intended for content entity types, since config entity types usually rely
|
||||
* on a single "administer" permission.
|
||||
* Example annotation:
|
||||
* @code
|
||||
* handlers = {
|
||||
@@ -37,23 +38,58 @@ use Drupal\Core\Entity\EntityTypeInterface;
|
||||
class EntityPermissionProvider extends EntityPermissionProviderBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* Builds permissions for the entity_type granularity.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
|
||||
* The entity type.
|
||||
*
|
||||
* @return array
|
||||
* The permissions.
|
||||
*/
|
||||
public function buildPermissions(EntityTypeInterface $entity_type) {
|
||||
protected function buildEntityTypePermissions(EntityTypeInterface $entity_type) {
|
||||
$permissions = parent::buildEntityTypePermissions($entity_type);
|
||||
$entity_type_id = $entity_type->id();
|
||||
$plural_label = $entity_type->getPluralLabel();
|
||||
|
||||
$permissions = parent::buildPermissions($entity_type);
|
||||
|
||||
// View permissions are the same for both granularities.
|
||||
$permissions["view {$entity_type_id}"] = [
|
||||
'title' => $this->t('View @type', [
|
||||
'@type' => $plural_label,
|
||||
]),
|
||||
];
|
||||
|
||||
return $this->processPermissions($permissions, $entity_type);
|
||||
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) {
|
||||
$permissions = parent::buildBundlePermissions($entity_type);
|
||||
$entity_type_id = $entity_type->id();
|
||||
$bundles = $this->entityTypeBundleInfo->getBundleInfo($entity_type_id);
|
||||
$plural_label = $entity_type->getPluralLabel();
|
||||
|
||||
$permissions["view {$entity_type_id}"] = [
|
||||
'title' => $this->t('View @type', [
|
||||
'@type' => $plural_label,
|
||||
]),
|
||||
];
|
||||
foreach ($bundles as $bundle_name => $bundle_info) {
|
||||
$permissions["view {$bundle_name} {$entity_type_id}"] = [
|
||||
'title' => $this->t('@bundle: View @type', [
|
||||
'@bundle' => $bundle_info['label'],
|
||||
'@type' => $plural_label,
|
||||
]),
|
||||
];
|
||||
}
|
||||
|
||||
return $permissions;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -56,9 +56,11 @@ class EntityPermissionProviderBase implements EntityPermissionProviderInterface,
|
||||
'title' => $this->t('Administer @type', ['@type' => $plural_label]),
|
||||
'restrict access' => TRUE,
|
||||
];
|
||||
$permissions["access {$entity_type_id} overview"] = [
|
||||
'title' => $this->t('Access the @type overview page', ['@type' => $plural_label]),
|
||||
];
|
||||
if ($entity_type->hasLinkTemplate('collection')) {
|
||||
$permissions["access {$entity_type_id} overview"] = [
|
||||
'title' => $this->t('Access the @type overview page', ['@type' => $plural_label]),
|
||||
];
|
||||
}
|
||||
if ($has_owner && $entity_type->entityClassImplements(EntityPublishedInterface::class)) {
|
||||
$permissions["view own unpublished {$entity_type_id}"] = [
|
||||
'title' => $this->t('View own unpublished @type', [
|
||||
@@ -82,7 +84,7 @@ class EntityPermissionProviderBase implements EntityPermissionProviderInterface,
|
||||
* Adds the provider and converts the titles to strings to allow sorting.
|
||||
*
|
||||
* @param array $permissions
|
||||
* The array of permissions
|
||||
* The array of permissions.
|
||||
* @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
|
||||
* The entity type.
|
||||
*
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\entity;
|
||||
|
||||
use Drupal\Core\Entity\EntityViewBuilder as CoreEntityViewBuilder;
|
||||
|
||||
@trigger_error('\Drupal\entity\EntityViewBuilder has been deprecated in favor of \Drupal\Core\Entity\EntityViewBuilder. Use that instead.');
|
||||
|
||||
/**
|
||||
* Provides a entity view builder with contextual links support.
|
||||
*
|
||||
* @deprecated in favor of \Drupal\Core\Entity\EntityViewBuilder. Use that
|
||||
* instead.
|
||||
*/
|
||||
class EntityViewBuilder extends CoreEntityViewBuilder {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\entity\Form;
|
||||
|
||||
use Drupal\Core\Entity\ContentEntityForm;
|
||||
use Drupal\Core\Entity\RevisionableEntityBundleInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
|
||||
@trigger_error('\Drupal\entity\Form\RevisionableContentEntityForm has been deprecated in favor of \Drupal\Core\Entity\ContentEntityForm. Use that instead.');
|
||||
|
||||
/**
|
||||
* Extends the base entity form with revision support in the UI.
|
||||
*
|
||||
* @deprecated in favor of \Drupal\Core\Entity\ContentEntityForm. Use that
|
||||
* instead.
|
||||
*/
|
||||
class RevisionableContentEntityForm extends ContentEntityForm {
|
||||
|
||||
/**
|
||||
* The entity being used by this form.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityInterface|\Drupal\Core\Entity\RevisionableInterface|\Drupal\entity\Revision\EntityRevisionLogInterface
|
||||
*/
|
||||
protected $entity;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function prepareEntity() {
|
||||
parent::prepareEntity();
|
||||
|
||||
$bundle_entity = $this->getBundleEntity();
|
||||
|
||||
// Set up default values, if required.
|
||||
if (!$this->entity->isNew()) {
|
||||
$this->entity->setRevisionLogMessage(NULL);
|
||||
}
|
||||
|
||||
if ($bundle_entity instanceof RevisionableEntityBundleInterface) {
|
||||
// Always use the default revision setting.
|
||||
$this->entity->setNewRevision($bundle_entity && $bundle_entity->shouldCreateNewRevision());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the bundle entity of the current entity.
|
||||
*
|
||||
* @return \Drupal\Core\Entity\EntityInterface|null
|
||||
* The bundle entity, or NULL if there is none.
|
||||
*/
|
||||
protected function getBundleEntity() {
|
||||
if ($bundle_key = $this->entity->getEntityType()->getKey('bundle')) {
|
||||
return $this->entity->{$bundle_key}->referencedEntities()[0];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function form(array $form, FormStateInterface $form_state) {
|
||||
$entity_type = $this->entity->getEntityType();
|
||||
$bundle_entity = $this->getBundleEntity();
|
||||
$account = $this->currentUser();
|
||||
|
||||
if ($this->operation == 'edit') {
|
||||
$form['#title'] = $this->t('Edit %bundle_label @label', [
|
||||
'%bundle_label' => $bundle_entity ? $bundle_entity->label() : '',
|
||||
'@label' => $this->entity->label(),
|
||||
]);
|
||||
}
|
||||
|
||||
$form['advanced'] = [
|
||||
'#type' => 'vertical_tabs',
|
||||
'#weight' => 99,
|
||||
];
|
||||
|
||||
// Add a log field if the "Create new revision" option is checked, or if the
|
||||
// current user has the ability to check that option.
|
||||
// @todo Could we autogenerate this form by using some widget on the
|
||||
// revision info field.
|
||||
$form['revision_information'] = [
|
||||
'#type' => 'details',
|
||||
'#title' => $this->t('Revision information'),
|
||||
// Open by default when "Create new revision" is checked.
|
||||
'#open' => $this->entity->isNewRevision(),
|
||||
'#group' => 'advanced',
|
||||
'#weight' => 20,
|
||||
'#access' => $this->entity->isNewRevision() || $account->hasPermission($entity_type->get('admin_permission')),
|
||||
];
|
||||
|
||||
$form['revision_information']['revision'] = [
|
||||
'#type' => 'checkbox',
|
||||
'#title' => $this->t('Create new revision'),
|
||||
'#default_value' => $this->entity->isNewRevision(),
|
||||
'#access' => $account->hasPermission($entity_type->get('admin_permission')),
|
||||
];
|
||||
|
||||
// Check the revision log checkbox when the log textarea is filled in.
|
||||
// This must not happen if "Create new revision" is enabled by default,
|
||||
// since the state would auto-disable the checkbox otherwise.
|
||||
if (!$this->entity->isNewRevision()) {
|
||||
$form['revision_information']['revision']['#states'] = [
|
||||
'checked' => [
|
||||
'textarea[name="revision_log"]' => ['empty' => FALSE],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
$form['revision_information']['revision_log'] = [
|
||||
'#type' => 'textarea',
|
||||
'#title' => $this->t('Revision log message'),
|
||||
'#rows' => 4,
|
||||
'#default_value' => $this->entity->getRevisionLogMessage(),
|
||||
'#description' => $this->t('Briefly describe the changes you have made.'),
|
||||
];
|
||||
|
||||
return parent::form($form, $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function save(array $form, FormStateInterface $form_state) {
|
||||
// Save as a new revision if requested to do so.
|
||||
if (!$form_state->isValueEmpty('revision')) {
|
||||
$this->entity->setNewRevision();
|
||||
}
|
||||
|
||||
$insert = $this->entity->isNew();
|
||||
$this->entity->save();
|
||||
$context = ['@type' => $this->entity->bundle(), '%info' => $this->entity->label()];
|
||||
$logger = $this->logger('content');
|
||||
$bundle_entity = $this->getBundleEntity();
|
||||
$t_args = ['@type' => $bundle_entity ? $bundle_entity->label() : 'None', '%info' => $this->entity->label()];
|
||||
|
||||
if ($insert) {
|
||||
$logger->notice('@type: added %info.', $context);
|
||||
drupal_set_message($this->t('@type %info has been created.', $t_args));
|
||||
}
|
||||
else {
|
||||
$logger->notice('@type: updated %info.', $context);
|
||||
drupal_set_message($this->t('@type %info has been updated.', $t_args));
|
||||
}
|
||||
|
||||
if ($this->entity->id()) {
|
||||
$form_state->setValue('id', $this->entity->id());
|
||||
$form_state->set('id', $this->entity->id());
|
||||
|
||||
if ($this->entity->getEntityType()->hasLinkTemplate('collection')) {
|
||||
$form_state->setRedirectUrl($this->entity->toUrl('collection'));
|
||||
}
|
||||
else {
|
||||
$form_state->setRedirectUrl($this->entity->toUrl('canonical'));
|
||||
}
|
||||
}
|
||||
else {
|
||||
// In the unlikely case something went wrong on save, the entity will be
|
||||
// rebuilt and entity form redisplayed.
|
||||
drupal_set_message($this->t('The entity could not be saved.'), 'error');
|
||||
$form_state->setRebuild();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -44,7 +44,7 @@ class DeleteAction extends ActionBase implements ContainerFactoryPluginInterface
|
||||
* The plugin implementation definition.
|
||||
* @param \Drupal\Core\TempStore\PrivateTempStoreFactory $temp_store_factory
|
||||
* The tempstore factory.
|
||||
* @param AccountInterface $current_user
|
||||
* @param \Drupal\Core\Session\AccountInterface $current_user
|
||||
* Current user.
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, PrivateTempStoreFactory $temp_store_factory, AccountInterface $current_user) {
|
||||
|
||||
+13
-97
@@ -3,12 +3,10 @@
|
||||
namespace Drupal\entity;
|
||||
|
||||
use Drupal\Core\Access\AccessResult;
|
||||
use Drupal\Core\Entity\EntityAccessControlHandler as CoreEntityAccessControlHandler;
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\Core\Entity\EntityPublishedInterface;
|
||||
use Drupal\Core\Entity\EntityTypeInterface;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Drupal\user\EntityOwnerInterface;
|
||||
|
||||
/**
|
||||
* Controls access based on the uncacheable entity permissions.
|
||||
@@ -17,7 +15,7 @@ use Drupal\user\EntityOwnerInterface;
|
||||
*
|
||||
* Note: this access control handler will cause pages to be cached per user.
|
||||
*/
|
||||
class UncacheableEntityAccessControlHandler extends CoreEntityAccessControlHandler {
|
||||
class UncacheableEntityAccessControlHandler extends EntityAccessControlHandlerBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
@@ -26,110 +24,28 @@ class UncacheableEntityAccessControlHandler extends CoreEntityAccessControlHandl
|
||||
parent::__construct($entity_type);
|
||||
|
||||
if (!$entity_type->hasHandlerClass('permission_provider') || !is_a($entity_type->getHandlerClass('permission_provider'), UncacheableEntityPermissionProvider::class, TRUE)) {
|
||||
throw new \Exception("This entity access control handler requires the entity permissions provider: {EntityPermissionProvider::class}");
|
||||
throw new \Exception('\Drupal\entity\UncacheableEntityAccessControlHandler requires the \Drupal\entity\UncacheableEntityPermissionProvider permission provider.');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@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())) {
|
||||
if ($operation === 'view' && $entity instanceof EntityPublishedInterface && !$entity->isPublished()) {
|
||||
$permissions = [
|
||||
"view own unpublished {$entity->getEntityTypeId()}",
|
||||
];
|
||||
/** @var \Drupal\user\EntityOwnerInterface $entity */
|
||||
if ($operation === 'view' && $entity instanceof EntityPublishedInterface && !$entity->isPublished()) {
|
||||
if ($account->id() != $entity->getOwnerId()) {
|
||||
// There's no permission for viewing other user's unpublished entity.
|
||||
return AccessResult::neutral()->cachePerUser();
|
||||
}
|
||||
else {
|
||||
$permissions = [
|
||||
"$operation own {$entity->getEntityTypeId()}",
|
||||
"$operation any {$entity->getEntityTypeId()}",
|
||||
"$operation own {$entity->bundle()} {$entity->getEntityTypeId()}",
|
||||
"$operation any {$entity->bundle()} {$entity->getEntityTypeId()}",
|
||||
];
|
||||
}
|
||||
$result = AccessResult::allowedIfHasPermissions($account, $permissions, 'OR');
|
||||
|
||||
$permissions = [
|
||||
"view own unpublished {$entity->getEntityTypeId()}",
|
||||
];
|
||||
$result = AccessResult::allowedIfHasPermissions($account, $permissions)->cachePerUser();
|
||||
}
|
||||
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()) {
|
||||
$permissions = [
|
||||
'administer ' . $this->entityTypeId,
|
||||
'create ' . $this->entityTypeId,
|
||||
];
|
||||
if ($entity_bundle) {
|
||||
$permissions[] = 'create ' . $entity_bundle . ' ' . $this->entityTypeId;
|
||||
}
|
||||
|
||||
$result = AccessResult::allowedIfHasPermissions($account, $permissions, 'OR');
|
||||
$result = parent::checkEntityOwnerPermissions($entity, $operation, $account);
|
||||
}
|
||||
|
||||
return $result;
|
||||
|
||||
@@ -8,24 +8,25 @@ use Drupal\user\EntityOwnerInterface;
|
||||
/**
|
||||
* Provides generic entity permissions which are cached per user.
|
||||
*
|
||||
* This includes:
|
||||
* Intended for content entity types, since config entity types usually rely
|
||||
* on a single "administer" permission.
|
||||
*
|
||||
* Provided permissions:
|
||||
* - administer $entity_type
|
||||
* - access $entity_type overview
|
||||
* - view an ($bundle) $entity_type
|
||||
* - view any ($bundle) $entity_type
|
||||
* - view own ($bundle) $entity_type
|
||||
* - view own unpublished $entity_type
|
||||
* - update (own|any) ($bundle) $entity_type
|
||||
* - delete (own|any) ($bundle) $entity_type
|
||||
* - create $bundle $entity_type
|
||||
*
|
||||
* As this class supports "view own ($bundle) $entity_type" it is just cacheable
|
||||
* per user, which might harm performance of sites. Given that please use
|
||||
* \Drupal\entity\EntityPermissionProvider unless you need the feature, or your
|
||||
* entity type is not really user facing (commerce orders for example).
|
||||
* Important:
|
||||
* Provides "view own ($bundle) $entity_type" permissions, which require
|
||||
* caching pages per user. This can significantly increase the size of caches,
|
||||
* impacting site performance. Use \Drupal\entity\EntityPermissionProvider
|
||||
* if those permissions are not necessary.
|
||||
*
|
||||
* Intended for content entity types, since config entity types usually rely
|
||||
* on a single "administer" permission.
|
||||
* Example annotation:
|
||||
* @code
|
||||
* handlers = {
|
||||
|
||||
Reference in New Issue
Block a user