Issue #2765297 by mohit_aghera, joseph.olstad, sylus, alexpott, ducktape, anmolgoyal74, heikki, kishor_kolekar, kriboogh, googletorp, dnotes, mpp, catch, Lendude, Berdir, borisson_, xjm: Return translated term name on views "Content: Has taxonomy term ID (with depth)"

(cherry picked from commit 1bcc7f34e6)
merge-requests/7078/head
Alex Pott 2024-03-18 13:26:17 +00:00
parent 8ac6759551
commit 46564ee733
No known key found for this signature in database
GPG Key ID: BDA67E7EE836E5CE
7 changed files with 582 additions and 12 deletions

View File

@ -3,6 +3,7 @@
namespace Drupal\taxonomy\Plugin\views\argument;
use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Entity\EntityRepositoryInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\taxonomy\TaxonomyIndexDepthQueryTrait;
@ -26,16 +27,26 @@ class IndexTidDepth extends ArgumentPluginBase implements ContainerFactoryPlugin
/**
* @var \Drupal\Core\Entity\EntityStorageInterface
*
* @deprecated in drupal:10.3.0 and is removed from drupal:11.0.0. There is no
* replacement.
*
* @see https://www.drupal.org/node/3427843
*/
protected $termStorage;
/**
* {@inheritdoc}
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityStorageInterface $termStorage) {
public function __construct(array $configuration, $plugin_id, $plugin_definition, protected EntityStorageInterface|EntityRepositoryInterface $entityRepository) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->termStorage = $termStorage;
if ($entityRepository instanceof EntityStorageInterface) {
// @phpstan-ignore-next-line
$this->termStorage = $entityRepository;
@trigger_error('Calling ' . __CLASS__ . '::__construct() with the $termStorage argument as \Drupal\Core\Entity\EntityStorageInterface is deprecated in drupal:10.3.0 and it will require Drupal\Core\Entity\EntityRepositoryInterface in drupal:11.0.0. See https://www.drupal.org/node/3427843', E_USER_DEPRECATED);
$this->entityRepository = \Drupal::service('entity.repository');
}
}
/**
@ -46,7 +57,7 @@ class IndexTidDepth extends ArgumentPluginBase implements ContainerFactoryPlugin
$configuration,
$plugin_id,
$plugin_definition,
$container->get('entity_type.manager')->getStorage('taxonomy_term')
$container->get('entity.repository')
);
}
@ -114,9 +125,9 @@ class IndexTidDepth extends ArgumentPluginBase implements ContainerFactoryPlugin
}
public function title() {
$term = $this->termStorage->load($this->argument);
$term = $this->entityRepository->getCanonical('taxonomy_term', $this->argument);
if (!empty($term)) {
return $term->getName();
return $term->label();
}
// TODO review text
return $this->t('No name');

View File

@ -2,6 +2,7 @@
namespace Drupal\taxonomy\Plugin\views\argument;
use Drupal\Core\Entity\EntityRepositoryInterface;
use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\views\Attribute\ViewsArgument;
@ -20,16 +21,25 @@ class Taxonomy extends NumericArgument implements ContainerFactoryPluginInterfac
/**
* @var \Drupal\Core\Entity\EntityStorageInterface
*
* @deprecated in drupal:10.3.0 and is removed from drupal:11.0.0. There is no
* replacement.
*
* @see https://www.drupal.org/node/3427843
*/
protected $termStorage;
/**
* {@inheritdoc}
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityStorageInterface $term_storage) {
public function __construct(array $configuration, $plugin_id, $plugin_definition, protected EntityStorageInterface|EntityRepositoryInterface $entityRepository) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->termStorage = $term_storage;
if ($entityRepository instanceof EntityStorageInterface) {
// @phpstan-ignore-next-line
$this->termStorage = $this->entityRepository;
@trigger_error('Calling ' . __CLASS__ . '::__construct() with the $termStorage argument as \Drupal\Core\Entity\EntityStorageInterface is deprecated in drupal:10.3.0 and it will require Drupal\Core\Entity\EntityRepositoryInterface in drupal:11.0.0. See https://www.drupal.org/node/3427843', E_USER_DEPRECATED);
$this->entityRepository = \Drupal::service('entity.repository');
}
}
/**
@ -40,7 +50,7 @@ class Taxonomy extends NumericArgument implements ContainerFactoryPluginInterfac
$configuration,
$plugin_id,
$plugin_definition,
$container->get('entity_type.manager')->getStorage('taxonomy_term')
$container->get('entity.repository')
);
}
@ -50,9 +60,9 @@ class Taxonomy extends NumericArgument implements ContainerFactoryPluginInterfac
public function title() {
// There might be no valid argument.
if ($this->argument) {
$term = $this->termStorage->load($this->argument);
$term = $this->entityRepository->getCanonical('taxonomy_term', $this->argument);
if (!empty($term)) {
return $term->getName();
return $term->label();
}
}
// TODO review text

View File

@ -112,6 +112,7 @@ function taxonomy_tokens($type, $tokens, array $data, array $options, Bubbleable
$replacements = [];
if ($type == 'term' && !empty($data['term'])) {
$term = $data['term'];
$term = \Drupal::service('entity.repository')->getTranslationFromContext($term, isset($options['langcode']) ? $options['langcode'] : NULL);
foreach ($tokens as $name => $original) {
switch ($name) {
@ -120,7 +121,7 @@ function taxonomy_tokens($type, $tokens, array $data, array $options, Bubbleable
break;
case 'name':
$replacements[$original] = $term->getName();
$replacements[$original] = $term->label();
break;
case 'description':

View File

@ -0,0 +1,41 @@
<?php
declare(strict_types=1);
namespace Drupal\taxonomy_test\Plugin\views\argument;
use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
use Drupal\taxonomy\Plugin\views\argument\Taxonomy;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Test argument handler for testing deprecation in IndexTidDepth plugin.
*
* @ingroup views_argument_handlers
*
* @ViewsArgument("taxonomy_views_argument_test")
*/
class TaxonomyViewsArgumentTest extends Taxonomy {
/**
* Constructs new IndexTidDepthTestPlugin object.
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityStorageInterface $term_storage, protected EntityTypeBundleInfoInterface $entityTypeBundleInfo) {
parent::__construct($configuration, $plugin_id, $plugin_definition, $term_storage);
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition): static {
return new static(
$configuration,
$plugin_id,
$plugin_definition,
$container->get('entity_type.manager')->getStorage('taxonomy_term'),
$container->get('entity_type.bundle.info'),
);
}
}

View File

@ -0,0 +1,337 @@
langcode: en
status: true
dependencies:
config:
- core.entity_view_mode.node.teaser
module:
- node
- taxonomy
- user
id: taxonomy_translated_term_name_test
label: 'Taxonomy Translated Term Name Test'
module: taxonomy
description: 'Content belonging to a certain taxonomy term.'
tag: default
base_table: node_field_data
base_field: nid
display:
default:
id: default
display_title: Default
display_plugin: default
position: 0
display_options:
query:
type: views_query
options:
query_comment: ''
disable_sql_rewrite: false
distinct: false
replica: false
query_tags: { }
access:
type: perm
options:
perm: 'access content'
cache:
type: tag
options: { }
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: mini
options:
items_per_page: 10
offset: 0
id: 0
total_pages: 0
expose:
items_per_page: false
items_per_page_label: 'Items per page'
items_per_page_options: '5, 10, 25, 50'
items_per_page_options_all: false
items_per_page_options_all_label: '- All -'
offset: false
offset_label: Offset
tags:
previous:
next:
sorts:
sticky:
id: sticky
table: taxonomy_index
field: sticky
order: DESC
plugin_id: standard
relationship: none
group_type: group
admin_label: ''
exposed: false
expose:
label: ''
created:
id: created
table: taxonomy_index
field: created
order: DESC
plugin_id: date
relationship: none
group_type: group
admin_label: ''
exposed: false
expose:
label: ''
granularity: second
arguments:
term_node_tid_depth:
id: term_node_tid_depth
table: node_field_data
field: term_node_tid_depth
relationship: none
group_type: group
admin_label: ''
default_action: ignore
exception:
value: all
title_enable: false
title: All
title_enable: true
title: '{{ arguments.term_node_tid_depth }}'
default_argument_type: fixed
default_argument_options:
argument: ''
summary_options:
base_path: ''
count: true
items_per_page: 25
override: false
summary:
sort_order: asc
number_of_records: 0
format: default_summary
specify_validation: true
validate:
type: 'entity:taxonomy_term'
fail: 'not found'
validate_options:
access: true
operation: view
multiple: 0
bundles: { }
depth: 2
break_phrase: false
use_taxonomy_term_path: false
entity_type: node
plugin_id: taxonomy_index_tid_depth
filters:
langcode:
id: langcode
table: node_field_data
field: langcode
relationship: none
group_type: group
admin_label: ''
operator: in
value:
'***LANGUAGE_language_content***': '***LANGUAGE_language_content***'
group: 1
exposed: false
expose:
operator_id: ''
label: ''
description: ''
use_operator: false
operator: ''
identifier: ''
required: false
remember: false
multiple: false
remember_roles:
authenticated: authenticated
reduce: false
operator_limit_selection: false
operator_list: { }
is_grouped: false
group_info:
label: ''
description: ''
identifier: ''
optional: true
widget: select
multiple: false
remember: false
default_group: All
default_group_multiple: { }
group_items: { }
plugin_id: language
entity_type: node
entity_field: langcode
status:
id: status
table: taxonomy_index
field: status
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
operator_limit_selection: false
operator_list: { }
is_grouped: false
group_info:
label: ''
description: ''
identifier: ''
optional: true
widget: select
multiple: false
remember: false
default_group: All
default_group_multiple: { }
group_items: { }
plugin_id: boolean
style:
type: default
options:
grouping: { }
row_class: ''
default_row_class: true
uses_fields: false
row:
type: 'entity:node'
options:
view_mode: teaser
header:
entity_taxonomy_term:
id: entity_taxonomy_term
table: views
field: entity_taxonomy_term
relationship: none
group_type: group
admin_label: ''
empty: true
tokenize: true
target: '{{ raw_arguments.tid }}'
view_mode: full
bypass_access: false
plugin_id: entity
footer: { }
empty: { }
relationships: { }
fields: { }
display_extenders: { }
link_url: ''
link_display: page_1
cache_metadata:
contexts:
- 'languages:language_interface'
- url
- url.query_args
- 'user.node_grants:view'
- user.permissions
max-age: -1
tags: { }
page_1:
id: page_1
display_title: Page
display_plugin: page
position: 1
display_options:
query:
type: views_query
options: { }
display_extenders: { }
path: taxonomy/test/%
cache_metadata:
max-age: -1
contexts: { }
tags: { }
page_2:
id: page_2
display_title: Page
display_plugin: page
position: 1
display_options:
arguments:
tid:
id: tid
table: taxonomy_term_field_data
field: tid
relationship: term_node_tid
group_type: group
admin_label: ''
entity_type: taxonomy_term
entity_field: tid
plugin_id: taxonomy
default_action: ignore
exception:
value: all
title_enable: false
title: All
title_enable: false
title: ''
default_argument_type: fixed
default_argument_options:
argument: ''
summary_options:
base_path: ''
count: true
override: false
items_per_page: 25
summary:
sort_order: asc
number_of_records: 0
format: default_summary
specify_validation: false
validate:
type: none
fail: 'not found'
validate_options: { }
break_phrase: false
not: false
query:
type: views_query
options: { }
defaults:
relationships: false
arguments: false
relationships:
term_node_tid:
id: term_node_tid
table: node_field_data
field: term_node_tid
relationship: none
group_type: group
admin_label: term
entity_type: node
plugin_id: node_term_data
required: false
vids: { }
display_extenders: { }
path: taxonomy/test2/%
cache_metadata:
max-age: -1
contexts: { }
tags: { }

View File

@ -0,0 +1,132 @@
<?php
declare(strict_types=1);
namespace Drupal\Tests\taxonomy\Functional\Views;
use Drupal\Core\Url;
use Drupal\Tests\taxonomy\Functional\TaxonomyTranslationTestTrait;
/**
* Tests for views translation.
*
* @group taxonomy
*/
class TermTranslationViewsTest extends TaxonomyTestBase {
use TaxonomyTranslationTestTrait;
/**
* Term to translated term mapping.
*
* @var array
*/
protected $termTranslationMap = [
'one' => 'translatedOne',
'two' => 'translatedTwo',
'three' => 'translatedThree',
];
/**
* Created terms.
*
* @var \Drupal\taxonomy\Entity\Term[]
*/
protected $terms = [];
/**
* {@inheritdoc}
*/
protected static $modules = ['taxonomy', 'language', 'content_translation', 'views'];
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = ['taxonomy_translated_term_name_test'];
/**
* {@inheritdoc}
*/
protected $defaultTheme = 'stark';
/**
* Language object.
*
* @var \Drupal\Core\Language\LanguageInterface|null
*/
protected $translationLanguage;
/**
* {@inheritdoc}
*/
protected function setUp($import_test_views = TRUE, $modules = []): void {
parent::setUp($import_test_views, $modules);
$this->setupLanguages();
$this->enableTranslation();
$this->setUpTerms();
$this->translationLanguage = \Drupal::languageManager()->getLanguage($this->translateToLangcode);
}
/**
* Ensure that proper translation is returned when contextual filter.
*
* Taxonomy term: Term ID & Content: Has taxonomy term ID (with depth)
* contextual filters are enabled for two separate view modes.
*/
public function testTermsTranslationWithContextualFilter() {
$this->drupalLogin($this->rootUser);
foreach ($this->terms as $term) {
// Test with "Content: Has taxonomy term ID (with depth)" contextual filter.
// Generate base language url and send request.
$url = Url::fromRoute('view.taxonomy_translated_term_name_test.page_1', ['arg_0' => $term->id()])->toString();
$this->drupalGet($url);
$this->assertSession()->pageTextContains($term->label());
// Generate translation URL and send request.
$url = Url::fromRoute('view.taxonomy_translated_term_name_test.page_1', ['arg_0' => $term->id()], ['language' => $this->translationLanguage])->toString();
$this->drupalGet($url);
$this->assertSession()->pageTextContains($this->termTranslationMap[$term->label()]);
// Test with "Taxonomy term: Term ID" contextual filter.
// Generate base language url and send request.
$url = Url::fromRoute('view.taxonomy_translated_term_name_test.page_2', ['arg_0' => $term->id()])->toString();
$this->drupalGet($url);
$this->assertSession()->pageTextContains($term->label());
// Generate translation URL and send request.
$url = Url::fromRoute('view.taxonomy_translated_term_name_test.page_2', ['arg_0' => $term->id()], ['language' => $this->translationLanguage])->toString();
$this->drupalGet($url);
$this->assertSession()->pageTextContains($this->termTranslationMap[$term->label()]);
}
}
/**
* Setup translated terms in a hierarchy.
*/
protected function setUpTerms() {
$parent_vid = 0;
foreach ($this->termTranslationMap as $name => $translation) {
$term = $this->createTerm([
'name' => $name,
'langcode' => $this->baseLangcode,
'parent' => $parent_vid,
'vid' => $this->vocabulary->id(),
]);
$term->addTranslation($this->translateToLangcode, [
'name' => $translation,
]);
$term->save();
// Each term is nested under the last.
$parent_vid = $term->id();
$this->terms[] = $term;
}
}
}

View File

@ -0,0 +1,38 @@
<?php
declare(strict_types=1);
namespace Drupal\Tests\taxonomy\Kernel\Views;
use Drupal\KernelTests\KernelTestBase;
use Drupal\taxonomy_test\Plugin\views\argument\TaxonomyViewsArgumentTest;
/**
* Tests deprecation messages in views argument plugins.
*
* @group taxonomy
*/
class ViewsArgumentDeprecationTest extends KernelTestBase {
/**
* {@inheritdoc}
*/
protected static $modules = [
'system',
'taxonomy',
'taxonomy_test',
'views',
];
/**
* Test the deprecation message in ViewsArgument plugin.
*
* @group legacy
*/
public function testDeprecation(): void {
$this->expectDeprecation('Calling Drupal\taxonomy\Plugin\views\argument\Taxonomy::__construct() with the $termStorage argument as \Drupal\Core\Entity\EntityStorageInterface is deprecated in drupal:10.3.0 and it will require Drupal\Core\Entity\EntityRepositoryInterface in drupal:11.0.0. See https://www.drupal.org/node/3427843');
$plugin = \Drupal::service('plugin.manager.views.argument')->createInstance('taxonomy_views_argument_test', []);
$this->assertInstanceOf(TaxonomyViewsArgumentTest::class, $plugin);
}
}