summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFrancesco Placella2018-07-27 09:09:33 (GMT)
committerFrancesco Placella2018-07-27 09:10:36 (GMT)
commit80818954e65f6dca74082d451137554ef865b740 (patch)
treefde8b9fc58c44c6f23920edc06f4b267a19f1b1d
parent80d7332e3cc7649fa02abe9b0eb3e4c2b688c03f (diff)
Issue #2981887 by amateescu, joachim, jibran, chr.fritsch, Manuel Garcia, timmillwood, plach, Wim Leers, Gábor Hojtsy, Berdir, jojototh, pameeela, dawehner, catch, Bojhan, Fabianx, Jo Fitzgerald: Add a publishing status to taxonomy terms
(cherry picked from commit 543b3f4ed3b00da642c98660e4a4072feceada75)
-rw-r--r--core/modules/rest/tests/src/Functional/EntityResource/XmlEntityNormalizationQuirksTrait.php4
-rw-r--r--core/modules/system/tests/src/Functional/Entity/EntityReferenceSelection/EntityReferenceSelectionAccessTest.php151
-rw-r--r--core/modules/taxonomy/src/Entity/Term.php12
-rw-r--r--core/modules/taxonomy/src/Plugin/EntityReferenceSelection/TermSelection.php66
-rw-r--r--core/modules/taxonomy/src/TermAccessControlHandler.php26
-rw-r--r--core/modules/taxonomy/src/TermInterface.php3
-rw-r--r--core/modules/taxonomy/taxonomy.install49
-rw-r--r--core/modules/taxonomy/taxonomy.post_update.php107
-rw-r--r--core/modules/taxonomy/tests/fixtures/update/drupal-8.views-taxonomy-term-publishing-status-2981887.php32
-rw-r--r--core/modules/taxonomy/tests/fixtures/update/views.view.test_taxonomy_term_view_with_content_translation_status.yml250
-rw-r--r--core/modules/taxonomy/tests/fixtures/update/views.view.test_taxonomy_term_view_without_content_translation_status.yml128
-rw-r--r--core/modules/taxonomy/tests/src/Functional/Rest/TermResourceTestBase.php16
-rw-r--r--core/modules/taxonomy/tests/src/Functional/TermAccessTest.php124
-rw-r--r--core/modules/taxonomy/tests/src/Functional/Update/TaxonomyTermUpdatePathTest.php132
14 files changed, 1091 insertions, 9 deletions
diff --git a/core/modules/rest/tests/src/Functional/EntityResource/XmlEntityNormalizationQuirksTrait.php b/core/modules/rest/tests/src/Functional/EntityResource/XmlEntityNormalizationQuirksTrait.php
index 3064ea3..a7e588a 100644
--- a/core/modules/rest/tests/src/Functional/EntityResource/XmlEntityNormalizationQuirksTrait.php
+++ b/core/modules/rest/tests/src/Functional/EntityResource/XmlEntityNormalizationQuirksTrait.php
@@ -14,6 +14,7 @@ use Drupal\image\Plugin\Field\FieldType\ImageItem;
use Drupal\options\Plugin\Field\FieldType\ListIntegerItem;
use Drupal\path\Plugin\Field\FieldType\PathItem;
use Drupal\Tests\rest\Functional\XmlNormalizationQuirksTrait;
+use Drupal\user\StatusItem;
/**
* Trait for EntityResourceTestBase subclasses testing $format='xml'.
@@ -63,6 +64,9 @@ trait XmlEntityNormalizationQuirksTrait {
for ($i = 0; $i < count($normalization[$field_name]); $i++) {
switch ($field->getItemDefinition()->getClass()) {
case BooleanItem::class:
+ case StatusItem::class:
+ // @todo Remove the StatusItem case in
+ // https://www.drupal.org/project/drupal/issues/2936864.
$value = &$normalization[$field_name][$i]['value'];
$value = $value === TRUE ? '1' : '0';
break;
diff --git a/core/modules/system/tests/src/Functional/Entity/EntityReferenceSelection/EntityReferenceSelectionAccessTest.php b/core/modules/system/tests/src/Functional/Entity/EntityReferenceSelection/EntityReferenceSelectionAccessTest.php
index aac7f39..c037d12 100644
--- a/core/modules/system/tests/src/Functional/Entity/EntityReferenceSelection/EntityReferenceSelectionAccessTest.php
+++ b/core/modules/system/tests/src/Functional/Entity/EntityReferenceSelection/EntityReferenceSelectionAccessTest.php
@@ -8,6 +8,8 @@ use Drupal\Core\Language\LanguageInterface;
use Drupal\comment\CommentInterface;
use Drupal\KernelTests\KernelTestBase;
use Drupal\node\Entity\Node;
+use Drupal\taxonomy\Entity\Term;
+use Drupal\taxonomy\Entity\Vocabulary;
use Drupal\node\NodeInterface;
use Drupal\Tests\node\Traits\ContentTypeCreationTrait;
use Drupal\Tests\user\Traits\UserCreationTrait;
@@ -30,7 +32,7 @@ class EntityReferenceSelectionAccessTest extends KernelTestBase {
*
* @var array
*/
- public static $modules = ['comment', 'field', 'node', 'system', 'text', 'user'];
+ public static $modules = ['comment', 'field', 'node', 'system', 'taxonomy', 'text', 'user'];
/**
* {@inheritdoc}
@@ -43,9 +45,10 @@ class EntityReferenceSelectionAccessTest extends KernelTestBase {
$this->installEntitySchema('comment');
$this->installEntitySchema('node');
+ $this->installEntitySchema('taxonomy_term');
$this->installEntitySchema('user');
- $this->installConfig(['comment', 'field', 'node', 'user']);
+ $this->installConfig(['comment', 'field', 'node', 'taxonomy', 'user']);
// Create the anonymous and the admin users.
$anonymous_user = User::create([
@@ -534,4 +537,148 @@ class EntityReferenceSelectionAccessTest extends KernelTestBase {
$this->assertReferenceable($selection_options, $referenceable_tests, 'Comment handler (comment + node admin)');
}
+ /**
+ * Test the term-specific overrides of the selection handler.
+ */
+ public function testTermHandler() {
+ // Create a 'Tags' vocabulary.
+ Vocabulary::create([
+ 'name' => 'Tags',
+ 'description' => $this->randomMachineName(),
+ 'vid' => 'tags',
+ ])->save();
+
+ $selection_options = [
+ 'target_type' => 'taxonomy_term',
+ 'handler' => 'default',
+ 'target_bundles' => NULL,
+ ];
+
+ // Build a set of test data.
+ $term_values = [
+ 'published1' => [
+ 'vid' => 'tags',
+ 'status' => 1,
+ 'name' => 'Term published1',
+ ],
+ 'published2' => [
+ 'vid' => 'tags',
+ 'status' => 1,
+ 'name' => 'Term published2',
+ ],
+ 'unpublished' => [
+ 'vid' => 'tags',
+ 'status' => 0,
+ 'name' => 'Term unpublished',
+ ],
+ 'published3' => [
+ 'vid' => 'tags',
+ 'status' => 1,
+ 'name' => 'Term published3',
+ 'parent' => 'unpublished',
+ ],
+ 'published4' => [
+ 'vid' => 'tags',
+ 'status' => 1,
+ 'name' => 'Term published4',
+ 'parent' => 'published3',
+ ],
+ ];
+
+ $terms = [];
+ $term_labels = [];
+ foreach ($term_values as $key => $values) {
+ $term = Term::create($values);
+ if (isset($values['parent'])) {
+ $term->parent->entity = $terms[$values['parent']];
+ }
+ $term->save();
+ $terms[$key] = $term;
+ $term_labels[$key] = Html::escape($term->label());
+ }
+
+ // Test as a non-admin.
+ $normal_user = $this->createUser(['access content']);
+ $this->setCurrentUser($normal_user);
+ $referenceable_tests = [
+ [
+ 'arguments' => [
+ [NULL, 'CONTAINS'],
+ ],
+ 'result' => [
+ 'tags' => [
+ $terms['published1']->id() => $term_labels['published1'],
+ $terms['published2']->id() => $term_labels['published2'],
+ ],
+ ],
+ ],
+ [
+ 'arguments' => [
+ ['published1', 'CONTAINS'],
+ ['Published1', 'CONTAINS'],
+ ],
+ 'result' => [
+ 'tags' => [
+ $terms['published1']->id() => $term_labels['published1'],
+ ],
+ ],
+ ],
+ [
+ 'arguments' => [
+ ['published2', 'CONTAINS'],
+ ['Published2', 'CONTAINS'],
+ ],
+ 'result' => [
+ 'tags' => [
+ $terms['published2']->id() => $term_labels['published2'],
+ ],
+ ],
+ ],
+ [
+ 'arguments' => [
+ ['invalid term', 'CONTAINS'],
+ ],
+ 'result' => [],
+ ],
+ [
+ 'arguments' => [
+ ['Term unpublished', 'CONTAINS'],
+ ],
+ 'result' => [],
+ ],
+ ];
+ $this->assertReferenceable($selection_options, $referenceable_tests, 'Term handler');
+
+ // Test as an admin.
+ $admin_user = $this->createUser(['access content', 'administer taxonomy']);
+ $this->setCurrentUser($admin_user);
+ $referenceable_tests = [
+ [
+ 'arguments' => [
+ [NULL, 'CONTAINS'],
+ ],
+ 'result' => [
+ 'tags' => [
+ $terms['published1']->id() => $term_labels['published1'],
+ $terms['published2']->id() => $term_labels['published2'],
+ $terms['unpublished']->id() => $term_labels['unpublished'],
+ $terms['published3']->id() => '-' . $term_labels['published3'],
+ $terms['published4']->id() => '--' . $term_labels['published4'],
+ ],
+ ],
+ ],
+ [
+ 'arguments' => [
+ ['Term unpublished', 'CONTAINS'],
+ ],
+ 'result' => [
+ 'tags' => [
+ $terms['unpublished']->id() => $term_labels['unpublished'],
+ ],
+ ],
+ ],
+ ];
+ $this->assertReferenceable($selection_options, $referenceable_tests, 'Term handler (admin)');
+ }
+
}
diff --git a/core/modules/taxonomy/src/Entity/Term.php b/core/modules/taxonomy/src/Entity/Term.php
index 77cefcc..8fc3ced 100644
--- a/core/modules/taxonomy/src/Entity/Term.php
+++ b/core/modules/taxonomy/src/Entity/Term.php
@@ -4,10 +4,12 @@ namespace Drupal\taxonomy\Entity;
use Drupal\Core\Entity\ContentEntityBase;
use Drupal\Core\Entity\EntityChangedTrait;
+use Drupal\Core\Entity\EntityPublishedTrait;
use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Field\BaseFieldDefinition;
use Drupal\taxonomy\TermInterface;
+use Drupal\user\StatusItem;
/**
* Defines the taxonomy term entity.
@@ -45,7 +47,8 @@ use Drupal\taxonomy\TermInterface;
* "bundle" = "vid",
* "label" = "name",
* "langcode" = "langcode",
- * "uuid" = "uuid"
+ * "uuid" = "uuid",
+ * "published" = "status",
* },
* bundle_entity_type = "taxonomy_vocabulary",
* field_ui_base_route = "entity.taxonomy_vocabulary.overview_form",
@@ -62,6 +65,7 @@ use Drupal\taxonomy\TermInterface;
class Term extends ContentEntityBase implements TermInterface {
use EntityChangedTrait;
+ use EntityPublishedTrait;
/**
* {@inheritdoc}
@@ -116,6 +120,12 @@ class Term extends ContentEntityBase implements TermInterface {
/** @var \Drupal\Core\Field\BaseFieldDefinition[] $fields */
$fields = parent::baseFieldDefinitions($entity_type);
+ // Add the published field.
+ $fields += static::publishedBaseFieldDefinitions($entity_type);
+ // @todo Remove the usage of StatusItem in
+ // https://www.drupal.org/project/drupal/issues/2936864.
+ $fields['status']->getItemDefinition()->setClass(StatusItem::class);
+
$fields['tid']->setLabel(t('Term ID'))
->setDescription(t('The term ID.'));
diff --git a/core/modules/taxonomy/src/Plugin/EntityReferenceSelection/TermSelection.php b/core/modules/taxonomy/src/Plugin/EntityReferenceSelection/TermSelection.php
index a312111..0592250 100644
--- a/core/modules/taxonomy/src/Plugin/EntityReferenceSelection/TermSelection.php
+++ b/core/modules/taxonomy/src/Plugin/EntityReferenceSelection/TermSelection.php
@@ -59,10 +59,17 @@ class TermSelection extends DefaultSelection {
$bundles = $this->entityManager->getBundleInfo('taxonomy_term');
$bundle_names = $this->getConfiguration()['target_bundles'] ?: array_keys($bundles);
+ $has_admin_access = $this->currentUser->hasPermission('administer taxonomy');
+ $unpublished_terms = [];
foreach ($bundle_names as $bundle) {
if ($vocabulary = Vocabulary::load($bundle)) {
+ /** @var \Drupal\taxonomy\TermInterface[] $terms */
if ($terms = $this->entityManager->getStorage('taxonomy_term')->loadTree($vocabulary->id(), 0, NULL, TRUE)) {
foreach ($terms as $term) {
+ if (!$has_admin_access && (!$term->isPublished() || in_array($term->parent->target_id, $unpublished_terms))) {
+ $unpublished_terms[] = $term->id();
+ continue;
+ }
$options[$vocabulary->id()][$term->id()] = str_repeat('-', $term->depth) . Html::escape($this->entityManager->getTranslationFromContext($term)->label());
}
}
@@ -72,4 +79,63 @@ class TermSelection extends DefaultSelection {
return $options;
}
+ /**
+ * {@inheritdoc}
+ */
+ public function countReferenceableEntities($match = NULL, $match_operator = 'CONTAINS') {
+ if ($match) {
+ return parent::countReferenceableEntities($match, $match_operator);
+ }
+
+ $total = 0;
+ $referenceable_entities = $this->getReferenceableEntities($match, $match_operator, 0);
+ foreach ($referenceable_entities as $bundle => $entities) {
+ $total += count($entities);
+ }
+ return $total;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function buildEntityQuery($match = NULL, $match_operator = 'CONTAINS') {
+ $query = parent::buildEntityQuery($match, $match_operator);
+
+ // Adding the 'taxonomy_term_access' tag is sadly insufficient for terms:
+ // core requires us to also know about the concept of 'published' and
+ // 'unpublished'.
+ if (!$this->currentUser->hasPermission('administer taxonomy')) {
+ $query->condition('status', 1);
+ }
+ return $query;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function createNewEntity($entity_type_id, $bundle, $label, $uid) {
+ $term = parent::createNewEntity($entity_type_id, $bundle, $label, $uid);
+
+ // In order to create a referenceable term, it needs to published.
+ /** @var \Drupal\taxonomy\TermInterface $term */
+ $term->setPublished();
+
+ return $term;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function validateReferenceableNewEntities(array $entities) {
+ $entities = parent::validateReferenceableNewEntities($entities);
+ // Mirror the conditions checked in buildEntityQuery().
+ if (!$this->currentUser->hasPermission('administer taxonomy')) {
+ $entities = array_filter($entities, function ($term) {
+ /** @var \Drupal\taxonomy\TermInterface $term */
+ return $term->isPublished();
+ });
+ }
+ return $entities;
+ }
+
}
diff --git a/core/modules/taxonomy/src/TermAccessControlHandler.php b/core/modules/taxonomy/src/TermAccessControlHandler.php
index 1d48463..b25dca4 100644
--- a/core/modules/taxonomy/src/TermAccessControlHandler.php
+++ b/core/modules/taxonomy/src/TermAccessControlHandler.php
@@ -18,19 +18,37 @@ class TermAccessControlHandler extends EntityAccessControlHandler {
* {@inheritdoc}
*/
protected function checkAccess(EntityInterface $entity, $operation, AccountInterface $account) {
+ if ($account->hasPermission('administer taxonomy')) {
+ return AccessResult::allowed()->cachePerPermissions();
+ }
+
switch ($operation) {
case 'view':
- return AccessResult::allowedIfHasPermission($account, 'access content');
+ $access_result = AccessResult::allowedIf($account->hasPermission('access content') && $entity->isPublished())
+ ->cachePerPermissions()
+ ->addCacheableDependency($entity);
+ if (!$access_result->isAllowed()) {
+ $access_result->setReason("The 'access content' permission is required and the taxonomy term must be published.");
+ }
+ return $access_result;
case 'update':
- return AccessResult::allowedIfHasPermissions($account, ["edit terms in {$entity->bundle()}", 'administer taxonomy'], 'OR');
+ if ($account->hasPermission("edit terms in {$entity->bundle()}")) {
+ return AccessResult::allowed()->cachePerPermissions();
+ }
+
+ return AccessResult::neutral()->setReason("The following permissions are required: 'edit terms in {$entity->bundle()}' OR 'administer taxonomy'.");
case 'delete':
- return AccessResult::allowedIfHasPermissions($account, ["delete terms in {$entity->bundle()}", 'administer taxonomy'], 'OR');
+ if ($account->hasPermission("delete terms in {$entity->bundle()}")) {
+ return AccessResult::allowed()->cachePerPermissions();
+ }
+
+ return AccessResult::neutral()->setReason("The following permissions are required: 'delete terms in {$entity->bundle()}' OR 'administer taxonomy'.");
default:
// No opinion.
- return AccessResult::neutral();
+ return AccessResult::neutral()->cachePerPermissions();
}
}
diff --git a/core/modules/taxonomy/src/TermInterface.php b/core/modules/taxonomy/src/TermInterface.php
index 4cde8f4..2dc26fb 100644
--- a/core/modules/taxonomy/src/TermInterface.php
+++ b/core/modules/taxonomy/src/TermInterface.php
@@ -4,11 +4,12 @@ namespace Drupal\taxonomy;
use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Entity\EntityChangedInterface;
+use Drupal\Core\Entity\EntityPublishedInterface;
/**
* Provides an interface defining a taxonomy term entity.
*/
-interface TermInterface extends ContentEntityInterface, EntityChangedInterface {
+interface TermInterface extends ContentEntityInterface, EntityChangedInterface, EntityPublishedInterface {
/**
* Gets the term's description.
diff --git a/core/modules/taxonomy/taxonomy.install b/core/modules/taxonomy/taxonomy.install
index c1a18bc..c0e292d 100644
--- a/core/modules/taxonomy/taxonomy.install
+++ b/core/modules/taxonomy/taxonomy.install
@@ -5,6 +5,8 @@
* Install, update and uninstall functions for the taxonomy module.
*/
+use Drupal\Core\Field\BaseFieldDefinition;
+
/**
* Convert the custom taxonomy term hierarchy storage to a default storage.
*/
@@ -126,3 +128,50 @@ function taxonomy_update_8503() {
}
}
}
+
+/**
+ * Add the publishing status fields to taxonomy terms.
+ */
+function taxonomy_update_8601() {
+ $definition_update_manager = \Drupal::entityDefinitionUpdateManager();
+ $entity_type = $definition_update_manager->getEntityType('taxonomy_term');
+
+ // Bail out early if a field named 'status' is already installed.
+ if ($definition_update_manager->getFieldStorageDefinition('status', 'taxonomy_term')) {
+ return t('The publishing status field has <strong>not</strong> been added to taxonomy terms. See <a href=":link">this page</a> for more information on how to install it.', [
+ ':link' => 'https://www.drupal.org/node/2985366',
+ ]);
+ }
+
+ // Add the 'published' entity key to the taxonomy_term entity type.
+ $entity_keys = $entity_type->getKeys();
+ $entity_keys['published'] = 'status';
+ $entity_type->set('entity_keys', $entity_keys);
+
+ $definition_update_manager->updateEntityType($entity_type);
+
+ // Add the status field.
+ $status = BaseFieldDefinition::create('boolean')
+ ->setLabel(t('Publishing status'))
+ ->setDescription(t('A boolean indicating the published state.'))
+ ->setRevisionable(TRUE)
+ ->setTranslatable(TRUE)
+ ->setDefaultValue(TRUE);
+
+ $has_content_translation_status_field = \Drupal::moduleHandler()->moduleExists('content_translation') && $definition_update_manager->getFieldStorageDefinition('content_translation_status', 'taxonomy_term');
+ if ($has_content_translation_status_field) {
+ $status->setInitialValueFromField('content_translation_status', TRUE);
+ }
+ else {
+ $status->setInitialValue(TRUE);
+ }
+ $definition_update_manager->installFieldStorageDefinition('status', 'taxonomy_term', 'taxonomy_term', $status);
+
+ // Uninstall the 'content_translation_status' field if needed.
+ if ($has_content_translation_status_field) {
+ $content_translation_status = $definition_update_manager->getFieldStorageDefinition('content_translation_status', 'taxonomy_term');
+ $definition_update_manager->uninstallFieldStorageDefinition($content_translation_status);
+ }
+
+ return t('The publishing status field has been added to taxonomy terms.');
+}
diff --git a/core/modules/taxonomy/taxonomy.post_update.php b/core/modules/taxonomy/taxonomy.post_update.php
index ce1d870..12a5962 100644
--- a/core/modules/taxonomy/taxonomy.post_update.php
+++ b/core/modules/taxonomy/taxonomy.post_update.php
@@ -5,6 +5,9 @@
* Post update functions for Taxonomy.
*/
+use Drupal\Core\Config\Entity\ConfigEntityUpdater;
+use Drupal\views\ViewExecutable;
+
/**
* Clear caches due to updated taxonomy entity views data.
*/
@@ -18,3 +21,107 @@ function taxonomy_post_update_clear_views_data_cache() {
function taxonomy_post_update_clear_entity_bundle_field_definitions_cache() {
// An empty update will flush caches.
}
+
+/**
+ * Add a 'published' = TRUE filter for all Taxonomy term views and converts
+ * existing ones that were using the 'content_translation_status' field.
+ */
+function taxonomy_post_update_handle_publishing_status_addition_in_views(&$sandbox = NULL) {
+ $definition_update_manager = \Drupal::entityDefinitionUpdateManager();
+ $entity_type = $definition_update_manager->getEntityType('taxonomy_term');
+ $published_key = $entity_type->getKey('published');
+
+ $status_filter = [
+ 'id' => 'status',
+ 'table' => 'taxonomy_term_field_data',
+ 'field' => $published_key,
+ 'relationship' => 'none',
+ 'group_type' => 'group',
+ 'admin_label' => '',
+ 'operator' => '=',
+ 'value' => '1',
+ 'group' => 1,
+ 'exposed' => FALSE,
+ 'expose' => [
+ 'operator_id' => '',
+ 'label' => '',
+ 'description' => '',
+ 'use_operator' => FALSE,
+ 'operator' => '',
+ 'identifier' => '',
+ 'required' => FALSE,
+ 'remember' => FALSE,
+ 'multiple' => FALSE,
+ 'remember_roles' => [
+ 'authenticated' => 'authenticated',
+ 'anonymous' => '0',
+ 'administrator' => '0',
+ ],
+ ],
+ 'is_grouped' => FALSE,
+ 'group_info' => [
+ 'label' => '',
+ 'description' => '',
+ 'identifier' => '',
+ 'optional' => TRUE,
+ 'widget' => 'select',
+ 'multiple' => FALSE,
+ 'remember' => FALSE,
+ 'default_group' => 'All',
+ 'default_group_multiple' => [],
+ 'group_items' => [],
+ ],
+ 'entity_type' => 'taxonomy_term',
+ 'entity_field' => $published_key,
+ 'plugin_id' => 'boolean',
+ ];
+
+ \Drupal::classResolver(ConfigEntityUpdater::class)->update($sandbox, 'view', function ($view) use ($published_key, $status_filter) {
+ /** @var \Drupal\views\ViewEntityInterface $view */
+ // Only alter taxonomy term views.
+ if ($view->get('base_table') !== 'taxonomy_term_field_data') {
+ return FALSE;
+ }
+
+ $displays = $view->get('display');
+ foreach ($displays as $display_name => &$display) {
+ // Update any existing 'content_translation_status fields.
+ $fields = isset($display['display_options']['fields']) ? $display['display_options']['fields'] : [];
+ foreach ($fields as $id => $field) {
+ if (isset($field['field']) && $field['field'] == 'content_translation_status') {
+ $fields[$id]['field'] = $published_key;
+ }
+ }
+ $display['display_options']['fields'] = $fields;
+
+ // Update any existing 'content_translation_status sorts.
+ $sorts = isset($display['display_options']['sorts']) ? $display['display_options']['sorts'] : [];
+ foreach ($sorts as $id => $sort) {
+ if (isset($sort['field']) && $sort['field'] == 'content_translation_status') {
+ $sorts[$id]['field'] = $published_key;
+ }
+ }
+ $display['display_options']['sorts'] = $sorts;
+
+ // Update any existing 'content_translation_status' filters or add a new
+ // one if necessary.
+ $filters = isset($display['display_options']['filters']) ? $display['display_options']['filters'] : [];
+ $has_status_filter = FALSE;
+ foreach ($filters as $id => $filter) {
+ if (isset($filter['field']) && $filter['field'] == 'content_translation_status') {
+ $filters[$id]['field'] = $published_key;
+ $has_status_filter = TRUE;
+ }
+ }
+
+ if (!$has_status_filter) {
+ $status_filter['id'] = ViewExecutable::generateHandlerId($published_key, $filters);
+ $filters[$status_filter['id']] = $status_filter;
+ }
+ $display['display_options']['filters'] = $filters;
+ }
+ $view->set('display', $displays);
+
+ return TRUE;
+ });
+}
diff --git a/core/modules/taxonomy/tests/fixtures/update/drupal-8.views-taxonomy-term-publishing-status-2981887.php b/core/modules/taxonomy/tests/fixtures/update/drupal-8.views-taxonomy-term-publishing-status-2981887.php
new file mode 100644
index 0000000..13374db
--- /dev/null
+++ b/core/modules/taxonomy/tests/fixtures/update/drupal-8.views-taxonomy-term-publishing-status-2981887.php
@@ -0,0 +1,32 @@
+<?php
+
+/**
+ * @file
+ * Contains database additions to drupal-8.filled.standard.php.gz for testing
+ * the upgrade path of https://www.drupal.org/project/drupal/issues/2981887.
+ */
+
+use Drupal\Core\Database\Database;
+use Drupal\Core\Serialization\Yaml;
+
+$connection = Database::getConnection();
+
+$view_file = __DIR__ . '/views.view.test_taxonomy_term_view_with_content_translation_status.yml';
+$view_with_cts_config = Yaml::decode(file_get_contents($view_file));
+
+$view_file = __DIR__ . '/views.view.test_taxonomy_term_view_without_content_translation_status.yml';
+$view_without_cts_config = Yaml::decode(file_get_contents($view_file));
+
+$connection->insert('config')
+ ->fields(['collection', 'name', 'data'])
+ ->values([
+ 'collection' => '',
+ 'name' => 'views.view.test_taxonomy_term_view_with_content_translation_status',
+ 'data' => serialize($view_with_cts_config),
+ ])
+ ->values([
+ 'collection' => '',
+ 'name' => 'views.view.test_taxonomy_term_view_without_content_translation_status',
+ 'data' => serialize($view_without_cts_config),
+ ])
+ ->execute();
diff --git a/core/modules/taxonomy/tests/fixtures/update/views.view.test_taxonomy_term_view_with_content_translation_status.yml b/core/modules/taxonomy/tests/fixtures/update/views.view.test_taxonomy_term_view_with_content_translation_status.yml
new file mode 100644
index 0000000..f4cc45b
--- /dev/null
+++ b/core/modules/taxonomy/tests/fixtures/update/views.view.test_taxonomy_term_view_with_content_translation_status.yml
@@ -0,0 +1,250 @@
+langcode: en
+status: true
+dependencies:
+ module:
+ - taxonomy
+ - user
+id: test_taxonomy_term_view_with_content_translation_status
+label: 'Test taxonomy term view with content translation status'
+module: views
+description: ''
+tag: ''
+base_table: taxonomy_term_field_data
+base_field: tid
+core: 8.x
+display:
+ default:
+ display_plugin: default
+ id: default
+ display_title: Master
+ position: 0
+ display_options:
+ access:
+ type: perm
+ options:
+ perm: 'access content'
+ cache:
+ type: tag
+ options: { }
+ query:
+ type: views_query
+ options:
+ disable_sql_rewrite: false
+ distinct: false
+ replica: false
+ query_comment: ''
+ query_tags: { }
+ exposed_form:
+ type: basic
+ options:
+ submit_button: Apply
+ reset_button: false
+ reset_button_label: Reset
+ exposed_sorts_label: 'Sort by'
+ expose_sort_order: true
+ sort_asc_label: Asc
+ sort_desc_label: Desc
+ pager:
+ type: none
+ options:
+ offset: 0
+ style:
+ type: default
+ options:
+ grouping: { }
+ row_class: ''
+ default_row_class: true
+ uses_fields: false
+ row:
+ type: fields
+ options:
+ inline: { }
+ separator: ''
+ hide_empty: false
+ default_field_elements: true
+ fields:
+ name:
+ id: name
+ table: taxonomy_term_field_data
+ field: name
+ entity_type: taxonomy_term
+ entity_field: name
+ label: ''
+ alter:
+ alter_text: false
+ make_link: false
+ absolute: false
+ trim: false
+ word_boundary: false
+ ellipsis: false
+ strip_tags: false
+ html: false
+ hide_empty: false
+ empty_zero: false
+ type: string
+ settings:
+ link_to_entity: true
+ plugin_id: term_name
+ relationship: none
+ group_type: group
+ admin_label: ''
+ exclude: false
+ element_type: ''
+ element_class: ''
+ element_label_type: ''
+ element_label_class: ''
+ element_label_colon: true
+ element_wrapper_type: ''
+ element_wrapper_class: ''
+ element_default_classes: true
+ empty: ''
+ hide_alter_empty: true
+ click_sort_column: value
+ group_column: value
+ group_columns: { }
+ group_rows: true
+ delta_limit: 0
+ delta_offset: 0
+ delta_reversed: false
+ delta_first_last: false
+ multi_type: separator
+ separator: ', '
+ field_api_classes: false
+ convert_spaces: false
+ content_translation_status:
+ id: content_translation_status
+ table: taxonomy_term_field_data
+ field: content_translation_status
+ relationship: none
+ group_type: group
+ admin_label: ''
+ label: ''
+ exclude: false
+ alter:
+ alter_text: false
+ text: ''
+ make_link: false
+ path: ''
+ absolute: false
+ external: false
+ replace_spaces: false
+ path_case: none
+ trim_whitespace: false
+ alt: ''
+ rel: ''
+ link_class: ''
+ prefix: ''
+ suffix: ''
+ target: ''
+ nl2br: false
+ max_length: 0
+ word_boundary: true
+ ellipsis: true
+ more_link: false
+ more_link_text: ''
+ more_link_path: ''
+ strip_tags: false
+ trim: false
+ preserve_tags: ''
+ html: false
+ element_type: ''
+ element_class: ''
+ element_label_type: ''
+ element_label_class: ''
+ element_label_colon: false
+ element_wrapper_type: ''
+ element_wrapper_class: ''
+ element_default_classes: true
+ empty: ''
+ hide_empty: false
+ empty_zero: false
+ hide_alter_empty: true
+ click_sort_column: value
+ type: boolean
+ settings:
+ format: true-false
+ format_custom_true: ''
+ format_custom_false: ''
+ group_column: value
+ group_columns: { }
+ group_rows: true
+ delta_limit: 0
+ delta_offset: 0
+ delta_reversed: false
+ delta_first_last: false
+ multi_type: separator
+ separator: ', '
+ field_api_classes: false
+ entity_type: taxonomy_term
+ entity_field: content_translation_status
+ plugin_id: field
+ filters:
+ content_translation_status:
+ id: content_translation_status
+ table: taxonomy_term_field_data
+ field: content_translation_status
+ relationship: none
+ group_type: group
+ admin_label: ''
+ operator: '='
+ value: All
+ group: 1
+ exposed: true
+ expose:
+ operator_id: ''
+ label: 'Translation status'
+ description: ''
+ use_operator: false
+ operator: content_translation_status_op
+ identifier: content_translation_status
+ required: false
+ remember: false
+ multiple: false
+ remember_roles:
+ authenticated: authenticated
+ anonymous: '0'
+ administrator: '0'
+ is_grouped: false
+ group_info:
+ label: ''
+ description: ''
+ identifier: ''
+ optional: true
+ widget: select
+ multiple: false
+ remember: false
+ default_group: All
+ default_group_multiple: { }
+ group_items: { }
+ entity_type: taxonomy_term
+ entity_field: content_translation_status
+ plugin_id: boolean
+ sorts:
+ content_translation_status:
+ id: content_translation_status
+ table: taxonomy_term_field_data
+ field: content_translation_status
+ relationship: none
+ group_type: group
+ admin_label: ''
+ order: ASC
+ exposed: false
+ expose:
+ label: ''
+ entity_type: taxonomy_term
+ entity_field: content_translation_status
+ plugin_id: standard
+ header: { }
+ footer: { }
+ empty: { }
+ relationships: { }
+ arguments: { }
+ display_extenders: { }
+ cache_metadata:
+ max-age: -1
+ contexts:
+ - 'languages:language_content'
+ - 'languages:language_interface'
+ - url
+ - user.permissions
+ tags: { }
diff --git a/core/modules/taxonomy/tests/fixtures/update/views.view.test_taxonomy_term_view_without_content_translation_status.yml b/core/modules/taxonomy/tests/fixtures/update/views.view.test_taxonomy_term_view_without_content_translation_status.yml
new file mode 100644
index 0000000..53eb09c
--- /dev/null
+++ b/core/modules/taxonomy/tests/fixtures/update/views.view.test_taxonomy_term_view_without_content_translation_status.yml
@@ -0,0 +1,128 @@
+langcode: en
+status: true
+dependencies:
+ module:
+ - taxonomy
+ - user
+id: test_taxonomy_term_view_without_content_translation_status
+label: 'Test taxonomy term view without content translation status'
+module: views
+description: ''
+tag: ''
+base_table: taxonomy_term_field_data
+base_field: tid
+core: 8.x
+display:
+ default:
+ display_plugin: default
+ id: default
+ display_title: Master
+ position: 0
+ display_options:
+ access:
+ type: perm
+ options:
+ perm: 'access content'
+ cache:
+ type: tag
+ options: { }
+ query:
+ type: views_query
+ options:
+ disable_sql_rewrite: false
+ distinct: false
+ replica: false
+ query_comment: ''
+ query_tags: { }
+ exposed_form:
+ type: basic
+ options:
+ submit_button: Apply
+ reset_button: false
+ reset_button_label: Reset
+ exposed_sorts_label: 'Sort by'
+ expose_sort_order: true
+ sort_asc_label: Asc
+ sort_desc_label: Desc
+ pager:
+ type: none
+ options:
+ offset: 0
+ style:
+ type: default
+ options:
+ grouping: { }
+ row_class: ''
+ default_row_class: true
+ uses_fields: false
+ row:
+ type: fields
+ options:
+ inline: { }
+ separator: ''
+ hide_empty: false
+ default_field_elements: true
+ fields:
+ name:
+ id: name
+ table: taxonomy_term_field_data
+ field: name
+ entity_type: taxonomy_term
+ entity_field: name
+ label: ''
+ alter:
+ alter_text: false
+ make_link: false
+ absolute: false
+ trim: false
+ word_boundary: false
+ ellipsis: false
+ strip_tags: false
+ html: false
+ hide_empty: false
+ empty_zero: false
+ type: string
+ settings:
+ link_to_entity: true
+ plugin_id: term_name
+ relationship: none
+ group_type: group
+ admin_label: ''
+ exclude: false
+ element_type: ''
+ element_class: ''
+ element_label_type: ''
+ element_label_class: ''
+ element_label_colon: true
+ element_wrapper_type: ''
+ element_wrapper_class: ''
+ element_default_classes: true
+ empty: ''
+ hide_alter_empty: true
+ click_sort_column: value
+ group_column: value
+ group_columns: { }
+ group_rows: true
+ delta_limit: 0
+ delta_offset: 0
+ delta_reversed: false
+ delta_first_last: false
+ multi_type: separator
+ separator: ', '
+ field_api_classes: false
+ convert_spaces: false
+ filters: { }
+ sorts: { }
+ header: { }
+ footer: { }
+ empty: { }
+ relationships: { }
+ arguments: { }
+ display_extenders: { }
+ cache_metadata:
+ max-age: -1
+ contexts:
+ - 'languages:language_content'
+ - 'languages:language_interface'
+ - user.permissions
+ tags: { }
diff --git a/core/modules/taxonomy/tests/src/Functional/Rest/TermResourceTestBase.php b/core/modules/taxonomy/tests/src/Functional/Rest/TermResourceTestBase.php
index 7e5144e..3a1a5a2 100644
--- a/core/modules/taxonomy/tests/src/Functional/Rest/TermResourceTestBase.php
+++ b/core/modules/taxonomy/tests/src/Functional/Rest/TermResourceTestBase.php
@@ -200,6 +200,11 @@ abstract class TermResourceTestBase extends EntityResourceTestBase {
'langcode' => 'en',
],
],
+ 'status' => [
+ [
+ 'value' => TRUE,
+ ],
+ ],
];
}
@@ -237,7 +242,7 @@ abstract class TermResourceTestBase extends EntityResourceTestBase {
switch ($method) {
case 'GET':
- return "The 'access content' permission is required.";
+ return "The 'access content' permission is required and the taxonomy term must be published.";
case 'POST':
return "The following permissions are required: 'create terms in camelids' OR 'administer taxonomy'.";
case 'PATCH':
@@ -348,4 +353,13 @@ abstract class TermResourceTestBase extends EntityResourceTestBase {
];
}
+ /**
+ * {@inheritdoc}
+ */
+ protected function getExpectedUnauthorizedAccessCacheability() {
+ // @see \Drupal\taxonomy\TermAccessControlHandler::checkAccess()
+ return parent::getExpectedUnauthorizedAccessCacheability()
+ ->addCacheTags(['taxonomy_term:1']);
+ }
+
}
diff --git a/core/modules/taxonomy/tests/src/Functional/TermAccessTest.php b/core/modules/taxonomy/tests/src/Functional/TermAccessTest.php
new file mode 100644
index 0000000..4836fcd
--- /dev/null
+++ b/core/modules/taxonomy/tests/src/Functional/TermAccessTest.php
@@ -0,0 +1,124 @@
+<?php
+
+namespace Drupal\Tests\taxonomy\Functional;
+
+use Drupal\taxonomy\Entity\Term;
+use Drupal\taxonomy\TermInterface;
+use Drupal\Tests\system\Functional\Cache\AssertPageCacheContextsAndTagsTrait;
+
+/**
+ * Tests the taxonomy term access permissions.
+ *
+ * @group taxonomy
+ */
+class TermAccessTest extends TaxonomyTestBase {
+
+ use AssertPageCacheContextsAndTagsTrait;
+
+ /**
+ * Test access control functionality for taxonomy terms.
+ */
+ public function testTermAccess() {
+ $assert_session = $this->assertSession();
+
+ $vocabulary = $this->createVocabulary();
+
+ // Create two terms.
+ $published_term = Term::create([
+ 'vid' => $vocabulary->id(),
+ 'name' => 'Published term',
+ 'status' => 1,
+ ]);
+ $published_term->save();
+ $unpublished_term = Term::create([
+ 'vid' => $vocabulary->id(),
+ 'name' => 'Unpublished term',
+ 'status' => 0,
+ ]);
+ $unpublished_term->save();
+
+ // Start off logged in as admin.
+ $this->drupalLogin($this->drupalCreateUser(['administer taxonomy']));
+
+ // Test the 'administer taxonomy' permission.
+ $this->drupalGet('taxonomy/term/' . $published_term->id());
+ $assert_session->statusCodeEquals(200);
+ $this->assertTermAccess($published_term, 'view', TRUE);
+ $this->drupalGet('taxonomy/term/' . $unpublished_term->id());
+ $assert_session->statusCodeEquals(200);
+ $this->assertTermAccess($unpublished_term, 'view', TRUE);
+
+ $this->drupalGet('taxonomy/term/' . $published_term->id() . '/edit');
+ $assert_session->statusCodeEquals(200);
+ $this->assertTermAccess($published_term, 'update', TRUE);
+ $this->drupalGet('taxonomy/term/' . $unpublished_term->id() . '/edit');
+ $assert_session->statusCodeEquals(200);
+ $this->assertTermAccess($unpublished_term, 'update', TRUE);
+
+ $this->drupalGet('taxonomy/term/' . $published_term->id() . '/delete');
+ $assert_session->statusCodeEquals(200);
+ $this->assertTermAccess($published_term, 'delete', TRUE);
+ $this->drupalGet('taxonomy/term/' . $unpublished_term->id() . '/delete');
+ $assert_session->statusCodeEquals(200);
+ $this->assertTermAccess($unpublished_term, 'delete', TRUE);
+
+ // Test the 'access content' permission.
+ $this->drupalLogin($this->drupalCreateUser(['access content']));
+
+ $this->drupalGet('taxonomy/term/' . $published_term->id());
+ $assert_session->statusCodeEquals(200);
+ $this->assertTermAccess($published_term, 'view', TRUE);
+
+ $this->drupalGet('taxonomy/term/' . $unpublished_term->id());
+ $assert_session->statusCodeEquals(403);
+ $this->assertTermAccess($unpublished_term, 'view', FALSE, "The 'access content' permission is required and the taxonomy term must be published.");
+
+ $this->drupalGet('taxonomy/term/' . $published_term->id() . '/edit');
+ $assert_session->statusCodeEquals(403);
+ $this->assertTermAccess($published_term, 'update', FALSE, "The following permissions are required: 'edit terms in {$vocabulary->id()}' OR 'administer taxonomy'.");
+ $this->drupalGet('taxonomy/term/' . $unpublished_term->id() . '/edit');
+ $assert_session->statusCodeEquals(403);
+ $this->assertTermAccess($unpublished_term, 'update', FALSE, "The following permissions are required: 'edit terms in {$vocabulary->id()}' OR 'administer taxonomy'.");
+
+ $this->drupalGet('taxonomy/term/' . $published_term->id() . '/delete');
+ $assert_session->statusCodeEquals(403);
+ $this->assertTermAccess($published_term, 'delete', FALSE, "The following permissions are required: 'delete terms in {$vocabulary->id()}' OR 'administer taxonomy'.");
+ $this->drupalGet('taxonomy/term/' . $unpublished_term->id() . '/delete');
+ $assert_session->statusCodeEquals(403);
+ $this->assertTermAccess($unpublished_term, 'delete', FALSE, "The following permissions are required: 'delete terms in {$vocabulary->id()}' OR 'administer taxonomy'.");
+
+ // Install the Views module and repeat the checks for the 'view' permission.
+ \Drupal::service('module_installer')->install(['views'], TRUE);
+ $this->rebuildContainer();
+
+ $this->drupalGet('taxonomy/term/' . $published_term->id());
+ $assert_session->statusCodeEquals(200);
+
+ // @todo Change this assertion to expect a 403 status code when
+ // https://www.drupal.org/project/drupal/issues/2983070 is fixed.
+ $this->drupalGet('taxonomy/term/' . $unpublished_term->id());
+ $assert_session->statusCodeEquals(404);
+ }
+
+ /**
+ * Checks access on taxonomy term.
+ *
+ * @param \Drupal\taxonomy\TermInterface $term
+ * A taxonomy term entity.
+ * @param $access_operation
+ * The entity operation, e.g. 'view', 'edit', 'delete', etc.
+ * @param bool $access_allowed
+ * Whether the current use has access to the given operation or not.
+ * @param string $access_reason
+ * (optional) The reason of the access result.
+ */
+ protected function assertTermAccess(TermInterface $term, $access_operation, $access_allowed, $access_reason = '') {
+ $access_result = $term->access($access_operation, NULL, TRUE);
+ $this->assertSame($access_allowed, $access_result->isAllowed());
+
+ if ($access_reason) {
+ $this->assertSame($access_reason, $access_result->getReason());
+ }
+ }
+
+}
diff --git a/core/modules/taxonomy/tests/src/Functional/Update/TaxonomyTermUpdatePathTest.php b/core/modules/taxonomy/tests/src/Functional/Update/TaxonomyTermUpdatePathTest.php
new file mode 100644
index 0000000..87ad2a7
--- /dev/null
+++ b/core/modules/taxonomy/tests/src/Functional/Update/TaxonomyTermUpdatePathTest.php
@@ -0,0 +1,132 @@
+<?php
+
+namespace Drupal\Tests\taxonomy\Functional\Update;
+
+use Drupal\FunctionalTests\Update\UpdatePathTestBase;
+use Drupal\user\Entity\User;
+use Drupal\views\Entity\View;
+
+/**
+ * Tests the upgrade path for taxonomy terms.
+ *
+ * @group taxonomy
+ * @group Update
+ * @group legacy
+ */
+class TaxonomyTermUpdatePathTest extends UpdatePathTestBase {
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function setDatabaseDumpFiles() {
+ $this->databaseDumpFiles = [
+ __DIR__ . '/../../../../../system/tests/fixtures/update/drupal-8.filled.standard.php.gz',
+ __DIR__ . '/../../../fixtures/update/drupal-8.views-taxonomy-term-publishing-status-2981887.php',
+ ];
+ }
+
+ /**
+ * Tests the conversion of taxonomy terms to be publishable.
+ *
+ * @see taxonomy_update_8601()
+ */
+ public function testPublishable() {
+ $this->runUpdates();
+
+ // Log in as user 1.
+ $account = User::load(1);
+ $account->passRaw = 'drupal';
+ $this->drupalLogin($account);
+
+ // Make sure our vocabulary exists.
+ $this->drupalGet('admin/structure/taxonomy/manage/test_vocabulary/overview');
+
+ // Make sure our terms exist.
+ $assert_session = $this->assertSession();
+ $assert_session->pageTextContains('Test root term');
+ $assert_session->pageTextContains('Test child term');
+
+ $this->drupalGet('taxonomy/term/3');
+ $assert_session->statusCodeEquals('200');
+
+ // Make sure the terms are still translated.
+ $this->drupalGet('taxonomy/term/2/translations');
+ $assert_session->linkExists('Test root term - Spanish');
+
+ $storage = \Drupal::entityTypeManager()->getStorage('taxonomy_term');
+
+ // Check that the 'content_translation_status' field has been updated
+ // correctly.
+ /** @var \Drupal\taxonomy\TermInterface $term */
+ $term = $storage->load(2);
+ $translation = $term->getTranslation('es');
+ $this->assertTrue($translation->isPublished());
+
+ // Check that taxonomy terms can be created, saved and then loaded.
+ $term = $storage->create([
+ 'name' => 'Test term',
+ 'vid' => 'tags',
+ ]);
+ $term->save();
+
+ $term = $storage->loadUnchanged($term->id());
+
+ $this->assertEquals('Test term', $term->label());
+ $this->assertEquals('tags', $term->bundle());
+ $this->assertTrue($term->isPublished());
+
+ // Check that the term can be unpublished.
+ $term->setUnpublished();
+ $term->save();
+ $term = $storage->loadUnchanged($term->id());
+ $this->assertFalse($term->isPublished());
+ }
+
+ /**
+ * Tests handling of the publishing status in taxonomy term views updates.
+ *
+ * @see taxonomy_post_update_handle_publishing_status_addition_in_views()
+ */
+ public function testPublishingStatusUpdateForTaxonomyTermViews() {
+ // Check that the test view was previously using the
+ // 'content_translation_status' field.
+ $config = \Drupal::config('views.view.test_taxonomy_term_view_with_content_translation_status');
+ $display_options = $config->get('display.default.display_options');
+ $this->assertEquals('content_translation_status', $display_options['fields']['content_translation_status']['field']);
+ $this->assertEquals('content_translation_status', $display_options['filters']['content_translation_status']['field']);
+ $this->assertEquals('content_translation_status', $display_options['sorts']['content_translation_status']['field']);
+
+ // Check a test view without any filter.
+ $config = \Drupal::config('views.view.test_taxonomy_term_view_without_content_translation_status');
+ $display_options = $config->get('display.default.display_options');
+ $this->assertEmpty($display_options['filters']);
+
+ $this->runUpdates();
+
+ // Check that a view which had a field, filter and a sort on the
+ // 'content_translation_status' field has been updated to use the new
+ // 'status' field.
+ $view = View::load('test_taxonomy_term_view_with_content_translation_status');
+ foreach ($view->get('display') as $display) {
+ $this->assertEquals('status', $display['display_options']['fields']['content_translation_status']['field']);
+ $this->assertEquals('status', $display['display_options']['sorts']['content_translation_status']['field']);
+ $this->assertEquals('status', $display['display_options']['filters']['content_translation_status']['field']);
+ }
+
+ // Check that a view without any filters has been updated to include a
+ // filter for the 'status' field.
+ $view = View::load('test_taxonomy_term_view_without_content_translation_status');
+ foreach ($view->get('display') as $display) {
+ $this->assertNotEmpty($display['display_options']['filters']);
+ $this->assertEquals('status', $display['display_options']['filters']['status']['field']);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function replaceUser1() {
+ // Do not replace the user from our dump.
+ }
+
+}