Commit 9a8756ae authored by Pancho's avatar Pancho Committed by bojanz

Issue #2783699 by Pancho, harings_rob, dww: Views sorting by country name

parent f075f456
......@@ -41,9 +41,8 @@ function address_field_views_data(FieldStorageConfigInterface $field) {
'property' => $column,
];
}
// Add the custom country_code filter.
$data[$table_name][$field_name . '_country_code']['filter']['id'] = 'country_code';
// Add the custom administrative_area filter.
$data[$table_name][$field_name . '_country_code']['sort']['id'] = 'country';
$data[$table_name][$field_name . '_administrative_area']['filter']['id'] = 'administrative_area';
}
}
......@@ -55,6 +54,7 @@ function address_field_views_data(FieldStorageConfigInterface $field) {
'property' => 'value',
];
$data[$table_name][$field_name . '_value']['filter']['id'] = 'country_code';
$data[$table_name][$field_name . '_value']['sort']['id'] = 'country';
}
}
......
......@@ -202,3 +202,11 @@ views.filter.administrative_area:
label_type:
type: string
label: 'Label type'
views.sort.country:
type: views_sort
label: 'Country'
mapping:
sort_by:
type: string
label: 'Sort by'
<?php
namespace Drupal\address\Plugin\views\sort;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Language\LanguageManagerInterface;
use Drupal\views\Plugin\views\sort\SortPluginBase;
use Symfony\Component\DependencyInjection\ContainerInterface;
use CommerceGuys\Addressing\Country\CountryRepositoryInterface;
/**
* Sort handler for sorting by either country code or name.
*
* Allows sorting by name, since country codes don't necessarily reflect the
* first characters of the country name, especially if translations are used.
*
* @ingroup views_sort_handlers
*
* @ViewsSort("country")
*/
class Country extends SortPluginBase {
/**
* Sort by country name.
*/
const COUNTRY_NAME = 'name';
/**
* Sort by country code.
*/
const COUNTRY_CODE = 'code';
/**
* The country repository.
*
* @var \CommerceGuys\Addressing\Country\CountryRepositoryInterface
*/
protected $countryRepository;
/**
* The current language code.
*
* @var string
*/
protected $langcode;
/**
* Constructs a new Country object.
*
* @param array $configuration
* A configuration array containing information about the plugin instance.
* @param string $plugin_id
* The id of the plugin instance.
* @param mixed $plugin_definition
* The plugin implementation definition.
* @param \CommerceGuys\Addressing\Country\CountryRepositoryInterface $country_repository
* The country repository.
* @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
* The language manager.
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition, CountryRepositoryInterface $country_repository, LanguageManagerInterface $language_manager) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->countryRepository = $country_repository;
$this->langcode = $language_manager->getCurrentLanguage()->getId();
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static(
$configuration,
$plugin_id,
$plugin_definition,
$container->get('address.country_repository'),
$container->get('language_manager')
);
}
/**
* {@inheritdoc}
*/
protected function defineOptions() {
$options = parent::defineOptions();
$options['sort_by'] = ['default' => self::COUNTRY_NAME];
return $options;
}
/**
* {@inheritdoc}
*/
public function query() {
if ($this->options['sort_by'] === self::COUNTRY_NAME) {
$this->ensureMyTable();
// Map country codes to a sorting key using WHEN ... THEN clauses.
$country_list = $this->countryRepository->getList($this->langcode);
$field_name = $this->tableAlias . '.' . $this->realField;
$when = [];
$i = 0;
foreach (array_keys($country_list) as $country_code) {
// Use only the country codes which are in the expected format.
if (strlen($country_code) == 2) {
$when[] = "WHEN $field_name = '$country_code' THEN " . $i++;
}
}
$this->query->addField(NULL, 'CASE ' . implode(' ', $when) . ' END', 'address_sort_country_name');
$this->query->addOrderBy(NULL, NULL, $this->options['order'], 'address_sort_country_name');
}
else {
parent::query();
}
}
/**
* {@inheritdoc}
*/
public function buildOptionsForm(&$form, FormStateInterface $form_state) {
parent::buildOptionsForm($form, $form_state);
$form['sort_by'] = [
'#type' => 'radios',
'#title' => $this->t('Sort by'),
'#options' => [
self::COUNTRY_NAME => $this->t('Country name'),
self::COUNTRY_CODE => $this->t('Country code'),
],
'#default_value' => $this->options['sort_by'],
'#weight' => -0.5,
];
}
}
langcode: en
status: true
dependencies:
config:
- node.type.address_test
module:
- address
- node
- user
id: address_test_sort_country
label: 'Address test sort country'
module: views
description: ''
tag: ''
base_table: node_field_data
base_field: nid
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
row:
type: fields
options:
default_field_elements: true
inline:
counter: counter
field_address_test_country_code: field_address_test_country_code
separator: '-'
hide_empty: false
fields:
counter:
id: counter
table: views
field: counter
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
counter_start: 1
plugin_id: counter
field_address_test_country_code:
id: field_address_test_country_code
table: node__field_address_test
field: field_address_test_country_code
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
display_name: false
plugin_id: country_code
filters:
status:
value: '1'
table: node_field_data
field: status
plugin_id: boolean
entity_type: node
entity_field: status
id: status
expose:
operator: ''
group: 1
type:
id: type
table: node_field_data
field: type
relationship: none
group_type: group
admin_label: ''
operator: in
value:
address_test: address_test
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
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: node
entity_field: type
plugin_id: bundle
sorts:
field_address_test_country_code:
id: field_address_test_country_code
table: node__field_address_test
field: field_address_test_country_code
relationship: none
group_type: group
admin_label: ''
order: ASC
exposed: true
expose:
label: Country
sort_by: name
plugin_id: country
title: 'address views country sort test'
header: { }
footer: { }
empty: { }
relationships: { }
arguments: { }
display_extenders: { }
filter_groups:
operator: AND
groups:
1: AND
cache_metadata:
max-age: -1
contexts:
- 'languages:language_interface'
- 'url.query_args:sort_by'
- 'url.query_args:sort_order'
- 'user.node_grants:view'
- user.permissions
tags: { }
page_1:
display_plugin: page
id: page_1
display_title: Page
position: 1
display_options:
display_extenders: { }
path: address-test/views/sort-country
cache_metadata:
max-age: -1
contexts:
- 'languages:language_interface'
- 'url.query_args:sort_by'
- 'url.query_args:sort_order'
- 'user.node_grants:view'
- user.permissions
tags: { }
<?php
namespace Drupal\Tests\address\Functional\Views;
use Drupal\Tests\BrowserTestBase;
use Drupal\views\Views;
/**
* Tests sorting Views by country.
*
* @group address
*/
class CountrySortTest extends BrowserTestBase {
/**
* {@inheritdoc}
*/
protected static $modules = [
'node',
'user',
'views',
'address',
'address_test',
];
/**
* A regular user with 'access content' permission.
*
* @var \Drupal\user\UserInterface
*/
protected $user;
/**
* The test nodes.
*
* @var \Drupal\node\NodeInterface[]
*/
protected $nodes;
/**
* The countries, keyed by country code.
*
* @var string[]
*/
protected $countries;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->user = $this->drupalCreateUser(['access content']);
$this->drupalLogin($this->user);
// This is a good set since the names and codes aren't in the same order.
$this->countries = [
'AT' => 'Austria',
'DE' => 'Germany',
'FR' => 'France',
'HR' => 'Croatia',
'US' => 'United States',
'VI' => 'U.S. Virgin Islands',
];
foreach ($this->countries as $country_code => $name) {
$this->nodes[$country_code] = $this->drupalCreateNode([
'type' => 'address_test',
'status' => 1,
'title' => $name,
'field_address_test' => [
'country_code' => $country_code,
],
]);
}
}
/**
* Test sorting by country code.
*/
public function testSortCountryCode() {
// Force the view to sort by code.
$view = Views::getView('address_test_sort_country');
$sorts = $view->getDisplay()->getOption('sorts');
$sorts['field_address_test_country_code']['sort_by'] = 'code';
$view->getDisplay()->overrideOption('sorts', $sorts);
$view->save();
$this->drupalGet('address-test/views/sort-country');
$this->assertSession()->statusCodeEquals(200);
$this->assertSession()->pageTextContains('1-AT');
$this->assertSession()->pageTextContains('2-DE');
$this->assertSession()->pageTextContains('3-FR');
$this->assertSession()->pageTextContains('4-HR');
$this->assertSession()->pageTextContains('5-US');
$this->assertSession()->pageTextContains('6-VI');
}
/**
* Test sorting by country name.
*/
public function testSortCountryName() {
// Force the view to sort by name.
$view = Views::getView('address_test_sort_country');
$sorts = $view->getDisplay()->getOption('sorts');
$sorts['field_address_test_country_code']['sort_by'] = 'name';
$view->getDisplay()->overrideOption('sorts', $sorts);
$view->save();
$this->drupalGet('address-test/views/sort-country');
$this->assertSession()->statusCodeEquals(200);
$this->assertSession()->pageTextContains('1-AT');
$this->assertSession()->pageTextContains('2-HR');
$this->assertSession()->pageTextContains('3-FR');
$this->assertSession()->pageTextContains('4-DE');
$this->assertSession()->pageTextContains('5-VI');
$this->assertSession()->pageTextContains('6-US');
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment