Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OEL-1213: New inline address formatter. #84

Merged
merged 2 commits into from
Mar 7, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,10 @@ content:
view_mode: default
third_party_settings: { }
oe_location:
type: address_default
type: oe_whitelabel_helper_address_inline
label: inline
settings: { }
settings:
delimiter: ', '
third_party_settings: { }
weight: 5
region: content
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
field.formatter.settings.oe_whitelabel_helper_address_inline:
type: mapping
label: 'Address inline formatter settings'
mapping:
delimiter:
type: string
label: 'Delimiter for address items.'
15 changes: 15 additions & 0 deletions modules/oe_whitelabel_helper/oe_whitelabel_helper.module
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,18 @@ declare(strict_types = 1);
function oe_whitelabel_helper_locale_translation_projects_alter(&$projects) {
$projects['oe_whitelabel_helper']['info']['interface translation server pattern'] = drupal_get_path('module', 'oe_whitelabel_helper') . '/translations/%project-%language.po';
}

/**
* Implements hook_theme().
*/
function oe_whitelabel_helper_theme($existing, $type, $theme, $path) {
return [
'oe_whitelabel_helper_address_inline' => [
'variables' => [
'address' => NULL,
'address_items' => [],
'address_delimiter' => NULL,
],
],
];
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
<?php

declare(strict_types = 1);

namespace Drupal\oe_whitelabel_helper\Plugin\Field\FieldFormatter;

use CommerceGuys\Addressing\Locale;
use Drupal\address\AddressInterface;
use Drupal\address\Plugin\Field\FieldFormatter\AddressDefaultFormatter;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Language\LanguageInterface;

/**
* Format an address inline with locale format and a configurable separator.
*
drishu marked this conversation as resolved.
Show resolved Hide resolved
* @FieldFormatter(
* id = "oe_whitelabel_helper_address_inline",
* label = @Translation("Inline address"),
* field_types = {
* "address",
* },
* )
*
* @see https://github.com/openeuropa/oe_theme/blob/3.x/modules/oe_theme_helper/src/Plugin/Field/FieldFormatter/AddressInlineFormatter.php
*/
class AddressInlineFormatter extends AddressDefaultFormatter {

/**
* {@inheritdoc}
*/
public static function defaultSettings() {
return [
'delimiter' => ', ',
];
}

/**
* {@inheritdoc}
*/
public function settingsForm(array $form, FormStateInterface $form_state) {

$form['delimiter'] = [
'#type' => 'textfield',
'#title' => $this->t('Delimiter'),
'#default_value' => $this->getSetting('delimiter'),
'#description' => $this->t('Specify delimiter between address items.'),
'#required' => TRUE,
];

return $form;
}

/**
* {@inheritdoc}
*/
public function settingsSummary() {
return [
$this->t('Delimiter: @delimiter', [
'@delimiter' => $this->getSetting('delimiter'),
]),
];
}

/**
* {@inheritdoc}
*/
public function viewElements(FieldItemListInterface $items, $langcode) {
$elements = [];
foreach ($items as $delta => $item) {
$elements[$delta] = $this->viewElement($item, $langcode);
}

return $elements;
}

/**
* Builds a renderable array for a single address item.
*
* @param \Drupal\address\AddressInterface $address
* The address.
* @param string $langcode
* The language that should be used to render the field.
*
* @return array
* A renderable array.
*/
protected function viewElement(AddressInterface $address, $langcode) {
$country_code = $address->getCountryCode();
$countries = $this->countryRepository->getList($langcode);
$address_format = $this->addressFormatRepository->get($country_code);
$values = $this->getValues($address, $address_format);

$address_elements['%country'] = $countries[$country_code];
foreach ($address_format->getUsedFields() as $field) {
$address_elements['%' . $field] = $values[$field];
}

if (Locale::matchCandidates($address_format->getLocale(), $address->getLocale())) {
$format_string = '%country' . "\n" . $address_format->getLocalFormat();
}
else {
$format_string = $address_format->getFormat() . "\n" . '%country';
}
/*
* Remove extra characters from address format since address fields are
* optional.
*
* @see \CommerceGuys\Addressing\AddressFormat\AddressFormatRepository::getDefinitions()
*/
$format_string = str_replace([',', ' - ', '/'], "\n", $format_string);

$items = $this->extractAddressItems($format_string, $address_elements);

return [
'#theme' => 'oe_whitelabel_helper_address_inline',
'#address' => $address,
'#address_items' => $items,
'#address_delimiter' => $this->getSetting('delimiter'),
'#cache' => [
'contexts' => [
'languages:' . LanguageInterface::TYPE_INTERFACE,
],
],
];
}

/**
* Extract address items from a format string and replace placeholders.
*
* @param string $string
* The address format string, containing placeholders.
* @param array $replacements
* An array of address items.
*
* @return array
* The exploded lines.
*/
protected function extractAddressItems(string $string, array $replacements): array {
// Make sure the replacements don't have any unneeded newlines.
$replacements = array_map('trim', $replacements);
$string = strtr($string, $replacements);
// Remove noise caused by empty placeholders.
$lines = explode("\n", $string);
foreach ($lines as $index => $line) {
// Remove leading punctuation, excess whitespace.
$line = trim(preg_replace('/^[-,]+/', '', $line, 1));
$line = preg_replace('/\s\s+/', ' ', $line);
$lines[$index] = $line;
}
// Remove empty lines.
$lines = array_filter($lines);

return $lines;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{#
/**
* @file
* Default template for the 'oe_whitelabel_helper_address_inline' address formatter.
*
* Available variables:
* - address: Address object.
* - address_items: Address items.
* - address_delimiter: Delimiter between address items.
*
* @ingroup themeable
*/
#}
<span translate="no">
{{ address_items|join(address_delimiter) }}
</span>
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
<?php

declare(strict_types = 1);

namespace Drupal\Tests\oe_whitelabel_helper\Kernel\Plugin\Field\FieldFormatter;

use Drupal\entity_test\Entity\EntityTest;
use Drupal\Tests\address\Kernel\Formatter\FormatterTestBase;

/**
* Test AddressInlineFormatter plugin.
*/
class AddressInlineFormatterTest extends FormatterTestBase {

/**
* {@inheritdoc}
*/
public static $modules = [
'oe_whitelabel_helper',
];

/**
* {@inheritdoc}
*/
protected function setUp(): void {
parent::setUp();

$this->createField('address', 'oe_whitelabel_helper_address_inline');
}

/**
* Tests formatting of address.
*/
public function testInlineFormatterAddress(): void {
$entity = EntityTest::create([]);
foreach ($this->addressFieldTestData() as $data) {
$cloned_entity = clone $entity;
$cloned_entity->{$this->fieldName} = $data['address'];
$this->renderEntityFields($cloned_entity, $this->display);
$this->assertRaw($data['expected']);
unset($cloned_entity);
}
}

/**
* Test data for testInlineFormatterAddress.
*
* @return array[]
* An array of test data arrays with expected result.
*/
public function addressFieldTestData(): array {
return [
'Brussels Belgium' => [
'address' => [
'country_code' => 'BE',
'locality' => 'Brussels <Bruxelles>',
'postal_code' => '1000',
'address_line1' => 'Rue de la Loi, 56 <123>',
'address_line2' => 'or \'Wetstraat\' (Dutch), meaning "Law Street"',
],
'expected' => 'Rue de la Loi, 56 &lt;123&gt;, or &#039;Wetstraat&#039; (Dutch), meaning &quot;Law Street&quot;, 1000 Brussels &lt;Bruxelles&gt;, Belgium',
],
'Mexico' => [
'address' => [
'country_code' => 'MX',
],
'expected' => 'Mexico',
],
'Mexico Ciudad de Mexico' => [
'address' => [
'country_code' => 'MX',
'administrative_area' => 'CDMX',
],
'expected' => 'CDMX, Mexico',
],
'Mexico Baja California Tijuana' => [
'address' => [
'country_code' => 'MX',
'administrative_area' => 'B.C.',
'locality' => 'Tijuana',
],
'expected' => 'Tijuana, B.C., Mexico',
],
'Mexico Baja California Tijuana 22000' => [
'address' => [
'country_code' => 'MX',
'administrative_area' => 'B.C.',
'locality' => 'Tijuana',
'postal_code' => '22000',
],
'expected' => '22000 Tijuana, B.C., Mexico',
],
'Mexico Baja California Tijuana 22000 Street' => [
'address' => [
'country_code' => 'MX',
'administrative_area' => 'B.C.',
'locality' => 'Tijuana',
'postal_code' => '22000',
'address_line1' => 'Street',
],
'expected' => 'Street, 22000 Tijuana, B.C., Mexico',
],
'Bangladesh Dhaka' => [
'address' => [
'country_code' => 'BD',
'locality' => 'Dhaka',
],
'expected' => 'Dhaka, Bangladesh',
],
'Bangladesh Dhaka 1100' => [
'address' => [
'country_code' => 'BD',
'locality' => 'Dhaka',
'postal_code' => '1100',
],
'expected' => 'Dhaka, 1100, Bangladesh',
],
];
}

}