updated contrib modules
This commit is contained in:
@@ -38,7 +38,7 @@ before_script:
|
||||
# Export database variable for kernel tests.
|
||||
- export SIMPLETEST_DB=mysql://root:@127.0.0.1/entity
|
||||
# Download Drupal 8 core.
|
||||
- travis_retry git clone --branch 8.1.x --depth 1 http://git.drupal.org/project/drupal.git
|
||||
- travis_retry git clone --branch 8.3.x --depth 1 http://git.drupal.org/project/drupal.git
|
||||
- cd drupal
|
||||
- composer self-update
|
||||
- composer install -n
|
||||
|
||||
@@ -5,6 +5,6 @@
|
||||
"homepage": "http://drupal.org/project/entity",
|
||||
"license": "GPL-2.0+",
|
||||
"require": {
|
||||
"drupal/core": "~8.1"
|
||||
"drupal/core": "~8.3"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,10 +3,10 @@ description: Provides expanded entity APIs, which will be moved to Drupal core o
|
||||
type: module
|
||||
# core: 8.x
|
||||
dependencies:
|
||||
- system (>=8.1.0)
|
||||
- drupal:system (>=8.3.0)
|
||||
|
||||
# Information added by Drupal.org packaging script on 2016-12-08
|
||||
version: '8.x-1.0-alpha4'
|
||||
# Information added by Drupal.org packaging script on 2017-09-20
|
||||
version: '8.x-1.0-beta1'
|
||||
core: '8.x'
|
||||
project: 'entity'
|
||||
datestamp: 1481194986
|
||||
datestamp: 1505895847
|
||||
|
||||
@@ -4,3 +4,85 @@
|
||||
* @file
|
||||
* Provides expanded entity APIs.
|
||||
*/
|
||||
|
||||
use Drupal\Core\Entity\EntityTypeInterface;
|
||||
use Drupal\entity\BundlePlugin\BundlePluginHandler;
|
||||
|
||||
/**
|
||||
* Gets the entity types which use bundle plugins.
|
||||
*
|
||||
* @return \Drupal\Core\Entity\EntityTypeInterface[]
|
||||
* The entity types.
|
||||
*/
|
||||
function entity_get_bundle_plugin_entity_types() {
|
||||
$entity_types = \Drupal::entityTypeManager()->getDefinitions();
|
||||
$entity_types = array_filter($entity_types, function (EntityTypeInterface $entity_type) {
|
||||
return $entity_type->hasHandlerClass('bundle_plugin');
|
||||
});
|
||||
|
||||
return $entity_types;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_entity_type_build().
|
||||
*/
|
||||
function entity_entity_type_build(array &$entity_types) {
|
||||
foreach ($entity_types as $entity_type) {
|
||||
if ($entity_type->get('bundle_plugin_type')) {
|
||||
$entity_type->setHandlerClass('bundle_plugin', BundlePluginHandler::class);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_entity_bundle_info().
|
||||
*/
|
||||
function entity_entity_bundle_info() {
|
||||
$bundles = [];
|
||||
foreach (entity_get_bundle_plugin_entity_types() as $entity_type) {
|
||||
/** @var \Drupal\entity\BundlePlugin\BundlePluginHandler $bundle_handler */
|
||||
$bundle_handler = \Drupal::entityTypeManager()->getHandler($entity_type->id(), 'bundle_plugin');
|
||||
$bundles[$entity_type->id()] = $bundle_handler->getBundleInfo();
|
||||
}
|
||||
return $bundles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_entity_field_storage_info().
|
||||
*/
|
||||
function entity_entity_field_storage_info(EntityTypeInterface $entity_type) {
|
||||
if ($entity_type->hasHandlerClass('bundle_plugin')) {
|
||||
/** @var \Drupal\entity\BundlePlugin\BundlePluginHandler $bundle_handler */
|
||||
$bundle_handler = \Drupal::entityTypeManager()->getHandler($entity_type->id(), 'bundle_plugin');
|
||||
return $bundle_handler->getFieldStorageDefinitions();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_entity_bundle_field_info().
|
||||
*/
|
||||
function entity_entity_bundle_field_info(EntityTypeInterface $entity_type, $bundle) {
|
||||
if ($entity_type->hasHandlerClass('bundle_plugin')) {
|
||||
/** @var \Drupal\entity\BundlePlugin\BundlePluginHandler $bundle_handler */
|
||||
$bundle_handler = \Drupal::entityTypeManager()->getHandler($entity_type->id(), 'bundle_plugin');
|
||||
return $bundle_handler->getFieldDefinitions($bundle);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_modules_installed().
|
||||
*/
|
||||
function entity_modules_installed($modules) {
|
||||
foreach (entity_get_bundle_plugin_entity_types() as $entity_type) {
|
||||
\Drupal::service('entity.bundle_plugin_installer')->installBundles($entity_type, $modules);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_module_preuninstall().
|
||||
*/
|
||||
function entity_module_preuninstall($module) {
|
||||
foreach (entity_get_bundle_plugin_entity_types() as $entity_type) {
|
||||
\Drupal::service('entity.bundle_plugin_installer')->uninstallBundles($entity_type, [$module]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,16 @@
|
||||
services:
|
||||
access_checker.entity_revision:
|
||||
class: \Drupal\entity\Access\EntityRevisionRouteAccessChecker
|
||||
arguments: ['@entity_type.manager', '@request_stack']
|
||||
arguments: ['@entity_type.manager', '@current_route_match']
|
||||
tags:
|
||||
- { name: access_check, applies_to: _entity_access_revision }
|
||||
|
||||
entity.bundle_plugin_installer:
|
||||
class: Drupal\entity\BundlePlugin\BundlePluginInstaller
|
||||
arguments: ['@entity_type.manager', '@entity_bundle.listener', '@field_storage_definition.listener', '@field_definition.listener']
|
||||
|
||||
entity.bundle_plugin.uninstall_validator:
|
||||
class: \Drupal\entity\BundlePlugin\BundlePluginUninstallValidator
|
||||
tags:
|
||||
- { name: module_install.uninstall_validator }
|
||||
arguments: ['@entity_type.manager', '@string_translation']
|
||||
|
||||
@@ -9,7 +9,7 @@ use Drupal\Core\Entity\EntityTypeInterface;
|
||||
function entity_views_data() {
|
||||
$entity_types = \Drupal::entityTypeManager()->getDefinitions();
|
||||
$entity_types = array_filter($entity_types, function (EntityTypeInterface $entity_type) {
|
||||
return $entity_type->isSubclassOf(ContentEntityInterface::class);
|
||||
return $entity_type->entityClassImplements(ContentEntityInterface::class);
|
||||
});
|
||||
|
||||
$data = [];
|
||||
|
||||
+19
-16
@@ -7,9 +7,8 @@ use Drupal\Core\Entity\ContentEntityInterface;
|
||||
use Drupal\Core\Entity\EntityStorageInterface;
|
||||
use Drupal\Core\Entity\EntityTypeManagerInterface;
|
||||
use Drupal\Core\Routing\Access\AccessInterface;
|
||||
use Drupal\Core\Routing\RouteMatchInterface;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
use Symfony\Component\Routing\Route;
|
||||
|
||||
/**
|
||||
@@ -30,42 +29,42 @@ class EntityRevisionRouteAccessChecker implements AccessInterface {
|
||||
protected $accessCache = array();
|
||||
|
||||
/**
|
||||
* The request stack.
|
||||
* The currently active route match object.
|
||||
*
|
||||
* @var \Symfony\Component\HttpFoundation\RequestStack
|
||||
* @var \Drupal\Core\Routing\RouteMatchInterface
|
||||
*/
|
||||
protected $requestStack;
|
||||
protected $routeMatch;
|
||||
|
||||
/**
|
||||
* Creates a new EntityRevisionRouteAccessChecker instance.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
|
||||
* The entity manager.
|
||||
* @param \Symfony\Component\HttpFoundation\RequestStack $request_stack
|
||||
* The request stack.
|
||||
* @param \Drupal\Core\Routing\RouteMatchInterface $route_match
|
||||
* The currently active route match object.
|
||||
*/
|
||||
public function __construct(EntityTypeManagerInterface $entity_type_manager, RequestStack $request_stack) {
|
||||
public function __construct(EntityTypeManagerInterface $entity_type_manager, RouteMatchInterface $route_match) {
|
||||
$this->entityTypeManager = $entity_type_manager;
|
||||
$this->requestStack = $request_stack;
|
||||
$this->routeMatch = $route_match;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function access(Route $route, AccountInterface $account, Request $request = NULL) {
|
||||
if (empty($request)) {
|
||||
$request = $this->requestStack->getCurrentRequest();
|
||||
public function access(Route $route, AccountInterface $account, RouteMatchInterface $route_match = NULL) {
|
||||
if (empty($route_match)) {
|
||||
$route_match = $this->routeMatch;
|
||||
}
|
||||
|
||||
$operation = $route->getRequirement('_entity_access_revision');
|
||||
list(, $operation) = explode('.', $operation, 2);
|
||||
list($entity_type_id, $operation) = explode('.', $operation, 2);
|
||||
|
||||
if ($operation === 'list') {
|
||||
$_entity = $request->attributes->get('_entity', $request->attributes->get($route->getOption('entity_type_id')));
|
||||
$_entity = $route_match->getParameter($entity_type_id);
|
||||
return AccessResult::allowedIf($this->checkAccess($_entity, $account, $operation))->cachePerPermissions();
|
||||
}
|
||||
else {
|
||||
$_entity_revision = $request->attributes->get('_entity_revision');
|
||||
$_entity_revision = $route_match->getParameter($entity_type_id . '_revision');
|
||||
return AccessResult::allowedIf($_entity_revision && $this->checkAccess($_entity_revision, $account, $operation))->cachePerPermissions();
|
||||
}
|
||||
}
|
||||
@@ -104,8 +103,10 @@ class EntityRevisionRouteAccessChecker implements AccessInterface {
|
||||
$cid = $entity->getRevisionId() . ':' . $langcode . ':' . $account->id() . ':' . $operation;
|
||||
|
||||
if (!isset($this->accessCache[$cid])) {
|
||||
$admin_permission = $entity_type->getAdminPermission();
|
||||
|
||||
// Perform basic permission checks first.
|
||||
if (!$account->hasPermission($map[$operation]) && !$account->hasPermission($type_map[$operation]) && !$account->hasPermission('administer nodes')) {
|
||||
if (!$account->hasPermission($map[$operation]) && !$account->hasPermission($type_map[$operation]) && ($admin_permission && !$account->hasPermission($admin_permission))) {
|
||||
$this->accessCache[$cid] = FALSE;
|
||||
return FALSE;
|
||||
}
|
||||
@@ -114,6 +115,8 @@ class EntityRevisionRouteAccessChecker implements AccessInterface {
|
||||
$this->accessCache[$cid] = TRUE;
|
||||
}
|
||||
else {
|
||||
// Entity access handlers are generally not aware of the "list" operation.
|
||||
$operation = $operation == 'list' ? 'view' : $operation;
|
||||
// First check the access to the default revision and finally, if the
|
||||
// node passed in is not the default revision then access to that, too.
|
||||
$this->accessCache[$cid] = $entity_access->access($entity_storage->load($entity->id()), $operation, $account) && ($entity->isDefaultRevision() || $entity_access->access($entity, $operation, $account));
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\entity;
|
||||
|
||||
use Drupal\Core\Field\BaseFieldDefinition;
|
||||
|
||||
/**
|
||||
* Provides a field definition class for bundle fields.
|
||||
*
|
||||
* Core currently doesn't provide one, the hook_entity_bundle_field_info()
|
||||
* example uses BaseFieldDefinition, which is wrong. Tracked in #2346347.
|
||||
*
|
||||
* Note that this class implements both FieldStorageDefinitionInterface and
|
||||
* FieldDefinitionInterface. This is a simplification for DX reasons,
|
||||
* allowing code to return just the bundle definitions instead of having to
|
||||
* return both storage definitions and bundle definitions.
|
||||
*/
|
||||
class BundleFieldDefinition extends BaseFieldDefinition {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isBaseField() {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\entity\BundlePlugin;
|
||||
|
||||
use Drupal\Component\Plugin\PluginManagerInterface;
|
||||
use Drupal\Core\Entity\EntityTypeInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
class BundlePluginHandler implements BundlePluginHandlerInterface {
|
||||
|
||||
/**
|
||||
* The entity type.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityTypeInterface
|
||||
*/
|
||||
protected $entityType;
|
||||
|
||||
/**
|
||||
* The bundle plugin manager.
|
||||
*
|
||||
* @var \Drupal\Component\Plugin\PluginManagerInterface
|
||||
*/
|
||||
protected $pluginManager;
|
||||
|
||||
/**
|
||||
* Constructs a new BundlePluginHandler object.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
|
||||
* The entity type.
|
||||
* @param \Drupal\Component\Plugin\PluginManagerInterface $plugin_manager
|
||||
* The bundle plugin manager.
|
||||
*/
|
||||
public function __construct(EntityTypeInterface $entity_type, PluginManagerInterface $plugin_manager) {
|
||||
$this->entityType = $entity_type;
|
||||
$this->pluginManager = $plugin_manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type) {
|
||||
return new static(
|
||||
$entity_type,
|
||||
$container->get('plugin.manager.' . $entity_type->get('bundle_plugin_type'))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getBundleInfo() {
|
||||
$bundles = [];
|
||||
foreach ($this->pluginManager->getDefinitions() as $plugin_id => $definition) {
|
||||
$bundles[$plugin_id] = [
|
||||
'label' => $definition['label'],
|
||||
'description' => isset($definition['description']) ? $definition['description'] : '',
|
||||
'translatable' => $this->entityType->isTranslatable(),
|
||||
'provider' => $definition['provider'],
|
||||
];
|
||||
}
|
||||
return $bundles;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFieldStorageDefinitions() {
|
||||
$definitions = [];
|
||||
foreach (array_keys($this->pluginManager->getDefinitions()) as $plugin_id) {
|
||||
/** @var \Drupal\entity\BundlePlugin\BundlePluginInterface $plugin */
|
||||
$plugin = $this->pluginManager->createInstance($plugin_id);
|
||||
$definitions += $plugin->buildFieldDefinitions();
|
||||
}
|
||||
// Ensure the presence of required keys which aren't set by the plugin.
|
||||
foreach ($definitions as $field_name => $definition) {
|
||||
$definition->setName($field_name);
|
||||
$definition->setTargetEntityTypeId($this->entityType->id());
|
||||
$definitions[$field_name] = $definition;
|
||||
}
|
||||
|
||||
return $definitions;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFieldDefinitions($bundle) {
|
||||
/** @var \Drupal\entity\BundlePlugin\BundlePluginInterface $plugin */
|
||||
$plugin = $this->pluginManager->createInstance($bundle);
|
||||
$definitions = $plugin->buildFieldDefinitions();
|
||||
// Ensure the presence of required keys which aren't set by the plugin.
|
||||
foreach ($definitions as $field_name => $definition) {
|
||||
$definition->setName($field_name);
|
||||
$definition->setTargetEntityTypeId($this->entityType->id());
|
||||
$definition->setTargetBundle($bundle);
|
||||
$definitions[$field_name] = $definition;
|
||||
}
|
||||
|
||||
return $definitions;
|
||||
}
|
||||
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\entity\BundlePlugin;
|
||||
|
||||
use Drupal\Core\Entity\EntityHandlerInterface;
|
||||
|
||||
/**
|
||||
* Handles plugin-provided bundles.
|
||||
*/
|
||||
interface BundlePluginHandlerInterface extends EntityHandlerInterface {
|
||||
|
||||
/**
|
||||
* Gets the bundle info.
|
||||
*
|
||||
* @return array
|
||||
* An array of bundle information keyed by the bundle name.
|
||||
* The format expected by hook_entity_bundle_info().
|
||||
*/
|
||||
public function getBundleInfo();
|
||||
|
||||
/**
|
||||
* Gets the field storage definitions.
|
||||
*/
|
||||
public function getFieldStorageDefinitions();
|
||||
|
||||
/**
|
||||
* Gets the field definitions for a specific bundle.
|
||||
*
|
||||
* @param string $bundle
|
||||
* The bundle name.
|
||||
*
|
||||
* @return \Drupal\entity\BundleFieldDefinition[]
|
||||
* An array of bundle field definitions, keyed by field name.
|
||||
*/
|
||||
public function getFieldDefinitions($bundle);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\entity\BundlePlugin;
|
||||
|
||||
use Drupal\Core\Entity\EntityBundleListenerInterface;
|
||||
use Drupal\Core\Entity\EntityTypeInterface;
|
||||
use Drupal\Core\Entity\EntityTypeManagerInterface;
|
||||
use Drupal\Core\Field\FieldDefinitionListenerInterface;
|
||||
use Drupal\Core\Field\FieldStorageDefinitionListenerInterface;
|
||||
|
||||
class BundlePluginInstaller implements BundlePluginInstallerInterface {
|
||||
|
||||
/**
|
||||
* The entity type manager.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
|
||||
*/
|
||||
protected $entityTypeManager;
|
||||
|
||||
/**
|
||||
* The entity bundle listener.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityBundleListenerInterface
|
||||
*/
|
||||
protected $entityBundleListener;
|
||||
|
||||
/**
|
||||
* The field storage definition listener.
|
||||
*
|
||||
* @var \Drupal\Core\Field\FieldStorageDefinitionListenerInterface
|
||||
*/
|
||||
protected $fieldStorageDefinitionListener;
|
||||
|
||||
/**
|
||||
* The field definition listener.
|
||||
*
|
||||
* @var \Drupal\Core\Field\FieldDefinitionListenerInterface
|
||||
*/
|
||||
protected $fieldDefinitionListener;
|
||||
|
||||
/**
|
||||
* Constructs a new BundlePluginInstaller object.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
|
||||
* The entity type manager.
|
||||
* @param \Drupal\Core\Entity\EntityBundleListenerInterface $entity_bundle_listener
|
||||
* The entity bundle listener.
|
||||
* @param \Drupal\Core\Field\FieldStorageDefinitionListenerInterface $field_storage_definition_listener
|
||||
* The field storage definition listener.
|
||||
* @param \Drupal\Core\Field\FieldDefinitionListenerInterface $field_definition_listener
|
||||
* The field definition listener.
|
||||
*/
|
||||
public function __construct(EntityTypeManagerInterface $entity_type_manager, EntityBundleListenerInterface $entity_bundle_listener, FieldStorageDefinitionListenerInterface $field_storage_definition_listener, FieldDefinitionListenerInterface $field_definition_listener) {
|
||||
$this->entityTypeManager = $entity_type_manager;
|
||||
$this->entityBundleListener = $entity_bundle_listener;
|
||||
$this->fieldStorageDefinitionListener = $field_storage_definition_listener;
|
||||
$this->fieldDefinitionListener = $field_definition_listener;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function installBundles(EntityTypeInterface $entity_type, array $modules) {
|
||||
$bundle_handler = $this->entityTypeManager->getHandler($entity_type->id(), 'bundle_plugin');
|
||||
$bundles = array_filter($bundle_handler->getBundleInfo(), function ($bundle_info) use ($modules) {
|
||||
return in_array($bundle_info['provider'], $modules, TRUE);
|
||||
});
|
||||
foreach (array_keys($bundles) as $bundle) {
|
||||
$this->entityBundleListener->onBundleCreate($bundle, $entity_type->id());
|
||||
foreach ($bundle_handler->getFieldDefinitions($bundle) as $definition) {
|
||||
$this->fieldStorageDefinitionListener->onFieldStorageDefinitionCreate($definition);
|
||||
$this->fieldDefinitionListener->onFieldDefinitionCreate($definition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function uninstallBundles(EntityTypeInterface $entity_type, array $modules) {
|
||||
$bundle_handler = $this->entityTypeManager->getHandler($entity_type->id(), 'bundle_plugin');
|
||||
$bundles = array_filter($bundle_handler->getBundleInfo(), function ($bundle_info) use ($modules) {
|
||||
return in_array($bundle_info['provider'], $modules, TRUE);
|
||||
});
|
||||
foreach (array_keys($bundles) as $bundle) {
|
||||
$this->entityBundleListener->onBundleDelete($bundle, $entity_type->id());
|
||||
foreach ($bundle_handler->getFieldDefinitions($bundle) as $definition) {
|
||||
$this->fieldDefinitionListener->onFieldDefinitionDelete($definition);
|
||||
$this->fieldStorageDefinitionListener->onFieldStorageDefinitionDelete($definition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\entity\BundlePlugin;
|
||||
|
||||
use Drupal\Core\Entity\EntityTypeInterface;
|
||||
|
||||
/**
|
||||
* Installs and uninstalls bundle plugins.
|
||||
*
|
||||
* Ensures that the fields provided by the bundle plugins are created/deleted.
|
||||
*/
|
||||
interface BundlePluginInstallerInterface {
|
||||
|
||||
/**
|
||||
* Installs the bundle plugins provided by the specified modules.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
|
||||
* The entity type.
|
||||
* @param array $modules
|
||||
* The modules.
|
||||
*/
|
||||
public function installBundles(EntityTypeInterface $entity_type, array $modules);
|
||||
|
||||
/**
|
||||
* Uninstalls the bundle plugins provided by the specified modules.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
|
||||
* The entity type.
|
||||
* @param array $modules
|
||||
* The modules.
|
||||
*/
|
||||
public function uninstallBundles(EntityTypeInterface $entity_type, array $modules);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\entity\BundlePlugin;
|
||||
|
||||
use Drupal\Component\Plugin\PluginInspectionInterface;
|
||||
|
||||
/**
|
||||
* Interface for plugins which act as entity bundles.
|
||||
*/
|
||||
interface BundlePluginInterface extends PluginInspectionInterface {
|
||||
|
||||
/**
|
||||
* Builds the field definitions for entities of this bundle.
|
||||
*
|
||||
* Important:
|
||||
* Field names must be unique across all bundles.
|
||||
* It is recommended to prefix them with the bundle name (plugin ID).
|
||||
*
|
||||
* @return \Drupal\entity\BundleFieldDefinition[]
|
||||
* An array of bundle field definitions, keyed by field name.
|
||||
*/
|
||||
public function buildFieldDefinitions();
|
||||
|
||||
}
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\entity\BundlePlugin;
|
||||
|
||||
use Drupal\Core\Entity\EntityTypeManagerInterface;
|
||||
use Drupal\Core\Extension\ModuleUninstallValidatorInterface;
|
||||
use Drupal\Core\StringTranslation\StringTranslationTrait;
|
||||
use Drupal\Core\StringTranslation\TranslationInterface;
|
||||
|
||||
/**
|
||||
* Prevents uninstalling modules with bundle plugins in case of found data.
|
||||
*/
|
||||
class BundlePluginUninstallValidator implements ModuleUninstallValidatorInterface {
|
||||
|
||||
use StringTranslationTrait;
|
||||
|
||||
/**
|
||||
* The entity type manager.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
|
||||
*/
|
||||
protected $entityTypeManager;
|
||||
|
||||
/**
|
||||
* Constructs the object.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
|
||||
* The entity type manager.
|
||||
* @param \Drupal\Core\StringTranslation\TranslationInterface $string_translation
|
||||
* The string translation service.
|
||||
*/
|
||||
public function __construct(EntityTypeManagerInterface $entity_type_manager, TranslationInterface $string_translation) {
|
||||
$this->entityTypeManager = $entity_type_manager;
|
||||
$this->stringTranslation = $string_translation;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validate($module) {
|
||||
$reasons = [];
|
||||
|
||||
foreach (entity_get_bundle_plugin_entity_types() as $entity_type) {
|
||||
/** @var \Drupal\entity\BundlePlugin\BundlePluginHandler $bundle_handler */
|
||||
$bundle_handler = $this->entityTypeManager->getHandler($entity_type->id(), 'bundle_plugin');
|
||||
$bundles = $bundle_handler->getBundleInfo();
|
||||
|
||||
// We find all bundles which have to be removed due to the uninstallation.
|
||||
$bundles_filtered_by_module = array_filter($bundles, function ($bundle_info) use ($module) {
|
||||
return $module === $bundle_info['provider'];
|
||||
});
|
||||
|
||||
if (!empty($bundles_filtered_by_module)) {
|
||||
$bundle_keys_with_content = array_filter(array_keys($bundles_filtered_by_module), function ($bundle) use ($entity_type) {
|
||||
$result = $this->entityTypeManager->getStorage($entity_type->id())->getQuery()
|
||||
->condition($entity_type->getKey('bundle'), $bundle)
|
||||
->range(0, 1)
|
||||
->execute();
|
||||
return !empty($result);
|
||||
});
|
||||
|
||||
$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'],
|
||||
'@entity_type' => $entity_type->getLabel(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $reasons;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -11,7 +11,6 @@ use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\Core\Render\RendererInterface;
|
||||
use Drupal\Core\Routing\RouteMatchInterface;
|
||||
use Drupal\Core\Entity\RevisionLogInterface;
|
||||
use Drupal\user\EntityOwnerInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
|
||||
@@ -5,16 +5,30 @@ 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\EntityPermissionProvider
|
||||
* @see \Drupal\entity\UncacheableEntityPermissionProvider
|
||||
*/
|
||||
class EntityAccessControlHandler extends CoreEntityAccessControlHandler {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __construct(EntityTypeInterface $entity_type) {
|
||||
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}");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
@@ -51,10 +65,18 @@ class EntityAccessControlHandler extends CoreEntityAccessControlHandler {
|
||||
* The access result.
|
||||
*/
|
||||
protected function checkEntityPermissions(EntityInterface $entity, $operation, AccountInterface $account) {
|
||||
return AccessResult::allowedIfHasPermissions($account, [
|
||||
"$operation {$entity->getEntityTypeId()}",
|
||||
"$operation {$entity->bundle()} {$entity->getEntityTypeId()}",
|
||||
], 'OR');
|
||||
if ($operation === 'view') {
|
||||
$permissions = [
|
||||
"view {$entity->getEntityTypeId()}"
|
||||
];
|
||||
}
|
||||
else {
|
||||
$permissions = [
|
||||
"$operation {$entity->getEntityTypeId()}",
|
||||
"$operation {$entity->bundle()} {$entity->getEntityTypeId()}",
|
||||
];
|
||||
}
|
||||
return AccessResult::allowedIfHasPermissions($account, $permissions, 'OR');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -72,23 +94,39 @@ class EntityAccessControlHandler extends CoreEntityAccessControlHandler {
|
||||
* 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');
|
||||
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();
|
||||
}
|
||||
return AccessResult::neutral()->cachePerUser();
|
||||
}
|
||||
else {
|
||||
return AccessResult::allowedIfHasPermissions($account, [
|
||||
"view {$entity->getEntityTypeId()}",
|
||||
]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
$result = AccessResult::allowedIfHasPermissions($account, [
|
||||
"$operation any {$entity->getEntityTypeId()}",
|
||||
"$operation any {$entity->bundle()} {$entity->getEntityTypeId()}",
|
||||
], 'OR');
|
||||
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;
|
||||
}
|
||||
|
||||
return $result->cachePerUser();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
namespace Drupal\entity;
|
||||
|
||||
use Drupal\Core\Entity\ContentEntityTypeInterface;
|
||||
use Drupal\Core\Entity\EntityHandlerInterface;
|
||||
use Drupal\Core\Entity\EntityPublishedInterface;
|
||||
use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
|
||||
use Drupal\Core\Entity\EntityTypeInterface;
|
||||
use Drupal\Core\StringTranslation\StringTranslationTrait;
|
||||
@@ -11,10 +11,21 @@ use Drupal\user\EntityOwnerInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Provides generic entity permissions.
|
||||
* Provides generic entity permissions which are still cacheable.
|
||||
*
|
||||
* Supports both entity_type and bundle granularities.
|
||||
* Supports entity ownership (own/any permissions).
|
||||
* This includes:
|
||||
*
|
||||
* - administer $entity_type
|
||||
* - access $entity_type overview
|
||||
* - view $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.
|
||||
*
|
||||
* Intended for content entity types, since config entity types usually rely
|
||||
* on a single "administer" permission.
|
||||
@@ -29,218 +40,26 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
* @see \Drupal\entity\EntityAccessControlHandler
|
||||
* @see \Drupal\entity\EntityPermissions
|
||||
*/
|
||||
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')
|
||||
);
|
||||
}
|
||||
class EntityPermissionProvider extends EntityPermissionProviderBase {
|
||||
|
||||
/**
|
||||
* {@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,
|
||||
];
|
||||
$permissions["access {$entity_type_id} overview"] = [
|
||||
'title' => $this->t('Access the @type overview page', ['@type' => $plural_label]),
|
||||
];
|
||||
$permissions = parent::buildPermissions($entity_type);
|
||||
|
||||
// View permissions are the same for both granularities.
|
||||
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 = [];
|
||||
$permissions["create {$entity_type_id}"] = [
|
||||
'title' => $this->t('Create @type', [
|
||||
$permissions["view {$entity_type_id}"] = [
|
||||
'title' => $this->t('View @type', [
|
||||
'@type' => $plural_label,
|
||||
]),
|
||||
];
|
||||
if ($has_owner) {
|
||||
$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["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;
|
||||
return $this->processPermissions($permissions, $entity_type);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
$permissions["create {$bundle_name} {$entity_type_id}"] = [
|
||||
'title' => $this->t('@bundle: Create @type', [
|
||||
'@bundle' => $bundle_info['label'],
|
||||
'@type' => $plural_label,
|
||||
]),
|
||||
];
|
||||
|
||||
if ($has_owner) {
|
||||
$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["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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,231 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\entity;
|
||||
|
||||
use Drupal\Core\Entity\EntityHandlerInterface;
|
||||
use Drupal\Core\Entity\EntityPublishedInterface;
|
||||
use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
|
||||
use Drupal\Core\Entity\EntityTypeInterface;
|
||||
use Drupal\Core\StringTranslation\StringTranslationTrait;
|
||||
use Drupal\user\EntityOwnerInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
class EntityPermissionProviderBase 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->entityClassImplements(EntityOwnerInterface::class);
|
||||
$plural_label = $entity_type->getPluralLabel();
|
||||
|
||||
$permissions = [];
|
||||
$permissions["administer {$entity_type_id}"] = [
|
||||
'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 ($has_owner && $entity_type->entityClassImplements(EntityPublishedInterface::class)) {
|
||||
$permissions["view own unpublished {$entity_type_id}"] = [
|
||||
'title' => $this->t('View own unpublished @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);
|
||||
}
|
||||
|
||||
return $this->processPermissions($permissions, $entity_type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the provider and converts the titles to strings to allow sorting.
|
||||
*
|
||||
* @param array $permissions
|
||||
* The array of permissions
|
||||
* @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
|
||||
* The entity type.
|
||||
*
|
||||
* @return array
|
||||
* An array of processed permissions.
|
||||
*/
|
||||
protected function processPermissions(array $permissions, EntityTypeInterface $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->entityClassImplements(EntityOwnerInterface::class);
|
||||
$singular_label = $entity_type->getSingularLabel();
|
||||
$plural_label = $entity_type->getPluralLabel();
|
||||
|
||||
$permissions = [];
|
||||
$permissions["create {$entity_type_id}"] = [
|
||||
'title' => $this->t('Create @type', [
|
||||
'@type' => $plural_label,
|
||||
]),
|
||||
];
|
||||
if ($has_owner) {
|
||||
$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["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->entityClassImplements(EntityOwnerInterface::class);
|
||||
$singular_label = $entity_type->getSingularLabel();
|
||||
$plural_label = $entity_type->getPluralLabel();
|
||||
|
||||
$permissions = [];
|
||||
foreach ($bundles as $bundle_name => $bundle_info) {
|
||||
$permissions["create {$bundle_name} {$entity_type_id}"] = [
|
||||
'title' => $this->t('@bundle: Create @type', [
|
||||
'@bundle' => $bundle_info['label'],
|
||||
'@type' => $plural_label,
|
||||
]),
|
||||
];
|
||||
|
||||
if ($has_owner) {
|
||||
$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["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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -10,6 +10,7 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
* Generates entity permissions via their permission providers.
|
||||
*
|
||||
* @see \Drupal\entity\EntityPermissionProvider
|
||||
* @see \Drupal\entity\UncacheableEntityPermissionProvider
|
||||
*/
|
||||
class EntityPermissions implements ContainerInjectionInterface {
|
||||
|
||||
|
||||
+1
-1
@@ -69,7 +69,7 @@ class DeleteActionDeriver extends DeriverBase implements ContainerDeriverInterfa
|
||||
protected function getParticipatingEntityTypes() {
|
||||
$entity_types = $this->entityTypeManager->getDefinitions();
|
||||
$entity_types = array_filter($entity_types, function (EntityTypeInterface $entity_type) {
|
||||
return $entity_type->isSubclassOf(ContentEntityInterface::class) && $entity_type->hasLinkTemplate('delete-multiple-form');
|
||||
return $entity_type->entityClassImplements(ContentEntityInterface::class) && $entity_type->hasLinkTemplate('delete-multiple-form');
|
||||
});
|
||||
|
||||
return $entity_types;
|
||||
|
||||
+3
-2
@@ -3,6 +3,7 @@
|
||||
namespace Drupal\entity\Plugin\Derivative;
|
||||
|
||||
use Drupal\Component\Plugin\Derivative\DeriverBase;
|
||||
use Drupal\Core\Entity\EntityTypeManagerInterface;
|
||||
use Drupal\Core\Plugin\Discovery\ContainerDeriverInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
@@ -24,7 +25,7 @@ class RevisionsOverviewDeriver extends DeriverBase implements ContainerDeriverIn
|
||||
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager
|
||||
* The entity type manager.
|
||||
*/
|
||||
public function __construct(\Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager) {
|
||||
public function __construct(EntityTypeManagerInterface $entityTypeManager) {
|
||||
$this->entityTypeManager = $entityTypeManager;
|
||||
}
|
||||
|
||||
@@ -55,7 +56,7 @@ class RevisionsOverviewDeriver extends DeriverBase implements ContainerDeriverIn
|
||||
|
||||
$this->derivatives[$entity_type_id] = [
|
||||
'route_name' => "entity.$entity_type_id.version_history",
|
||||
'title' => 'Revisions',
|
||||
'title' => t('Revisions'),
|
||||
'base_route' => "entity.$entity_type_id.canonical",
|
||||
'weight' => 20,
|
||||
] + $base_plugin_definition;
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
namespace Drupal\entity\Revision;
|
||||
|
||||
use Drupal\Core\Entity\RevisionableContentEntityBase as BaseRevisionableContentEntityBase;
|
||||
use Drupal\Core\Entity\ContentEntityBase;
|
||||
|
||||
/**
|
||||
* Improves the url route handling of core's revisionable content entity base.
|
||||
|
||||
@@ -0,0 +1,138 @@
|
||||
<?php
|
||||
|
||||
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.
|
||||
*
|
||||
* @see \Drupal\entity\UncacheableEntityPermissionProvider
|
||||
*
|
||||
* Note: this access control handler will cause pages to be cached per user.
|
||||
*/
|
||||
class UncacheableEntityAccessControlHandler extends CoreEntityAccessControlHandler {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __construct(EntityTypeInterface $entity_type) {
|
||||
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}");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@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()}",
|
||||
];
|
||||
}
|
||||
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');
|
||||
}
|
||||
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');
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\entity;
|
||||
|
||||
use Drupal\Core\Entity\EntityHandlerInterface;
|
||||
use Drupal\Core\Entity\EntityPublishedInterface;
|
||||
use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
|
||||
use Drupal\Core\Entity\EntityTypeInterface;
|
||||
use Drupal\Core\StringTranslation\StringTranslationTrait;
|
||||
use Drupal\user\EntityOwnerInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Provides generic entity permissions which are cached per user.
|
||||
*
|
||||
* This includes:
|
||||
*
|
||||
* - administer $entity_type
|
||||
* - access $entity_type overview
|
||||
* - view an ($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).
|
||||
*
|
||||
* Intended for content entity types, since config entity types usually rely
|
||||
* on a single "administer" permission.
|
||||
* Example annotation:
|
||||
* @code
|
||||
* handlers = {
|
||||
* "access" = "Drupal\entity\UncacheableEntityAccessControlHandler",
|
||||
* "permission_provider" = "Drupal\entity\UncacheableEntityPermissionProvider",
|
||||
* }
|
||||
* @endcode
|
||||
*
|
||||
* @see \Drupal\entity\EntityAccessControlHandler
|
||||
* @see \Drupal\entity\EntityPermissions
|
||||
*/
|
||||
class UncacheableEntityPermissionProvider extends EntityPermissionProviderBase {
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
$permissions = parent::buildEntityTypePermissions($entity_type);
|
||||
|
||||
$entity_type_id = $entity_type->id();
|
||||
$has_owner = $entity_type->entityClassImplements(EntityOwnerInterface::class);
|
||||
$plural_label = $entity_type->getPluralLabel();
|
||||
|
||||
if ($has_owner) {
|
||||
$permissions["view any {$entity_type_id}"] = [
|
||||
'title' => $this->t('View any @type', [
|
||||
'@type' => $plural_label,
|
||||
]),
|
||||
];
|
||||
$permissions["view own {$entity_type_id}"] = [
|
||||
'title' => $this->t('View own @type', [
|
||||
'@type' => $plural_label,
|
||||
]),
|
||||
];
|
||||
}
|
||||
else {
|
||||
$permissions["view any {$entity_type_id}"] = [
|
||||
'title' => $this->t('View any @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) {
|
||||
$permissions = parent::buildBundlePermissions($entity_type);
|
||||
$entity_type_id = $entity_type->id();
|
||||
$bundles = $this->entityTypeBundleInfo->getBundleInfo($entity_type_id);
|
||||
$has_owner = $entity_type->entityClassImplements(EntityOwnerInterface::class);
|
||||
$plural_label = $entity_type->getPluralLabel();
|
||||
|
||||
$permissions["view any {$entity_type_id}"] = [
|
||||
'title' => $this->t('View any @type', [
|
||||
'@type' => $plural_label,
|
||||
]),
|
||||
];
|
||||
if ($has_owner) {
|
||||
$permissions["view own {$entity_type_id}"] = [
|
||||
'title' => $this->t('View own @type', [
|
||||
'@type' => $plural_label,
|
||||
]),
|
||||
];
|
||||
}
|
||||
|
||||
foreach ($bundles as $bundle_name => $bundle_info) {
|
||||
if ($has_owner) {
|
||||
$permissions["view any {$bundle_name} {$entity_type_id}"] = [
|
||||
'title' => $this->t('@bundle: View any @type', [
|
||||
'@bundle' => $bundle_info['label'],
|
||||
'@type' => $plural_label,
|
||||
]),
|
||||
];
|
||||
$permissions["view own {$bundle_name} {$entity_type_id}"] = [
|
||||
'title' => $this->t('@bundle: View own @type', [
|
||||
'@bundle' => $bundle_info['label'],
|
||||
'@type' => $plural_label,
|
||||
]),
|
||||
];
|
||||
}
|
||||
else {
|
||||
$permissions["view any {$bundle_name} {$entity_type_id}"] = [
|
||||
'title' => $this->t('@bundle: View any @type', [
|
||||
'@bundle' => $bundle_info['label'],
|
||||
'@type' => $plural_label,
|
||||
]),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $permissions;
|
||||
}
|
||||
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
name: 'Entity bundle plugin examples test'
|
||||
type: module
|
||||
description: 'Module for testing bundle plugins.'
|
||||
package: Testing
|
||||
# core: 8.x
|
||||
dependencies:
|
||||
- entity
|
||||
|
||||
# Information added by Drupal.org packaging script on 2017-09-20
|
||||
version: '8.x-1.0-beta1'
|
||||
core: '8.x'
|
||||
project: 'entity'
|
||||
datestamp: 1505895847
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\entity_module_bundle_plugin_examples_test\Plugin\BundlePluginTest;
|
||||
|
||||
use Drupal\entity\BundleFieldDefinition;
|
||||
use Drupal\Core\Plugin\PluginBase;
|
||||
use Drupal\entity_module_bundle_plugin_test\Plugin\BundlePluginTest\BundlePluginTestInterface;
|
||||
|
||||
/**
|
||||
* Provides the second bundle plugin.
|
||||
*
|
||||
* @BundlePluginTest(
|
||||
* id = "second",
|
||||
* label = @Translation("Second"),
|
||||
* )
|
||||
*/
|
||||
class Second extends PluginBase implements BundlePluginTestInterface {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildFieldDefinitions() {
|
||||
$fields = [];
|
||||
$fields['second_mail'] = BundleFieldDefinition::create('email')
|
||||
->setLabel(t('Email'))
|
||||
->setRequired(TRUE);
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
name: 'Entity bundle plugin test'
|
||||
type: module
|
||||
description: 'Module for testing bundle plugins.'
|
||||
package: Testing
|
||||
# core: 8.x
|
||||
dependencies:
|
||||
- entity
|
||||
|
||||
# Information added by Drupal.org packaging script on 2017-09-20
|
||||
version: '8.x-1.0-beta1'
|
||||
core: '8.x'
|
||||
project: 'entity'
|
||||
datestamp: 1505895847
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
services:
|
||||
plugin.manager.bundle_plugin_test:
|
||||
class: Drupal\entity_module_bundle_plugin_test\BundlePluginTestManager
|
||||
parent: default_plugin_manager
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\entity_module_bundle_plugin_test\Annotation;
|
||||
|
||||
use Drupal\Component\Annotation\Plugin;
|
||||
|
||||
/**
|
||||
* Defines the BundlePluginTest annotation object.
|
||||
*
|
||||
* Plugin namespace: Plugin\BundlePluginTest.
|
||||
*
|
||||
* @see plugin_api
|
||||
*
|
||||
* @Annotation
|
||||
*/
|
||||
class BundlePluginTest extends Plugin {
|
||||
|
||||
/**
|
||||
* The plugin ID.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $id;
|
||||
|
||||
/**
|
||||
* The plugin label.
|
||||
*
|
||||
* @ingroup plugin_translatable
|
||||
*
|
||||
* @var \Drupal\Core\Annotation\Translation
|
||||
*/
|
||||
public $label;
|
||||
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\entity_module_bundle_plugin_test;
|
||||
|
||||
use Drupal\Core\Cache\CacheBackendInterface;
|
||||
use Drupal\Core\Extension\ModuleHandlerInterface;
|
||||
use Drupal\Core\Plugin\DefaultPluginManager;
|
||||
|
||||
/**
|
||||
* Manages discovery and instantiation of BundlePluginTest plugins.
|
||||
*
|
||||
* @see \Drupal\entity_module_bundle_plugin_test\Annotation\BundlePluginTest
|
||||
* @see plugin_api
|
||||
*/
|
||||
class BundlePluginTestManager extends DefaultPluginManager {
|
||||
|
||||
/**
|
||||
* Constructs a new BundlePluginTestManager object.
|
||||
*
|
||||
* @param \Traversable $namespaces
|
||||
* An object that implements \Traversable which contains the root paths
|
||||
* keyed by the corresponding namespace to look for plugin implementations.
|
||||
* @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend
|
||||
* The cache backend.
|
||||
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
|
||||
* The module handler.
|
||||
*/
|
||||
public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler) {
|
||||
parent::__construct('Plugin/BundlePluginTest', $namespaces, $module_handler, 'Drupal\entity_module_bundle_plugin_test\Plugin\BundlePluginTest\BundlePluginTestInterface', 'Drupal\entity_module_bundle_plugin_test\Annotation\BundlePluginTest');
|
||||
|
||||
$this->alterInfo('bundle_plugin_test_info');
|
||||
$this->setCacheBackend($cache_backend, 'bundle_plugin_test_plugins');
|
||||
}
|
||||
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\entity_module_bundle_plugin_test\Entity;
|
||||
|
||||
use Drupal\Core\Entity\ContentEntityBase;
|
||||
|
||||
/**
|
||||
* Defines the 'entity_test_bundle_plugin' entity class.
|
||||
*
|
||||
* @ContentEntityType(
|
||||
* id = "entity_test_bundle_plugin",
|
||||
* label = @Translation("Entity test bundle plugin"),
|
||||
* bundle_label = @Translation("Bundle Plugin Test"),
|
||||
* bundle_plugin_type = "bundle_plugin_test",
|
||||
* base_table = "entity_test_bundle_plugin",
|
||||
* admin_permission = "administer content",
|
||||
* fieldable = TRUE,
|
||||
* entity_keys = {
|
||||
* "id" = "method_id",
|
||||
* "uuid" = "uuid",
|
||||
* "bundle" = "type"
|
||||
* },
|
||||
* )
|
||||
*/
|
||||
class EntityTestBundlePlugin extends ContentEntityBase {
|
||||
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\entity_module_bundle_plugin_test\Plugin\BundlePluginTest;
|
||||
|
||||
use Drupal\entity\BundlePlugin\BundlePluginInterface;
|
||||
|
||||
/**
|
||||
* Defines the interface for BundlePluginTest plugins.
|
||||
*/
|
||||
interface BundlePluginTestInterface extends BundlePluginInterface {
|
||||
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\entity_module_bundle_plugin_test\Plugin\BundlePluginTest;
|
||||
|
||||
use Drupal\entity\BundleFieldDefinition;
|
||||
use Drupal\Core\Plugin\PluginBase;
|
||||
|
||||
/**
|
||||
* Provides the first bundle plugin.
|
||||
*
|
||||
* @BundlePluginTest(
|
||||
* id = "first",
|
||||
* label = @Translation("First"),
|
||||
* description = @Translation("Some description"),
|
||||
* )
|
||||
*/
|
||||
class First extends PluginBase implements BundlePluginTestInterface {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildFieldDefinitions() {
|
||||
$fields = [];
|
||||
$fields['first_mail'] = BundleFieldDefinition::create('email')
|
||||
->setLabel(t('Email'))
|
||||
->setRequired(TRUE);
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
}
|
||||
+4
-3
@@ -1,9 +1,10 @@
|
||||
name: Entity test
|
||||
type: module
|
||||
package: Testing
|
||||
# core: 8.x
|
||||
|
||||
# Information added by Drupal.org packaging script on 2016-12-08
|
||||
version: '8.x-1.0-alpha4'
|
||||
# Information added by Drupal.org packaging script on 2017-09-20
|
||||
version: '8.x-1.0-beta1'
|
||||
core: '8.x'
|
||||
project: 'entity'
|
||||
datestamp: 1481194986
|
||||
datestamp: 1505895847
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@ use Drupal\entity\Revision\RevisionableContentEntityBase;
|
||||
* label = @Translation("Entity test with enhancements"),
|
||||
* handlers = {
|
||||
* "storage" = "\Drupal\Core\Entity\Sql\SqlContentEntityStorage",
|
||||
* "access" = "\Drupal\entity\EntityAccessControlHandler",
|
||||
* "access" = "\Drupal\Core\Entity\EntityAccessControlHandler",
|
||||
* "permission_provider" = "\Drupal\entity\EntityPermissionProvider",
|
||||
* "form" = {
|
||||
* "add" = "\Drupal\entity\Form\RevisionableContentEntityForm",
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ namespace Drupal\Tests\entity\Functional;
|
||||
|
||||
use Drupal\entity_module_test\Entity\EnhancedEntity;
|
||||
use Drupal\entity_module_test\Entity\EnhancedEntityBundle;
|
||||
use Drupal\simpletest\BrowserTestBase;
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
|
||||
/**
|
||||
* Tests the delete multiple confirmation form.
|
||||
|
||||
@@ -0,0 +1,146 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\entity\Kernel;
|
||||
|
||||
use Drupal\entity_module_bundle_plugin_test\Entity\EntityTestBundlePlugin;
|
||||
use Drupal\KernelTests\KernelTestBase;
|
||||
|
||||
/**
|
||||
* Tests the bundle plugin API.
|
||||
*
|
||||
* @group entity
|
||||
*/
|
||||
class BundlePluginTest extends KernelTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = [
|
||||
'system',
|
||||
'entity',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->installSchema('system', 'router');
|
||||
|
||||
// Install the modules properly. Putting them into static::$modules doesn't trigger the install
|
||||
// hooks, like hook_modules_installed, so entity_modules_installed is not triggered().
|
||||
/** @var \Drupal\Core\Extension\ModuleInstallerInterface $module_installer */
|
||||
$module_installer = \Drupal::service('module_installer');
|
||||
$module_installer->install(['entity_module_bundle_plugin_test', 'entity_module_bundle_plugin_examples_test']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the bundle plugins.
|
||||
*/
|
||||
public function testPluginBundles() {
|
||||
$bundled_entity_types = entity_get_bundle_plugin_entity_types();
|
||||
/** @var \Drupal\Core\Entity\EntityTypeInterface $entity_type */
|
||||
$entity_type = $bundled_entity_types['entity_test_bundle_plugin'];
|
||||
$this->assertEquals('entity_test_bundle_plugin', $entity_type->id());
|
||||
$this->assertTrue($entity_type->hasHandlerClass('bundle_plugin'));
|
||||
|
||||
/** @var \Drupal\Core\Entity\EntityTypeBundleInfo $entity_type_bundle_info */
|
||||
$entity_type_bundle_info = \Drupal::service('entity_type.bundle.info');
|
||||
$bundle_info = $entity_type_bundle_info->getBundleInfo('entity_test_bundle_plugin');
|
||||
$this->assertEquals(2, count($bundle_info));
|
||||
$this->assertArrayHasKey('first', $bundle_info);
|
||||
$this->assertArrayHasKey('second', $bundle_info);
|
||||
$this->assertEquals('First', $bundle_info['first']['label']);
|
||||
$this->assertEquals('Some description', $bundle_info['first']['description']);
|
||||
|
||||
/** @var \Drupal\Core\Entity\EntityFieldManagerInterface $entity_field_manager */
|
||||
$entity_field_manager = \Drupal::service('entity_field.manager');
|
||||
$field_storage_definitions = $entity_field_manager->getFieldStorageDefinitions('entity_test_bundle_plugin');
|
||||
$this->assertArrayHasKey('first_mail', $field_storage_definitions);
|
||||
$this->assertArrayHasKey('second_mail', $field_storage_definitions);
|
||||
$first_field_definitions = $entity_field_manager->getFieldDefinitions('entity_test_bundle_plugin', 'first');
|
||||
$this->assertArrayHasKey('first_mail', $first_field_definitions);
|
||||
$this->assertArrayNotHasKey('second_mail', $first_field_definitions);
|
||||
$second_field_definitions = $entity_field_manager->getFieldDefinitions('entity_test_bundle_plugin', 'second');
|
||||
$this->assertArrayNotHasKey('first_mail', $second_field_definitions);
|
||||
$this->assertArrayHasKey('second_mail', $second_field_definitions);
|
||||
|
||||
$first_entity = EntityTestBundlePlugin::create([
|
||||
'type' => 'first',
|
||||
'first_mail' => 'admin@test.com',
|
||||
]);
|
||||
$first_entity->save();
|
||||
$first_entity = EntityTestBundlePlugin::load($first_entity->id());
|
||||
$this->assertEquals('admin@test.com', $first_entity->first_mail->value);
|
||||
|
||||
$second_entity = EntityTestBundlePlugin::create([
|
||||
'type' => 'second',
|
||||
'second_mail' => 'admin@example.com',
|
||||
]);
|
||||
$second_entity->save();
|
||||
$second_entity = EntityTestBundlePlugin::load($second_entity->id());
|
||||
$this->assertEquals('admin@example.com', $second_entity->second_mail->value);
|
||||
|
||||
// Also test entity queries.
|
||||
$result = \Drupal::entityTypeManager()->getStorage('entity_test_bundle_plugin')
|
||||
->getQuery()
|
||||
->condition('second_mail', 'admin@example.com')
|
||||
->execute();
|
||||
$this->assertEquals([$second_entity->id() => $second_entity->id()], $result);
|
||||
|
||||
$result = \Drupal::entityTypeManager()->getStorage('entity_test_bundle_plugin')
|
||||
->getQuery()
|
||||
->condition('type', 'first')
|
||||
->execute();
|
||||
$this->assertEquals([$first_entity->id() => $first_entity->id()], $result);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the uninstallation for a bundle provided by a module.
|
||||
*/
|
||||
public function testBundlePluginModuleUninstallation() {
|
||||
/** @var \Drupal\Core\Extension\ModuleInstallerInterface $module_installer */
|
||||
$module_installer = \Drupal::service('module_installer');
|
||||
|
||||
// One should be possible to uninstall without any actual content.
|
||||
$violations = $module_installer->validateUninstall(['entity_module_bundle_plugin_examples_test']);
|
||||
$this->assertEmpty($violations);
|
||||
|
||||
$first_entity = EntityTestBundlePlugin::create([
|
||||
'type' => 'first',
|
||||
'first_mail' => 'admin@test.com',
|
||||
]);
|
||||
$first_entity->save();
|
||||
$second_entity = EntityTestBundlePlugin::create([
|
||||
'type' => 'second',
|
||||
'second_mail' => 'admin@example.com',
|
||||
]);
|
||||
$second_entity->save();
|
||||
|
||||
$violations = $module_installer->validateUninstall(['entity_module_bundle_plugin_examples_test']);
|
||||
$this->assertCount(1, $violations);
|
||||
$this->assertCount(1, $violations['entity_module_bundle_plugin_examples_test']);
|
||||
$this->assertEquals('There is data for the bundle Second on the entity type Entity test bundle plugin. Please remove all content before uninstalling the module.', $violations['entity_module_bundle_plugin_examples_test'][0]);
|
||||
|
||||
$second_entity->delete();
|
||||
|
||||
// The first entity is defined by entity_module_bundle_plugin_test, so it should be possible
|
||||
// to uninstall the module providing the second bundle plugin.
|
||||
$violations = $module_installer->validateUninstall(['entity_module_bundle_plugin_examples_test']);
|
||||
$this->assertEmpty($violations);
|
||||
|
||||
$module_installer->uninstall(['entity_module_bundle_plugin_examples_test']);
|
||||
|
||||
// The first entity is provided by entity_module_bundle_plugin_test which we cannot uninstall,
|
||||
// until all the entities are deleted.
|
||||
$violations = $module_installer->validateUninstall(['entity_module_bundle_plugin_test']);
|
||||
$this->assertNotEmpty($violations);
|
||||
|
||||
$first_entity->delete();
|
||||
$violations = $module_installer->validateUninstall(['entity_module_bundle_plugin_test']);
|
||||
$this->assertEmpty($violations);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -57,22 +57,36 @@ class RevisionBasicUITest extends KernelTestBase {
|
||||
|
||||
/** @var \Symfony\Component\HttpKernel\HttpKernelInterface $http_kernel */
|
||||
$http_kernel = \Drupal::service('http_kernel');
|
||||
$request = Request::create($revision->url('version-history'));
|
||||
$request = Request::create($revision->toUrl('version-history')->toString());
|
||||
$response = $http_kernel->handle($request);
|
||||
$this->assertEquals(403, $response->getStatusCode());
|
||||
|
||||
$role_admin = Role::create(['id' => 'test_role_admin']);
|
||||
$role_admin->grantPermission('administer entity_test_enhanced');
|
||||
$role_admin->save();
|
||||
|
||||
$role = Role::create(['id' => 'test_role']);
|
||||
$role->grantPermission('view all entity_test_enhanced revisions');
|
||||
$role->grantPermission('administer entity_test_enhanced');
|
||||
$role->save();
|
||||
|
||||
$user_admin = User::create([
|
||||
'name' => 'Test user admin',
|
||||
]);
|
||||
$user_admin->addRole($role_admin->id());
|
||||
\Drupal::service('account_switcher')->switchTo($user_admin);
|
||||
|
||||
$request = Request::create($revision->toUrl('version-history')->toString());
|
||||
$response = $http_kernel->handle($request);
|
||||
$this->assertEquals(200, $response->getStatusCode());
|
||||
|
||||
$user = User::create([
|
||||
'name' => 'Test user',
|
||||
]);
|
||||
$user->addRole($role->id());
|
||||
\Drupal::service('account_switcher')->switchTo($user);
|
||||
|
||||
$request = Request::create($revision->url('version-history'));
|
||||
$request = Request::create($revision->toUrl('version-history')->toString());
|
||||
$response = $http_kernel->handle($request);
|
||||
$this->assertEquals(200, $response->getStatusCode());
|
||||
|
||||
@@ -87,7 +101,7 @@ class RevisionBasicUITest extends KernelTestBase {
|
||||
$revision->isDefaultRevision(TRUE);
|
||||
$revision->save();
|
||||
|
||||
$request = Request::create($revision->url('version-history'));
|
||||
$request = Request::create($revision->toUrl('version-history')->toString());
|
||||
$response = $http_kernel->handle($request);
|
||||
$this->assertEquals(200, $response->getStatusCode());
|
||||
|
||||
@@ -110,22 +124,36 @@ class RevisionBasicUITest extends KernelTestBase {
|
||||
|
||||
/** @var \Symfony\Component\HttpKernel\HttpKernelInterface $http_kernel */
|
||||
$http_kernel = \Drupal::service('http_kernel');
|
||||
$request = Request::create($revision->url('revision'));
|
||||
$request = Request::create($revision->toUrl('revision')->toString());
|
||||
$response = $http_kernel->handle($request);
|
||||
$this->assertEquals(403, $response->getStatusCode());
|
||||
|
||||
$role_admin = Role::create(['id' => 'test_role_admin']);
|
||||
$role_admin->grantPermission('administer entity_test_enhanced');
|
||||
$role_admin->save();
|
||||
|
||||
$role = Role::create(['id' => 'test_role']);
|
||||
$role->grantPermission('view all entity_test_enhanced revisions');
|
||||
$role->grantPermission('administer entity_test_enhanced');
|
||||
$role->save();
|
||||
|
||||
$user_admin = User::create([
|
||||
'name' => 'Test user admin',
|
||||
]);
|
||||
$user_admin->addRole($role_admin->id());
|
||||
\Drupal::service('account_switcher')->switchTo($user_admin);
|
||||
|
||||
$request = Request::create($revision->toUrl('version-history')->toString());
|
||||
$response = $http_kernel->handle($request);
|
||||
$this->assertEquals(200, $response->getStatusCode());
|
||||
|
||||
$user = User::create([
|
||||
'name' => 'Test user',
|
||||
]);
|
||||
$user->addRole($role->id());
|
||||
\Drupal::service('account_switcher')->switchTo($user);
|
||||
|
||||
$request = Request::create($revision->url('revision'));
|
||||
$request = Request::create($revision->toUrl('revision')->toString());
|
||||
$response = $http_kernel->handle($request);
|
||||
$this->assertEquals(200, $response->getStatusCode());
|
||||
$this->assertNotContains('rev 1', $response->getContent());
|
||||
@@ -156,7 +184,7 @@ class RevisionBasicUITest extends KernelTestBase {
|
||||
|
||||
/** @var \Symfony\Component\HttpKernel\HttpKernelInterface $http_kernel */
|
||||
$http_kernel = \Drupal::service('http_kernel');
|
||||
$request = Request::create($entity->url('revision-revert-form'));
|
||||
$request = Request::create($entity->toUrl('revision-revert-form')->toString());
|
||||
$response = $http_kernel->handle($request);
|
||||
$this->assertEquals(200, $response->getStatusCode());
|
||||
}
|
||||
|
||||
+54
-2
@@ -8,12 +8,14 @@ use Drupal\Core\DependencyInjection\ContainerBuilder;
|
||||
use Drupal\Core\Entity\ContentEntityInterface;
|
||||
use Drupal\Core\Entity\ContentEntityTypeInterface;
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\Core\Entity\EntityPublishedInterface;
|
||||
use Drupal\Core\Entity\EntityTypeInterface;
|
||||
use Drupal\Core\Extension\ModuleHandlerInterface;
|
||||
use Drupal\Core\Language\Language;
|
||||
use Drupal\Core\Language\LanguageInterface;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Drupal\entity\EntityAccessControlHandler;
|
||||
use Drupal\entity\EntityPermissionProvider;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
use Drupal\user\EntityOwnerInterface;
|
||||
use Prophecy\Argument;
|
||||
@@ -80,6 +82,8 @@ class EntityAccessControlHandlerTest extends UnitTestCase {
|
||||
$entity_type = $this->prophesize(ContentEntityTypeInterface::class);
|
||||
$entity_type->id()->willReturn('green_entity');
|
||||
$entity_type->getAdminPermission()->willReturn('administer green_entity');
|
||||
$entity_type->hasHandlerClass('permission_provider')->willReturn(TRUE);
|
||||
$entity_type->getHandlerClass('permission_provider')->willReturn(EntityPermissionProvider::class);
|
||||
|
||||
// User with the admin permission can do anything.
|
||||
$entity = $this->buildMockEntity($entity_type->reveal());
|
||||
@@ -126,6 +130,32 @@ class EntityAccessControlHandlerTest extends UnitTestCase {
|
||||
$data[] = [$entity->reveal(), 'update', $second_account->reveal(), FALSE];
|
||||
$data[] = [$entity->reveal(), 'update', $third_account->reveal(), TRUE];
|
||||
|
||||
// Test the unpublished permissions.
|
||||
$entity_first_other_up = $this->buildMockEntity($entity_type->reveal(), 9999, 'first', FALSE);
|
||||
$entity_first_own_up = $this->buildMockEntity($entity_type->reveal(), 14, 'first', FALSE);
|
||||
$entity_first_own_bundle_up = $this->buildMockEntity($entity_type->reveal(), 15, 'first', FALSE);
|
||||
|
||||
$entity_second_other_up = $this->buildMockEntity($entity_type->reveal(), 9999, 'second', FALSE);
|
||||
$entity_second_own_up = $this->buildMockEntity($entity_type->reveal(), 14, 'second', FALSE);
|
||||
$entity_second_own_bundle_up = $this->buildMockEntity($entity_type->reveal(), 15, 'second', FALSE);
|
||||
|
||||
$user_view_own_up = $this->buildMockUser(14, 'view own unpublished green_entity');
|
||||
$user_view_other = $this->buildMockUser(15, 'view green_entity');
|
||||
|
||||
$data['entity_first_other_up user_view_own_up'] = [$entity_first_other_up->reveal(), 'view', $user_view_own_up->reveal(), FALSE];
|
||||
$data['entity_first_own_up user_view_own_up'] = [$entity_first_own_up->reveal(), 'view', $user_view_own_up->reveal(), TRUE];
|
||||
$data['entity_first_own_bundle_up user_view_own_up'] = [$entity_first_own_bundle_up->reveal(), 'view', $user_view_own_up->reveal(), FALSE];
|
||||
$data['entity_second_other_up user_view_own_up'] = [$entity_second_other_up->reveal(), 'view', $user_view_own_up->reveal(), FALSE];
|
||||
$data['entity_second_own_up user_view_own_up'] = [$entity_second_own_up->reveal(), 'view', $user_view_own_up->reveal(), TRUE];
|
||||
$data['entity_second_own_bundle_up user_view_own_up'] = [$entity_second_own_bundle_up->reveal(), 'view', $user_view_own_up->reveal(), FALSE];
|
||||
|
||||
$data['entity_first_other_up user_view_other'] = [$entity_first_other_up->reveal(), 'view', $user_view_other->reveal(), FALSE];
|
||||
$data['entity_first_own_up user_view_other'] = [$entity_first_own_up->reveal(), 'view', $user_view_other->reveal(), FALSE];
|
||||
$data['entity_first_own_bundle_up user_view_other'] = [$entity_first_own_bundle_up->reveal(), 'view', $user_view_other->reveal(), FALSE];
|
||||
$data['entity_second_other_up user_view_other'] = [$entity_second_other_up->reveal(), 'view', $user_view_other->reveal(), FALSE];
|
||||
$data['entity_second_own_up user_view_other'] = [$entity_second_own_up->reveal(), 'view', $user_view_other->reveal(), FALSE];
|
||||
$data['entity_second_own_bundle_up user_view_other'] = [$entity_second_own_bundle_up->reveal(), 'view', $user_view_other->reveal(), FALSE];
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
@@ -141,6 +171,8 @@ class EntityAccessControlHandlerTest extends UnitTestCase {
|
||||
$entity_type = $this->prophesize(ContentEntityTypeInterface::class);
|
||||
$entity_type->id()->willReturn('green_entity');
|
||||
$entity_type->getAdminPermission()->willReturn('administer green_entity');
|
||||
$entity_type->hasHandlerClass('permission_provider')->willReturn(TRUE);
|
||||
$entity_type->getHandlerClass('permission_provider')->willReturn(EntityPermissionProvider::class);
|
||||
|
||||
// User with the admin permission.
|
||||
$account = $this->prophesize(AccountInterface::class);
|
||||
@@ -182,16 +214,27 @@ class EntityAccessControlHandlerTest extends UnitTestCase {
|
||||
* @return \Prophecy\Prophecy\ObjectProphecy
|
||||
* The entity mock.
|
||||
*/
|
||||
protected function buildMockEntity(EntityTypeInterface $entity_type, $owner_id = NULL) {
|
||||
protected function buildMockEntity(EntityTypeInterface $entity_type, $owner_id = NULL, $bundle = NULL, $published = NULL) {
|
||||
$langcode = LanguageInterface::LANGCODE_NOT_SPECIFIED;
|
||||
$entity = $this->prophesize(ContentEntityInterface::class);
|
||||
if (isset($published)) {
|
||||
$entity->willImplement(EntityPublishedInterface::class);
|
||||
}
|
||||
if ($owner_id) {
|
||||
$entity->willImplement(EntityOwnerInterface::class);
|
||||
}
|
||||
if (isset($published)) {
|
||||
$entity->isPublished()->willReturn($published);
|
||||
}
|
||||
if ($owner_id) {
|
||||
$entity->getOwnerId()->willReturn($owner_id);
|
||||
}
|
||||
$entity->bundle()->willReturn($entity_type->id());
|
||||
|
||||
$entity->bundle()->willReturn($bundle ?: $entity_type->id());
|
||||
$entity->isNew()->willReturn(FALSE);
|
||||
$entity->uuid()->willReturn('fake uuid');
|
||||
$entity->id()->willReturn('fake id');
|
||||
$entity->getRevisionId()->willReturn(NULL);
|
||||
$entity->language()->willReturn(new Language(['id' => $langcode]));
|
||||
$entity->getEntityTypeId()->willReturn($entity_type->id());
|
||||
$entity->getEntityType()->willReturn($entity_type);
|
||||
@@ -199,7 +242,16 @@ class EntityAccessControlHandlerTest extends UnitTestCase {
|
||||
$entity->getCacheTags()->willReturn([]);
|
||||
$entity->getCacheMaxAge()->willReturn(Cache::PERMANENT);
|
||||
|
||||
|
||||
return $entity;
|
||||
}
|
||||
|
||||
protected function buildMockUser($uid, $permission) {
|
||||
$account = $this->prophesize(AccountInterface::class);
|
||||
$account->id()->willReturn($uid);
|
||||
$account->hasPermission($permission)->willReturn(TRUE);
|
||||
$account->hasPermission(Argument::any())->willReturn(FALSE);
|
||||
return $account;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+38
-11
@@ -2,8 +2,8 @@
|
||||
|
||||
namespace Drupal\Tests\entity\Unit;
|
||||
|
||||
use Drupal\Core\Config\Entity\ConfigEntityTypeInterface;
|
||||
use Drupal\Core\Entity\ContentEntityTypeInterface;
|
||||
use Drupal\Core\Entity\EntityPublishedInterface;
|
||||
use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
|
||||
use Drupal\Core\Entity\EntityTypeInterface;
|
||||
use Drupal\entity\EntityPermissionProvider;
|
||||
@@ -37,6 +37,9 @@ class EntityPermissionProviderTest extends UnitTestCase {
|
||||
$entity_type_bundle_info->getBundleInfo('black_entity')->willReturn([
|
||||
'third' => ['label' => 'Third'],
|
||||
]);
|
||||
$entity_type_bundle_info->getBundleInfo('pink_entity')->willReturn([
|
||||
'third' => ['label' => 'Third'],
|
||||
]);
|
||||
$this->permissionProvider = new EntityPermissionProvider($entity_type_bundle_info->reveal());
|
||||
$this->permissionProvider->setStringTranslation($this->getStringTranslationStub());
|
||||
}
|
||||
@@ -69,15 +72,16 @@ class EntityPermissionProviderTest extends UnitTestCase {
|
||||
$entity_type->id()->willReturn('green_entity');
|
||||
$entity_type->getSingularLabel()->willReturn('green entity');
|
||||
$entity_type->getPluralLabel()->willReturn('green entities');
|
||||
$entity_type->isSubclassOf(EntityOwnerInterface::class)->willReturn(FALSE);
|
||||
$entity_type->entityClassImplements(EntityOwnerInterface::class)->willReturn(FALSE);
|
||||
$entity_type->entityClassImplements(EntityPublishedInterface::class)->willReturn(FALSE);
|
||||
$entity_type->getPermissionGranularity()->willReturn('entity_type');
|
||||
$expected_permissions = [
|
||||
'administer green_entity' => 'Administer green entities',
|
||||
'access green_entity overview' => 'Access the green entities overview page',
|
||||
'view green_entity' => 'View green entities',
|
||||
'create green_entity' => 'Create green entities',
|
||||
'update green_entity' => 'Update green entities',
|
||||
'delete green_entity' => 'Delete green entities',
|
||||
'view green_entity' => 'View green entities',
|
||||
];
|
||||
$data[] = [$entity_type->reveal(), $expected_permissions];
|
||||
|
||||
@@ -87,18 +91,18 @@ class EntityPermissionProviderTest extends UnitTestCase {
|
||||
$entity_type->id()->willReturn('blue_entity');
|
||||
$entity_type->getSingularLabel()->willReturn('blue entity');
|
||||
$entity_type->getPluralLabel()->willReturn('blue entities');
|
||||
$entity_type->isSubclassOf(EntityOwnerInterface::class)->willReturn(TRUE);
|
||||
$entity_type->entityClassImplements(EntityOwnerInterface::class)->willReturn(TRUE);
|
||||
$entity_type->entityClassImplements(EntityPublishedInterface::class)->willReturn(FALSE);
|
||||
$entity_type->getPermissionGranularity()->willReturn('entity_type');
|
||||
$expected_permissions = [
|
||||
'administer blue_entity' => 'Administer blue entities',
|
||||
'access blue_entity overview' => 'Access the blue entities overview page',
|
||||
'view any blue_entity' => 'View any blue entity',
|
||||
'view own blue_entity' => 'View own blue entities',
|
||||
'create blue_entity' => 'Create blue entities',
|
||||
'update any blue_entity' => 'Update any blue entity',
|
||||
'update own blue_entity' => 'Update own blue entities',
|
||||
'delete any blue_entity' => 'Delete any blue entity',
|
||||
'delete own blue_entity' => 'Delete own blue entities',
|
||||
'view blue_entity' => 'View blue entities',
|
||||
];
|
||||
$data[] = [$entity_type->reveal(), $expected_permissions];
|
||||
|
||||
@@ -108,18 +112,19 @@ class EntityPermissionProviderTest extends UnitTestCase {
|
||||
$entity_type->id()->willReturn('white_entity');
|
||||
$entity_type->getSingularLabel()->willReturn('white entity');
|
||||
$entity_type->getPluralLabel()->willReturn('white entities');
|
||||
$entity_type->isSubclassOf(EntityOwnerInterface::class)->willReturn(FALSE);
|
||||
$entity_type->entityClassImplements(EntityOwnerInterface::class)->willReturn(FALSE);
|
||||
$entity_type->entityClassImplements(EntityPublishedInterface::class)->willReturn(FALSE);
|
||||
$entity_type->getPermissionGranularity()->willReturn('bundle');
|
||||
$expected_permissions = [
|
||||
'administer white_entity' => 'Administer white entities',
|
||||
'access white_entity overview' => 'Access the white entities overview page',
|
||||
'view white_entity' => 'View white entities',
|
||||
'create first white_entity' => 'First: Create white entities',
|
||||
'update first white_entity' => 'First: Update white entities',
|
||||
'delete first white_entity' => 'First: Delete white entities',
|
||||
'create second white_entity' => 'Second: Create white entities',
|
||||
'update second white_entity' => 'Second: Update white entities',
|
||||
'delete second white_entity' => 'Second: Delete white entities',
|
||||
'view white_entity' => 'View white entities',
|
||||
];
|
||||
$data[] = [$entity_type->reveal(), $expected_permissions];
|
||||
|
||||
@@ -129,18 +134,40 @@ class EntityPermissionProviderTest extends UnitTestCase {
|
||||
$entity_type->id()->willReturn('black_entity');
|
||||
$entity_type->getSingularLabel()->willReturn('black entity');
|
||||
$entity_type->getPluralLabel()->willReturn('black entities');
|
||||
$entity_type->isSubclassOf(EntityOwnerInterface::class)->willReturn(TRUE);
|
||||
$entity_type->entityClassImplements(EntityOwnerInterface::class)->willReturn(TRUE);
|
||||
$entity_type->entityClassImplements(EntityPublishedInterface::class)->willReturn(FALSE);
|
||||
$entity_type->getPermissionGranularity()->willReturn('bundle');
|
||||
$expected_permissions = [
|
||||
'administer black_entity' => 'Administer black entities',
|
||||
'access black_entity overview' => 'Access the black entities overview page',
|
||||
'view any black_entity' => 'View any black entity',
|
||||
'view own black_entity' => 'View own black entities',
|
||||
'create third black_entity' => 'Third: Create black entities',
|
||||
'update any third black_entity' => 'Third: Update any black entity',
|
||||
'update own third black_entity' => 'Third: Update own black entities',
|
||||
'delete any third black_entity' => 'Third: Delete any black entity',
|
||||
'delete own third black_entity' => 'Third: Delete own black entities',
|
||||
'view black_entity' => 'View black entities',
|
||||
];
|
||||
$data[] = [$entity_type->reveal(), $expected_permissions];
|
||||
|
||||
// Content entity type with bundles and owner and entity published.
|
||||
$entity_type = $this->prophesize(ContentEntityTypeInterface::class);
|
||||
$entity_type->getProvider()->willReturn('entity_module_test');
|
||||
$entity_type->id()->willReturn('pink_entity');
|
||||
$entity_type->getSingularLabel()->willReturn('pink entity');
|
||||
$entity_type->getPluralLabel()->willReturn('pink entities');
|
||||
$entity_type->entityClassImplements(EntityOwnerInterface::class)->willReturn(TRUE);
|
||||
$entity_type->entityClassImplements(EntityPublishedInterface::class)->willReturn(TRUE);
|
||||
$entity_type->getPermissionGranularity()->willReturn('bundle');
|
||||
$expected_permissions = [
|
||||
'administer pink_entity' => 'Administer pink entities',
|
||||
'access pink_entity overview' => 'Access the pink entities overview page',
|
||||
'view own unpublished pink_entity' => 'View own unpublished pink entities',
|
||||
'create third pink_entity' => 'Third: Create pink entities',
|
||||
'update any third pink_entity' => 'Third: Update any pink entity',
|
||||
'update own third pink_entity' => 'Third: Update own pink entities',
|
||||
'delete any third pink_entity' => 'Third: Delete any pink entity',
|
||||
'delete own third pink_entity' => 'Third: Delete own pink entities',
|
||||
'view pink_entity' => 'View pink entities',
|
||||
];
|
||||
$data[] = [$entity_type->reveal(), $expected_permissions];
|
||||
|
||||
|
||||
+299
@@ -0,0 +1,299 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\entity\Unit;
|
||||
|
||||
use Drupal\Core\Cache\Cache;
|
||||
use Drupal\Core\Cache\Context\CacheContextsManager;
|
||||
use Drupal\Core\DependencyInjection\ContainerBuilder;
|
||||
use Drupal\Core\Entity\ContentEntityInterface;
|
||||
use Drupal\Core\Entity\ContentEntityTypeInterface;
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\Core\Entity\EntityPublishedInterface;
|
||||
use Drupal\Core\Entity\EntityTypeInterface;
|
||||
use Drupal\Core\Extension\ModuleHandlerInterface;
|
||||
use Drupal\Core\Language\Language;
|
||||
use Drupal\Core\Language\LanguageInterface;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Drupal\entity\UncacheableEntityAccessControlHandler;
|
||||
use Drupal\entity\UncacheableEntityPermissionProvider;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
use Drupal\user\EntityOwnerInterface;
|
||||
use Prophecy\Argument;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \Drupal\entity\EntityAccessControlHandler
|
||||
* @group entity
|
||||
*/
|
||||
class UncacheableEntityAccessControlHandlerTest extends UnitTestCase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$module_handler = $this->prophesize(ModuleHandlerInterface::class);
|
||||
$module_handler->invokeAll(Argument::any(), Argument::any())->willReturn([]);
|
||||
$cache_contexts_manager = $this->prophesize(CacheContextsManager::class);
|
||||
$cache_contexts_manager->assertValidTokens(Argument::any())->willReturn(TRUE);
|
||||
|
||||
$container = new ContainerBuilder();
|
||||
$container->set('module_handler', $module_handler->reveal());
|
||||
$container->set('cache_contexts_manager', $cache_contexts_manager->reveal());
|
||||
\Drupal::setContainer($container);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::checkAccess
|
||||
* @covers ::checkEntityPermissions
|
||||
* @covers ::checkEntityOwnerPermissions
|
||||
* @covers ::checkCreateAccess
|
||||
*
|
||||
* @dataProvider accessProvider
|
||||
*/
|
||||
public function testAccess(EntityInterface $entity, $operation, $account, $allowed) {
|
||||
$handler = new UncacheableEntityAccessControlHandler($entity->getEntityType());
|
||||
$handler->setStringTranslation($this->getStringTranslationStub());
|
||||
$result = $handler->access($entity, $operation, $account);
|
||||
$this->assertEquals($allowed, $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::checkCreateAccess
|
||||
*
|
||||
* @dataProvider createAccessProvider
|
||||
*/
|
||||
public function testCreateAccess(EntityTypeInterface $entity_type, $bundle, $account, $allowed) {
|
||||
$handler = new UncacheableEntityAccessControlHandler($entity_type);
|
||||
$handler->setStringTranslation($this->getStringTranslationStub());
|
||||
$result = $handler->createAccess($bundle, $account);
|
||||
$this->assertEquals($allowed, $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider for testAccess().
|
||||
*
|
||||
* @return array
|
||||
* A list of testAccess method arguments.
|
||||
*/
|
||||
public function accessProvider() {
|
||||
$data = [];
|
||||
|
||||
$entity_type = $this->prophesize(ContentEntityTypeInterface::class);
|
||||
$entity_type->id()->willReturn('green_entity');
|
||||
$entity_type->getAdminPermission()->willReturn('administer green_entity');
|
||||
$entity_type->hasHandlerClass('permission_provider')->willReturn(TRUE);
|
||||
$entity_type->getHandlerClass('permission_provider')->willReturn(UncacheableEntityPermissionProvider::class);
|
||||
|
||||
// User with the admin permission can do anything.
|
||||
$entity = $this->buildMockEntity($entity_type->reveal());
|
||||
$account = $this->prophesize(AccountInterface::class);
|
||||
$account->id()->willReturn(6);
|
||||
$account->hasPermission('administer green_entity')->willReturn(TRUE);
|
||||
$data[] = [$entity->reveal(), 'view', $account->reveal(), TRUE];
|
||||
$data[] = [$entity->reveal(), 'update', $account->reveal(), TRUE];
|
||||
$data[] = [$entity->reveal(), 'delete', $account->reveal(), TRUE];
|
||||
|
||||
// Entity with no owner.
|
||||
$entity = $this->buildMockEntity($entity_type->reveal());
|
||||
// User who has access.
|
||||
$first_account = $this->prophesize(AccountInterface::class);
|
||||
$first_account->id()->willReturn(6);
|
||||
$first_account->hasPermission('view green_entity')->willReturn(TRUE);
|
||||
$first_account->hasPermission(Argument::any())->willReturn(FALSE);
|
||||
// User who doesn't have access.
|
||||
$second_account = $this->prophesize(AccountInterface::class);
|
||||
$second_account->id()->willReturn(7);
|
||||
$second_account->hasPermission('view green_entity')->willReturn(FALSE);
|
||||
$second_account->hasPermission(Argument::any())->willReturn(FALSE);
|
||||
$data[] = [$entity->reveal(), 'view', $first_account->reveal(), TRUE];
|
||||
$data[] = [$entity->reveal(), 'view', $second_account->reveal(), FALSE];
|
||||
|
||||
// Entity with owner.
|
||||
$entity = $this->buildMockEntity($entity_type->reveal(), 6);
|
||||
// Owner.
|
||||
$first_account = $this->prophesize(AccountInterface::class);
|
||||
$first_account->id()->willReturn(6);
|
||||
$first_account->hasPermission('update own green_entity')->willReturn(TRUE);
|
||||
$first_account->hasPermission(Argument::any())->willReturn(FALSE);
|
||||
// Non-owner.
|
||||
$second_account = $this->prophesize(AccountInterface::class);
|
||||
$second_account->id()->willReturn(7);
|
||||
$second_account->hasPermission('update own green_entity')->willReturn(TRUE);
|
||||
$second_account->hasPermission(Argument::any())->willReturn(FALSE);
|
||||
// User who can update any.
|
||||
$third_account = $this->prophesize(AccountInterface::class);
|
||||
$third_account->id()->willReturn(8);
|
||||
$third_account->hasPermission('update any green_entity')->willReturn(TRUE);
|
||||
$third_account->hasPermission(Argument::any())->willReturn(FALSE);
|
||||
$data[] = [$entity->reveal(), 'update', $first_account->reveal(), TRUE];
|
||||
$data[] = [$entity->reveal(), 'update', $second_account->reveal(), FALSE];
|
||||
$data[] = [$entity->reveal(), 'update', $third_account->reveal(), TRUE];
|
||||
|
||||
// Per bundle permissions.
|
||||
$entity_first_other = $this->buildMockEntity($entity_type->reveal(), 9999, 'first');
|
||||
$entity_first_own = $this->buildMockEntity($entity_type->reveal(), 10, 'first');
|
||||
$entity_first_own_bundle = $this->buildMockEntity($entity_type->reveal(), 12, 'first');
|
||||
|
||||
$entity_second_other = $this->buildMockEntity($entity_type->reveal(), 9999, 'second');
|
||||
$entity_second_own = $this->buildMockEntity($entity_type->reveal(), 10, 'second');
|
||||
$entity_second_own_bundle = $this->buildMockEntity($entity_type->reveal(), 12, 'second');
|
||||
|
||||
$user_view_any = $this->buildMockUser(9, 'view any green_entity');
|
||||
$user_view_own = $this->buildMockUser(10, 'view own green_entity');
|
||||
$user_view_bundle_any = $this->buildMockUser(11, 'view any first green_entity');
|
||||
$user_view_bundle_own = $this->buildMockUser(12, 'view own first green_entity');
|
||||
|
||||
$data['entity_first_other user_view_any'] = [$entity_first_other->reveal(), 'view', $user_view_any->reveal(), TRUE];
|
||||
$data['entity_first_own user_view_any'] = [$entity_first_own->reveal(), 'view', $user_view_any->reveal(), TRUE];
|
||||
$data['entity_first_own_bundle user_view_any'] = [$entity_first_own_bundle->reveal(), 'view', $user_view_any->reveal(), TRUE];
|
||||
$data['entity_second_other user_view_any'] = [$entity_second_other->reveal(), 'view', $user_view_any->reveal(), TRUE];
|
||||
$data['entity_second_own user_view_any'] = [$entity_second_own->reveal(), 'view', $user_view_any->reveal(), TRUE];
|
||||
$data['entity_second_own_bundle user_view_any'] = [$entity_second_own_bundle->reveal(), 'view', $user_view_any->reveal(), TRUE];
|
||||
|
||||
$data['entity_first_other user_view_own'] = [$entity_first_other->reveal(), 'view', $user_view_own->reveal(), FALSE];
|
||||
$data['entity_first_own user_view_own'] = [$entity_first_own->reveal(), 'view', $user_view_own->reveal(), TRUE];
|
||||
$data['entity_first_own_bundle user_view_own'] = [$entity_first_own_bundle->reveal(), 'view', $user_view_own->reveal(), FALSE];
|
||||
$data['entity_second_other user_view_own'] = [$entity_second_other->reveal(), 'view', $user_view_own->reveal(), FALSE];
|
||||
$data['entity_second_own user_view_own'] = [$entity_second_own->reveal(), 'view', $user_view_own->reveal(), TRUE];
|
||||
$data['entity_second_own_bundle user_view_own'] = [$entity_second_own_bundle->reveal(), 'view', $user_view_own->reveal(), FALSE];
|
||||
|
||||
$data['entity_first_other user_view_bundle_any'] = [$entity_first_other->reveal(), 'view', $user_view_bundle_any->reveal(), TRUE];
|
||||
$data['entity_first_own user_view_bundle_any'] = [$entity_first_own->reveal(), 'view', $user_view_bundle_any->reveal(), TRUE];
|
||||
$data['entity_first_own_bundle user_view_bundle_any'] = [$entity_first_own_bundle->reveal(), 'view', $user_view_bundle_any->reveal(), TRUE];
|
||||
$data['entity_second_other user_view_bundle_any'] = [$entity_second_other->reveal(), 'view', $user_view_bundle_any->reveal(), FALSE];
|
||||
$data['entity_second_own user_view_bundle_any'] = [$entity_second_own->reveal(), 'view', $user_view_bundle_any->reveal(), FALSE];
|
||||
$data['entity_second_own_bundle user_view_bundle_any'] = [$entity_second_own_bundle->reveal(), 'view', $user_view_bundle_any->reveal(), FALSE];
|
||||
|
||||
$data['entity_first_other user_view_bundle_any'] = [$entity_first_other->reveal(), 'view', $user_view_bundle_own->reveal(), FALSE];
|
||||
$data['entity_first_own user_view_bundle_any'] = [$entity_first_own->reveal(), 'view', $user_view_bundle_own->reveal(), FALSE];
|
||||
$data['entity_first_own_bundle user_view_bundle_any'] = [$entity_first_own_bundle->reveal(), 'view', $user_view_bundle_own->reveal(), TRUE];
|
||||
$data['entity_second_other user_view_bundle_any'] = [$entity_second_other->reveal(), 'view', $user_view_bundle_own->reveal(), FALSE];
|
||||
$data['entity_second_own user_view_bundle_any'] = [$entity_second_own->reveal(), 'view', $user_view_bundle_own->reveal(), FALSE];
|
||||
$data['entity_second_own_bundle user_view_bundle_any'] = [$entity_second_own_bundle->reveal(), 'view', $user_view_bundle_own->reveal(), FALSE];
|
||||
|
||||
// Test the unpublished permissions.
|
||||
$entity_first_other_up = $this->buildMockEntity($entity_type->reveal(), 9999, 'first', FALSE);
|
||||
$entity_first_own_up = $this->buildMockEntity($entity_type->reveal(), 14, 'first', FALSE);
|
||||
$entity_first_own_bundle_up = $this->buildMockEntity($entity_type->reveal(), 15, 'first', FALSE);
|
||||
|
||||
$entity_second_other_up = $this->buildMockEntity($entity_type->reveal(), 9999, 'second', FALSE);
|
||||
$entity_second_own_up = $this->buildMockEntity($entity_type->reveal(), 14, 'second', FALSE);
|
||||
$entity_second_own_bundle_up = $this->buildMockEntity($entity_type->reveal(), 15, 'second', FALSE);
|
||||
|
||||
$user_view_own_up = $this->buildMockUser(14, 'view own unpublished green_entity');
|
||||
$user_view_other = $this->buildMockUser(15, 'view green_entity');
|
||||
|
||||
$data['entity_first_other_up user_view_own_up'] = [$entity_first_other_up->reveal(), 'view', $user_view_own_up->reveal(), FALSE];
|
||||
$data['entity_first_own_up user_view_own_up'] = [$entity_first_own_up->reveal(), 'view', $user_view_own_up->reveal(), TRUE];
|
||||
$data['entity_first_own_bundle_up user_view_own_up'] = [$entity_first_own_bundle_up->reveal(), 'view', $user_view_own_up->reveal(), FALSE];
|
||||
$data['entity_second_other_up user_view_own_up'] = [$entity_second_other_up->reveal(), 'view', $user_view_own_up->reveal(), FALSE];
|
||||
$data['entity_second_own_up user_view_own_up'] = [$entity_second_own_up->reveal(), 'view', $user_view_own_up->reveal(), TRUE];
|
||||
$data['entity_second_own_bundle_up user_view_own_up'] = [$entity_second_own_bundle_up->reveal(), 'view', $user_view_own_up->reveal(), FALSE];
|
||||
|
||||
$data['entity_first_other_up user_view_other'] = [$entity_first_other_up->reveal(), 'view', $user_view_other->reveal(), FALSE];
|
||||
$data['entity_first_own_up user_view_other'] = [$entity_first_own_up->reveal(), 'view', $user_view_other->reveal(), FALSE];
|
||||
$data['entity_first_own_bundle_up user_view_other'] = [$entity_first_own_bundle_up->reveal(), 'view', $user_view_other->reveal(), FALSE];
|
||||
$data['entity_second_other_up user_view_other'] = [$entity_second_other_up->reveal(), 'view', $user_view_other->reveal(), FALSE];
|
||||
$data['entity_second_own_up user_view_other'] = [$entity_second_own_up->reveal(), 'view', $user_view_other->reveal(), FALSE];
|
||||
$data['entity_second_own_bundle_up user_view_other'] = [$entity_second_own_bundle_up->reveal(), 'view', $user_view_other->reveal(), FALSE];
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider for testCreateAccess().
|
||||
*
|
||||
* @return array
|
||||
* A list of testCreateAccess method arguments.
|
||||
*/
|
||||
public function createAccessProvider() {
|
||||
$data = [];
|
||||
|
||||
$entity_type = $this->prophesize(ContentEntityTypeInterface::class);
|
||||
$entity_type->id()->willReturn('green_entity');
|
||||
$entity_type->getAdminPermission()->willReturn('administer green_entity');
|
||||
$entity_type->hasHandlerClass('permission_provider')->willReturn(TRUE);
|
||||
$entity_type->getHandlerClass('permission_provider')->willReturn(UncacheableEntityPermissionProvider::class);
|
||||
|
||||
// User with the admin permission.
|
||||
$account = $this->prophesize(AccountInterface::class);
|
||||
$account->id()->willReturn(6);
|
||||
$account->hasPermission('administer green_entity')->willReturn(TRUE);
|
||||
$data[] = [$entity_type->reveal(), NULL, $account->reveal(), TRUE];
|
||||
|
||||
// Ordinary user.
|
||||
$account = $this->prophesize(AccountInterface::class);
|
||||
$account->id()->willReturn(6);
|
||||
$account->hasPermission('create green_entity')->willReturn(TRUE);
|
||||
$account->hasPermission(Argument::any())->willReturn(FALSE);
|
||||
$data[] = [$entity_type->reveal(), NULL, $account->reveal(), TRUE];
|
||||
|
||||
// Ordinary user, entity with a bundle.
|
||||
$account = $this->prophesize(AccountInterface::class);
|
||||
$account->id()->willReturn(6);
|
||||
$account->hasPermission('create first_bundle green_entity')->willReturn(TRUE);
|
||||
$account->hasPermission(Argument::any())->willReturn(FALSE);
|
||||
$data[] = [$entity_type->reveal(), 'first_bundle', $account->reveal(), TRUE];
|
||||
|
||||
// User with no permissions.
|
||||
$account = $this->prophesize(AccountInterface::class);
|
||||
$account->id()->willReturn(6);
|
||||
$account->hasPermission(Argument::any())->willReturn(FALSE);
|
||||
$data[] = [$entity_type->reveal(), NULL, $account->reveal(), FALSE];
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a mock entity.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
|
||||
* The entity type.
|
||||
* @param string $owner_id
|
||||
* The owner ID.
|
||||
*
|
||||
* @return \Prophecy\Prophecy\ObjectProphecy
|
||||
* The entity mock.
|
||||
*/
|
||||
protected function buildMockEntity(EntityTypeInterface $entity_type, $owner_id = NULL, $bundle = NULL, $published = NULL) {
|
||||
$langcode = LanguageInterface::LANGCODE_NOT_SPECIFIED;
|
||||
$entity = $this->prophesize(ContentEntityInterface::class);
|
||||
if (isset($published)) {
|
||||
$entity->willImplement(EntityPublishedInterface::class);
|
||||
}
|
||||
if ($owner_id) {
|
||||
$entity->willImplement(EntityOwnerInterface::class);
|
||||
}
|
||||
if (isset($published)) {
|
||||
$entity->isPublished()->willReturn($published);
|
||||
}
|
||||
if ($owner_id) {
|
||||
$entity->getOwnerId()->willReturn($owner_id);
|
||||
}
|
||||
|
||||
$entity->bundle()->willReturn($bundle ?: $entity_type->id());
|
||||
$entity->isNew()->willReturn(FALSE);
|
||||
$entity->uuid()->willReturn('fake uuid');
|
||||
$entity->id()->willReturn('fake id');
|
||||
$entity->getRevisionId()->willReturn(NULL);
|
||||
$entity->language()->willReturn(new Language(['id' => $langcode]));
|
||||
$entity->getEntityTypeId()->willReturn($entity_type->id());
|
||||
$entity->getEntityType()->willReturn($entity_type);
|
||||
$entity->getCacheContexts()->willReturn([]);
|
||||
$entity->getCacheTags()->willReturn([]);
|
||||
$entity->getCacheMaxAge()->willReturn(Cache::PERMANENT);
|
||||
|
||||
|
||||
return $entity;
|
||||
}
|
||||
|
||||
protected function buildMockUser($uid, $permission) {
|
||||
$account = $this->prophesize(AccountInterface::class);
|
||||
$account->id()->willReturn($uid);
|
||||
$account->hasPermission($permission)->willReturn(TRUE);
|
||||
$account->hasPermission(Argument::any())->willReturn(FALSE);
|
||||
return $account;
|
||||
}
|
||||
|
||||
}
|
||||
+186
@@ -0,0 +1,186 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\entity\Unit;
|
||||
|
||||
use Drupal\Core\Entity\ContentEntityTypeInterface;
|
||||
use Drupal\Core\Entity\EntityPublishedInterface;
|
||||
use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
|
||||
use Drupal\Core\Entity\EntityTypeInterface;
|
||||
use Drupal\entity\UncacheableEntityPermissionProvider;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
use Drupal\user\EntityOwnerInterface;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \Drupal\entity\UncacheableEntityPermissionProvider
|
||||
* @group entity
|
||||
*/
|
||||
class UncacheableEntityPermissionProviderTest extends UnitTestCase {
|
||||
|
||||
/**
|
||||
* The entity permission provider.
|
||||
*
|
||||
* @var \Drupal\entity\EntityPermissionProviderInterface
|
||||
*/
|
||||
protected $permissionProvider;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$entity_type_bundle_info = $this->prophesize(EntityTypeBundleInfoInterface::class);
|
||||
$entity_type_bundle_info->getBundleInfo('white_entity')->willReturn([
|
||||
'first' => ['label' => 'First'],
|
||||
'second' => ['label' => 'Second'],
|
||||
]);
|
||||
$entity_type_bundle_info->getBundleInfo('black_entity')->willReturn([
|
||||
'third' => ['label' => 'Third'],
|
||||
]);
|
||||
$entity_type_bundle_info->getBundleInfo('pink_entity')->willReturn([
|
||||
'third' => ['label' => 'Third'],
|
||||
]);
|
||||
$this->permissionProvider = new UncacheableEntityPermissionProvider($entity_type_bundle_info->reveal());
|
||||
$this->permissionProvider->setStringTranslation($this->getStringTranslationStub());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::buildPermissions
|
||||
*
|
||||
* @dataProvider entityTypeProvider
|
||||
*/
|
||||
public function testBuildPermissions(EntityTypeInterface $entity_type, array $expected_permissions) {
|
||||
$permissions = $this->permissionProvider->buildPermissions($entity_type);
|
||||
$this->assertEquals(array_keys($expected_permissions), array_keys($permissions));
|
||||
foreach ($permissions as $name => $permission) {
|
||||
$this->assertEquals('entity_module_test', $permission['provider']);
|
||||
$this->assertEquals($expected_permissions[$name], $permission['title']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider for testBuildPermissions().
|
||||
*
|
||||
* @return array
|
||||
* A list of testBuildPermissions method arguments.
|
||||
*/
|
||||
public function entityTypeProvider() {
|
||||
$data = [];
|
||||
// Content entity type.
|
||||
$entity_type = $this->prophesize(ContentEntityTypeInterface::class);
|
||||
$entity_type->getProvider()->willReturn('entity_module_test');
|
||||
$entity_type->id()->willReturn('green_entity');
|
||||
$entity_type->getSingularLabel()->willReturn('green entity');
|
||||
$entity_type->getPluralLabel()->willReturn('green entities');
|
||||
$entity_type->entityClassImplements(EntityOwnerInterface::class)->willReturn(FALSE);
|
||||
$entity_type->entityClassImplements(EntityPublishedInterface::class)->willReturn(FALSE);
|
||||
$entity_type->getPermissionGranularity()->willReturn('entity_type');
|
||||
$expected_permissions = [
|
||||
'administer green_entity' => 'Administer green entities',
|
||||
'access green_entity overview' => 'Access the green entities overview page',
|
||||
'create green_entity' => 'Create green entities',
|
||||
'update green_entity' => 'Update green entities',
|
||||
'delete green_entity' => 'Delete green entities',
|
||||
'view any green_entity' => 'View any green entities',
|
||||
];
|
||||
$data[] = [$entity_type->reveal(), $expected_permissions];
|
||||
|
||||
// Content entity type with owner.
|
||||
$entity_type = $this->prophesize(ContentEntityTypeInterface::class);
|
||||
$entity_type->getProvider()->willReturn('entity_module_test');
|
||||
$entity_type->id()->willReturn('blue_entity');
|
||||
$entity_type->getSingularLabel()->willReturn('blue entity');
|
||||
$entity_type->getPluralLabel()->willReturn('blue entities');
|
||||
$entity_type->entityClassImplements(EntityOwnerInterface::class)->willReturn(TRUE);
|
||||
$entity_type->entityClassImplements(EntityPublishedInterface::class)->willReturn(FALSE);
|
||||
$entity_type->getPermissionGranularity()->willReturn('entity_type');
|
||||
$expected_permissions = [
|
||||
'administer blue_entity' => 'Administer blue entities',
|
||||
'access blue_entity overview' => 'Access the blue entities overview page',
|
||||
'create blue_entity' => 'Create blue entities',
|
||||
'update any blue_entity' => 'Update any blue entity',
|
||||
'update own blue_entity' => 'Update own blue entities',
|
||||
'delete any blue_entity' => 'Delete any blue entity',
|
||||
'delete own blue_entity' => 'Delete own blue entities',
|
||||
'view any blue_entity' => 'View any blue entities',
|
||||
'view own blue_entity' => 'View own blue entities',
|
||||
];
|
||||
$data[] = [$entity_type->reveal(), $expected_permissions];
|
||||
|
||||
// Content entity type with bundles.
|
||||
$entity_type = $this->prophesize(ContentEntityTypeInterface::class);
|
||||
$entity_type->getProvider()->willReturn('entity_module_test');
|
||||
$entity_type->id()->willReturn('white_entity');
|
||||
$entity_type->getSingularLabel()->willReturn('white entity');
|
||||
$entity_type->getPluralLabel()->willReturn('white entities');
|
||||
$entity_type->entityClassImplements(EntityOwnerInterface::class)->willReturn(FALSE);
|
||||
$entity_type->entityClassImplements(EntityPublishedInterface::class)->willReturn(FALSE);
|
||||
$entity_type->getPermissionGranularity()->willReturn('bundle');
|
||||
$expected_permissions = [
|
||||
'administer white_entity' => 'Administer white entities',
|
||||
'access white_entity overview' => 'Access the white entities overview page',
|
||||
'create first white_entity' => 'First: Create white entities',
|
||||
'update first white_entity' => 'First: Update white entities',
|
||||
'delete first white_entity' => 'First: Delete white entities',
|
||||
'create second white_entity' => 'Second: Create white entities',
|
||||
'update second white_entity' => 'Second: Update white entities',
|
||||
'delete second white_entity' => 'Second: Delete white entities',
|
||||
'view any white_entity' => 'View any white entities',
|
||||
'view any first white_entity' => 'First: View any white entities',
|
||||
'view any second white_entity' => 'Second: View any white entities',
|
||||
];
|
||||
$data[] = [$entity_type->reveal(), $expected_permissions];
|
||||
|
||||
// Content entity type with bundles and owner.
|
||||
$entity_type = $this->prophesize(ContentEntityTypeInterface::class);
|
||||
$entity_type->getProvider()->willReturn('entity_module_test');
|
||||
$entity_type->id()->willReturn('black_entity');
|
||||
$entity_type->getSingularLabel()->willReturn('black entity');
|
||||
$entity_type->getPluralLabel()->willReturn('black entities');
|
||||
$entity_type->entityClassImplements(EntityOwnerInterface::class)->willReturn(TRUE);
|
||||
$entity_type->entityClassImplements(EntityPublishedInterface::class)->willReturn(FALSE);
|
||||
$entity_type->getPermissionGranularity()->willReturn('bundle');
|
||||
$expected_permissions = [
|
||||
'administer black_entity' => 'Administer black entities',
|
||||
'access black_entity overview' => 'Access the black entities overview page',
|
||||
'create third black_entity' => 'Third: Create black entities',
|
||||
'update any third black_entity' => 'Third: Update any black entity',
|
||||
'update own third black_entity' => 'Third: Update own black entities',
|
||||
'delete any third black_entity' => 'Third: Delete any black entity',
|
||||
'delete own third black_entity' => 'Third: Delete own black entities',
|
||||
'view any black_entity' => 'View any black entities',
|
||||
'view own black_entity' => 'View own black entities',
|
||||
'view any third black_entity' => 'Third: View any black entities',
|
||||
'view own third black_entity' => 'Third: View own black entities',
|
||||
];
|
||||
$data[] = [$entity_type->reveal(), $expected_permissions];
|
||||
|
||||
// Content entity type with bundles and owner and entity published.
|
||||
$entity_type = $this->prophesize(ContentEntityTypeInterface::class);
|
||||
$entity_type->getProvider()->willReturn('entity_module_test');
|
||||
$entity_type->id()->willReturn('pink_entity');
|
||||
$entity_type->getSingularLabel()->willReturn('pink entity');
|
||||
$entity_type->getPluralLabel()->willReturn('pink entities');
|
||||
$entity_type->entityClassImplements(EntityOwnerInterface::class)->willReturn(TRUE);
|
||||
$entity_type->entityClassImplements(EntityPublishedInterface::class)->willReturn(TRUE);
|
||||
$entity_type->getPermissionGranularity()->willReturn('bundle');
|
||||
$expected_permissions = [
|
||||
'administer pink_entity' => 'Administer pink entities',
|
||||
'access pink_entity overview' => 'Access the pink entities overview page',
|
||||
'view own unpublished pink_entity' => 'View own unpublished pink entities',
|
||||
'create third pink_entity' => 'Third: Create pink entities',
|
||||
'update any third pink_entity' => 'Third: Update any pink entity',
|
||||
'update own third pink_entity' => 'Third: Update own pink entities',
|
||||
'delete any third pink_entity' => 'Third: Delete any pink entity',
|
||||
'delete own third pink_entity' => 'Third: Delete own pink entities',
|
||||
'view any pink_entity' => 'View any pink entities',
|
||||
'view own pink_entity' => 'View own pink entities',
|
||||
'view any third pink_entity' => 'Third: View any pink entities',
|
||||
'view own third pink_entity' => 'Third: View own pink entities',
|
||||
];
|
||||
$data[] = [$entity_type->reveal(), $expected_permissions];
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user