Skip to content
Snippets Groups Projects
Commit bea5c2f0 authored by Jeroen Tubex's avatar Jeroen Tubex
Browse files

Issue #3213622 by JeroenT: Add access check to formatters

parent 0fab5b39
No related branches found
No related tags found
No related merge requests found
......@@ -3,9 +3,12 @@
namespace Drupal\pluginreference\Plugin\Field\FieldFormatter;
use Drupal\Core\Cache\CacheableMetadata;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Field\FormatterBase;
use Drupal\Core\Plugin\PluginBase;
use Drupal\Core\Session\AccountInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Plugin implementation of the 'plugin_reference_id' formatter.
......@@ -20,6 +23,38 @@ use Drupal\Core\Plugin\PluginBase;
*/
class PluginReferenceIdFormatter extends FormatterBase {
/**
* The current user.
*
* @var \Drupal\Core\Session\AccountInterface
*/
protected $currentUser;
/**
* {@inheritdoc}
*/
public function __construct($plugin_id, $plugin_definition, FieldDefinitionInterface $field_definition, array $settings, $label, $view_mode, array $third_party_settings, AccountInterface $current_user) {
parent::__construct($plugin_id, $plugin_definition, $field_definition, $settings, $label, $view_mode, $third_party_settings);
$this->currentUser = $current_user;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static(
$plugin_id,
$plugin_definition,
$configuration['field_definition'],
$configuration['settings'],
$configuration['label'],
$configuration['view_mode'],
$configuration['third_party_settings'],
$container->get('current_user')
);
}
/**
* {@inheritdoc}
*/
......@@ -32,6 +67,18 @@ class PluginReferenceIdFormatter extends FormatterBase {
continue;
}
// Check access when the plugin has an access method.
if (method_exists($plugin, 'access')) {
$access = $plugin->access($this->currentUser->getAccount(), TRUE);
CacheableMetadata::createFromRenderArray($elements)
->addCacheableDependency($access)
->applyTo($elements);
if (!$access->isAllowed()) {
continue;
}
}
$elements[$delta] = [
'#markup' => $plugin->getPluginId(),
];
......
......@@ -3,8 +3,12 @@
namespace Drupal\pluginreference\Plugin\Field\FieldFormatter;
use Drupal\Core\Cache\CacheableMetadata;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Field\FormatterBase;
use Drupal\Core\Plugin\PluginBase;
use Drupal\Core\Session\AccountInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Plugin implementation of the 'plugin_reference_label' formatter.
......@@ -17,7 +21,39 @@ use Drupal\Core\Plugin\PluginBase;
* }
* )
*/
class PluginReferenceLabelFormatter extends PluginReferenceIdFormatter {
class PluginReferenceLabelFormatter extends FormatterBase {
/**
* The current user.
*
* @var \Drupal\Core\Session\AccountInterface
*/
protected $currentUser;
/**
* {@inheritdoc}
*/
public function __construct($plugin_id, $plugin_definition, FieldDefinitionInterface $field_definition, array $settings, $label, $view_mode, array $third_party_settings, AccountInterface $current_user) {
parent::__construct($plugin_id, $plugin_definition, $field_definition, $settings, $label, $view_mode, $third_party_settings);
$this->currentUser = $current_user;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static(
$plugin_id,
$plugin_definition,
$configuration['field_definition'],
$configuration['settings'],
$configuration['label'],
$configuration['view_mode'],
$configuration['third_party_settings'],
$container->get('current_user')
);
}
/**
* {@inheritdoc}
......@@ -31,6 +67,18 @@ class PluginReferenceLabelFormatter extends PluginReferenceIdFormatter {
continue;
}
// Check access when the plugin has an access method.
if (method_exists($plugin, 'access')) {
$access = $plugin->access($this->currentUser->getAccount(), TRUE);
CacheableMetadata::createFromRenderArray($elements)
->addCacheableDependency($access)
->applyTo($elements);
if (!$access->isAllowed()) {
continue;
}
}
$elements[$delta] = [
'#markup' => method_exists($plugin, 'label') ? $plugin->label() : $plugin->getPluginDefinition()['label'] ?? NULL,
];
......
view plugin reference test access block:
title: 'View the plugin reference test access block'
<?php
namespace Drupal\pluginreference_test\Plugin\Block;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Block\BlockBase;
use Drupal\Core\Session\AccountInterface;
/**
* Provides a plugin reference test caching block.
*
* @Block(
* id = "plugin_reference_test_access_block",
* admin_label = @Translation("Test access block"),
* )
*/
class PluginReferenceTestAccessBlock extends BlockBase {
/**
* {@inheritdoc}
*/
public function build() {
return 'TEST';
}
/**
* {@inheritdoc}
*/
protected function blockAccess(AccountInterface $account) {
return AccessResult::allowedIfHasPermission($account, 'view plugin reference test access block');
}
}
......@@ -162,7 +162,7 @@ class PluginReferenceFieldWidgetConfigurationTest extends WebDriverTestBase {
$page->findField('title[0][value]')->setValue('Test pluginreference');
$plugin_id_field = $assert_session->fieldExists(sprintf('%s[0][plugin_id]', $this->fieldName));
$plugin_id_field->setValue('test');
$plugin_id_field->setValue('test block');
$plugin_id_field->keyDown(' ');
$assert_session->waitOnAutocomplete()->click();
......@@ -192,7 +192,7 @@ class PluginReferenceFieldWidgetConfigurationTest extends WebDriverTestBase {
$page->findField('title[0][value]')->setValue('Test pluginreference 2');
$plugin_id_field = $assert_session->fieldExists(sprintf('%s[0][plugin_id]', $this->fieldName));
$plugin_id_field->setValue('test');
$plugin_id_field->setValue('test block');
$plugin_id_field->keyDown(' ');
$assert_session->waitOnAutocomplete()->click();
......
......@@ -6,6 +6,7 @@ use Drupal\Core\Cache\CacheableMetadata;
use Drupal\Core\Entity\FieldableEntityInterface;
use Drupal\KernelTests\KernelTestBase;
use Drupal\Tests\pluginreference\Traits\PluginReferenceTrait;
use Drupal\user\RoleInterface;
/**
* Test the pluginreference formatter functionality.
......@@ -52,7 +53,7 @@ class PluginReferenceFieldFormatterTest extends KernelTestBase {
protected function setUp(): void {
parent::setUp();
$this->installConfig(['field']);
$this->installConfig(['field', 'user']);
$this->installEntitySchema('entity_test');
$this->entityTypeManager = $this->container->get('entity_type.manager');
......@@ -230,6 +231,60 @@ class PluginReferenceFieldFormatterTest extends KernelTestBase {
];
}
/**
* Test access of plugins in the field formatters.
*
* @dataProvider accessDataProvider
*/
public function testAccess(string $formatter) {
$user_role_storage = $this->entityTypeManager->getStorage('user_role');
$anonymous_role = $user_role_storage->load(RoleInterface::ANONYMOUS_ID);
$anonymous_role->grantPermission('view plugin reference test access block');
$anonymous_role->save();
$field_name = mb_strtolower($this->randomMachineName());
$this->createPluginReferenceField('entity_test', 'entity_test', $field_name, 'block');
$entity = $this->entityTypeManager->getStorage('entity_test')->create([]);
$entity->set($field_name, [
'plugin_id' => 'plugin_reference_test_access_block',
]);
$build = $this->buildEntityField($entity, $field_name, $formatter);
// The user has access, check if the plugin is present in the renderable
// array.
$this->assertArrayHasKey(0, $build);
$expected_cacheability_metadata = [
'contexts' => ['user.permissions'],
];
$this->assertEquals(CacheableMetadata::createFromRenderArray(['#cache' => $expected_cacheability_metadata]), CacheableMetadata::createFromRenderArray($build));
// Revoke permission so the user no longer has access to the plugin.
$anonymous_role->revokePermission('view plugin reference test access block');
$anonymous_role->save();
// The user has no access to the plugin. Check if the plugin is removed from
// the renderable array.
$build = $this->buildEntityField($entity, $field_name, 'plugin_reference_label');
$this->assertArrayNotHasKey(0, $build);
$this->assertEquals(CacheableMetadata::createFromRenderArray(['#cache' => $expected_cacheability_metadata]), CacheableMetadata::createFromRenderArray($build));
}
/**
* Provides test cases for ::testAccess.
*/
public function accessDataProvider() {
return [
[
'plugin_reference_id',
],
[
'plugin_reference_label',
],
];
}
/**
* Helper method that builds a renderable array for a given entity field.
*
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment