Commit ddb1bb6c authored by bojanz's avatar bojanz

Issue #2804217: Remove the address format config entity and UI

parent c571dcf1
......@@ -6,7 +6,7 @@
function address_requirements($phase) {
$requirements = [];
if ($phase == 'install') {
if (!class_exists('\CommerceGuys\Addressing\Repository\AddressFormatRepository')) {
if (!class_exists('\CommerceGuys\Addressing\AddressFormat\AddressFormatRepository')) {
$requirements['addressing_library'] = [
'description' => t('Address requires the commerceguys/addressing library.'),
'severity' => REQUIREMENT_ERROR,
......@@ -24,14 +24,12 @@ function address_requirements($phase) {
}
/**
* Implements hook_install().
*
* Imports the address formats.
* Remove the stored address formats.
*/
function address_install() {
if (!\Drupal::isConfigSyncing()) {
/** @var \Drupal\address\AddressFormatImporterInterface $importer */
$importer = \Drupal::service('address.address_format_importer');
$importer->importAll();
function address_update_8100() {
$config_factory = \Drupal::configFactory();
$names = $config_factory->listAll('address.address_format.');
foreach ($names as $name) {
$config_factory->getEditable($name)->delete();
}
}
entity.address_format.add_form:
route_name: entity.address_format.add_form
title: 'Add a new address format'
appears_on:
- entity.address_format.collection
entity.zone.add_form:
route_name: entity.zone.add_form
title: 'Add a new zone'
......
entity.address_format.collection:
title: 'Address formats'
parent: system.admin_config_regional
description: 'Administer the address formats for each country.'
route_name: entity.address_format.collection
entity.zone.collection:
title: 'Zones'
route_name: entity.zone.collection
......
......@@ -5,18 +5,8 @@
* Provides functionality for handling postal addresses.
*/
use Drupal\language\Entity\ConfigurableLanguage;
use Drupal\Core\Form\FormStateInterface;
/**
* Implements hook_ENTITY_TYPE_insert() for 'address_format'.
*/
function address_configurable_language_insert(ConfigurableLanguage $language) {
// Allow the importer to import any found translations for the new language.
$importer = \Drupal::service('address.address_format_importer');
$importer->importTranslations([$language->getId()]);
}
/**
* Implements hook_form_BASE_FORM_ID_alter().
*
......
'administer address formats':
title: 'Administer address formats'
'restrict access': TRUE
'administer zones':
title: 'Administer zones'
'restrict access': TRUE
# edit_form and delete_form routes are generated by DefaultHtmlRouteProvider.
entity.address_format.collection:
path: '/admin/config/regional/address-formats'
defaults:
_entity_list: 'address_format'
_title: 'Address formats'
requirements:
_permission: 'administer address formats'
entity.address_format.add_form:
path: '/admin/config/regional/address-formats/add'
defaults:
_entity_form: 'address_format.add'
_title: 'Add a new address format'
requirements:
_entity_create_access: 'address_format'
entity.zone.collection:
path: '/admin/config/regional/zones'
defaults:
......
services:
address.address_format_importer:
class: Drupal\address\AddressFormatImporter
arguments: ['@entity.manager', '@language_manager']
address.address_format_repository:
class: Drupal\address\Repository\AddressFormatRepository
arguments: ['@entity.manager', '@language_manager']
arguments: ['@event_dispatcher']
address.country_repository:
class: Drupal\address\Repository\CountryRepository
......
......@@ -6,8 +6,8 @@
"license": "GPL-2.0+",
"require": {
"commerceguys/intl": "~0.7",
"commerceguys/addressing": "~0.8",
"commerceguys/zone": "~0.7"
"commerceguys/addressing": "~1.0",
"commerceguys/zone": "~1.0"
},
"minimum-stability": "dev"
}
address.address_format.*:
type: config_entity
label: 'Address format'
mapping:
countryCode:
type: string
label: 'Country code'
format:
type: text
label: 'Format'
requiredFields:
type: sequence
label: 'Required fields'
sequence:
- type: string
uppercaseFields:
type: sequence
label: 'Uppercase Fields'
sequence:
- type: string
administrativeAreaType:
type: string
label: 'Administrative area type'
localityType:
type: string
label: 'Locality type'
dependentLocalityType:
type: string
label: 'Dependent locality type'
postalCodeType:
type: string
label: 'Postal code type'
postalCodePattern:
type: string
label: 'Postal code pattern'
postalCodePrefix:
type: string
label: 'Postal code prefix'
address.zone.*:
type: config_entity
label: 'Zone'
......
<?php
namespace Drupal\address;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Entity\EntityAccessControlHandler;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Session\AccountInterface;
/**
* Defines the access control handler for the address format entity type.
*
* @see \Drupal\address\Entity\AddressFormat
*/
class AddressFormatAccessControlHandler extends EntityAccessControlHandler {
/**
* {@inheritdoc}
*/
protected function checkAccess(EntityInterface $entity, $operation, AccountInterface $account) {
// ZZ is the fallback address format and it must always be present.
if (($operation == 'delete') && ($entity->id() == 'ZZ')) {
return AccessResult::forbidden();
}
else {
return parent::checkAccess($entity, $operation, $account);
}
}
}
<?php
namespace Drupal\address;
use CommerceGuys\Addressing\Repository\AddressFormatRepository;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Language\LanguageManagerInterface;
/**
* Default implementation of the address format importer.
*/
class AddressFormatImporter implements AddressFormatImporterInterface {
/**
* The address format storage.
*
* @var \Drupal\Core\Config\Entity\ConfigEntityStorageInterface
*/
protected $storage;
/**
* The language manager.
*
* @var \Drupal\Core\Language\LanguageManagerInterface
*/
protected $languageManager;
/**
* The library's address format repository.
*
* @var \CommerceGuys\Addressing\Repository\AddressFormatRepositoryInterface
*/
protected $externalRepository;
/**
* Constructs a AddressFormatImporter object.
*
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* The entity type manager.
* @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
* The language manager.
*/
public function __construct(EntityTypeManagerInterface $entity_type_manager, LanguageManagerInterface $language_manager) {
$this->storage = $entity_type_manager->getStorage('address_format');
$this->languageManager = $language_manager;
$this->externalRepository = new AddressFormatRepository();
}
/**
* {@inheritdoc}
*/
public function importAll() {
$address_formats = $this->externalRepository->getAll();
$country_codes = array_keys($address_formats);
// It's nicer API-wise to just pass the country codes.
// The external repository maintains a static cache, so the repeated ->get()
// calls have minimal performance impact.
$this->importEntities($country_codes);
if ($this->languageManager->isMultilingual()) {
$languages = $this->languageManager->getLanguages(LanguageInterface::STATE_CONFIGURABLE);
$this->importTranslations(array_keys($languages));
}
}
/**
* {@inheritdoc}
*/
public function importEntities(array $country_codes) {
foreach ($country_codes as $country_code) {
$address_format = $this->externalRepository->get($country_code);
$values = [
'langcode' => 'en',
'countryCode' => $address_format->getCountryCode(),
'format' => $address_format->getFormat(),
'requiredFields' => $address_format->getRequiredFields(),
'uppercaseFields' => $address_format->getUppercaseFields(),
'administrativeAreaType' => $address_format->getAdministrativeAreaType(),
'localityType' => $address_format->getLocalityType(),
'dependentLocalityType' => $address_format->getDependentLocalityType(),
'postalCodeType' => $address_format->getPostalCodeType(),
'postalCodePattern' => $address_format->getPostalCodePattern(),
'postalCodePrefix' => $address_format->getPostalCodePrefix(),
];
$entity = $this->storage->create($values);
$entity->trustData()->save();
}
}
/**
* {@inheritdoc}
*/
public function importTranslations(array $langcodes) {
$available_translations = $this->getAvailableTranslations();
$available_translations = array_intersect_key($available_translations, array_flip($langcodes));
foreach ($available_translations as $langcode => $country_codes) {
$address_formats = $this->storage->loadMultiple($country_codes);
foreach ($address_formats as $country_code => $address_format) {
$external_translation = $this->externalRepository->get($country_code, $langcode);
$config_name = $address_format->getConfigDependencyName();
$config_translation = $this->languageManager->getLanguageConfigOverride($langcode, $config_name);
$config_translation->set('format', $external_translation->getFormat());
$config_translation->save();
}
}
}
/**
* Gets the available library translations.
*
* @return array
* Array keyed by language code who's value is an array of country codes
* related to that language.
*/
protected function getAvailableTranslations() {
// Hardcoded for now, since the library has no method for getting this data.
$translations = [
'ja' => ['JP'],
'ko' => ['KR'],
'th' => ['TH'],
'zh' => ['MO', 'CN'],
'zh-hant' => ['HK', 'TW'],
];
return $translations;
}
}
<?php
namespace Drupal\address;
/**
* Imports the library-provided address format data into config entities.
*/
interface AddressFormatImporterInterface {
/**
* Imports all available data.
*/
public function importAll();
/**
* Imports address formats for the given country codes.
*
* @param array $country_codes
* The country codes for which address formats should be imported.
*/
public function importEntities(array $country_codes);
/**
* Imports translations for the given language codes.
*
* @param array $langcodes
* Array of language codes to import translations for.
*/
public function importTranslations(array $langcodes);
}
<?php
namespace Drupal\address;
use Drupal\Core\Config\Entity\ConfigEntityListBuilder;
use Drupal\Core\Entity\EntityInterface;
/**
* Provides a listing of address formats.
*/
class AddressFormatListBuilder extends ConfigEntityListBuilder {
/**
* The number of address formats to list per page.
*
* The CLDR country list contains 253 countries, this limit ensures there's
* no pagination even if an address format is created for each one.
*
* @var int
*/
protected $limit = 260;
/**
* {@inheritdoc}
*/
public function buildHeader() {
$header['country'] = $this->t('Country');
return $header + parent::buildHeader();
}
/**
* {@inheritdoc}
*/
public function buildRow(EntityInterface $entity) {
$row['country'] = $entity->label();
return $row + parent::buildRow($entity);
}
}
<?php
namespace Drupal\address;
use Drupal\Core\Config\Entity\ConfigEntityStorage;
use Drupal\Core\Entity\EntityStorageException;
/**
* Defines the address format storage.
*/
class AddressFormatStorage extends ConfigEntityStorage {
/**
* {@inheritdoc}
*/
protected function doDelete($entities) {
// ZZ is the fallback address format and it must always be present.
if (isset($entities['ZZ'])) {
$entity = $entities['ZZ'];
if (!$entity->isUninstalling() && !$entity->isSyncing()) {
throw new EntityStorageException("The 'ZZ' address format can't be deleted.");
}
}
parent::doDelete($entities);
}
}
......@@ -2,7 +2,7 @@
namespace Drupal\address;
use CommerceGuys\Addressing\Model\AddressInterface as ExternalAddressInterface;
use CommerceGuys\Addressing\AddressInterface as ExternalAddressInterface;
use Drupal\Core\Field\FieldItemInterface;
/**
......
<?php
namespace Drupal\address\Entity;
use CommerceGuys\Addressing\Enum\AddressField;
use CommerceGuys\Addressing\Enum\AdministrativeAreaType;
use CommerceGuys\Addressing\Enum\DependentLocalityType;
use CommerceGuys\Addressing\Enum\LocalityType;
use CommerceGuys\Addressing\Enum\PostalCodeType;
use CommerceGuys\Addressing\Model\FormatStringTrait;
use Drupal\Core\Config\Entity\ConfigEntityBase;
/**
* Defines the AddressFormat configuration entity.
*
* @ConfigEntityType(
* id = "address_format",
* label = @Translation("Address format"),
* handlers = {
* "access" = "Drupal\address\AddressFormatAccessControlHandler",
* "list_builder" = "Drupal\address\AddressFormatListBuilder",
* "storage" = "Drupal\address\AddressFormatStorage",
* "form" = {
* "add" = "Drupal\address\Form\AddressFormatForm",
* "edit" = "Drupal\address\Form\AddressFormatForm",
* "delete" = "Drupal\address\Form\AddressFormatDeleteForm"
* },
* "route_provider" = {
* "html" = "Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider",
* }
* },
* admin_permission = "administer address formats",
* config_prefix = "address_format",
* entity_keys = {
* "id" = "countryCode",
* "label" = "countryCode",
* "uuid" = "uuid",
* },
* links = {
* "collection" = "/admin/config/regional/address-formats",
* "edit-form" = "/admin/config/regional/address-formats/manage/{address_format}",
* "delete-form" = "/admin/config/regional/address-formats/manage/{address_format}/delete"
* },
* config_export = {
* "countryCode",
* "format",
* "requiredFields",
* "uppercaseFields",
* "administrativeAreaType",
* "localityType",
* "dependentLocalityType",
* "postalCodeType",
* "postalCodePattern",
* "postalCodePrefix"
* }
* )
*/
class AddressFormat extends ConfigEntityBase implements AddressFormatInterface {
use FormatStringTrait;
/**
* The country code.
*
* @var string
*/
protected $countryCode;
/**
* The required fields.
*
* @var array
*/
protected $requiredFields = [];
/**
* The fields that need to be uppercased.
*
* @var array
*/
protected $uppercaseFields = [];
/**
* The administrative area type.
*
* @var string
*/
protected $administrativeAreaType;
/**
* The locality type.
*
* @var string
*/
protected $localityType;
/**
* The dependent locality type.
*
* @var string
*/
protected $dependentLocalityType;
/**
* The postal code type.
*
* @var string
*/
protected $postalCodeType;
/**
* The postal code pattern.
*
* @var string
*/
protected $postalCodePattern;
/**
* The postal code prefix.
*
* @var string
*/
protected $postalCodePrefix;
/**
* Overrides \Drupal\Core\Entity\Entity::id().
*/
public function id() {
return $this->countryCode;
}
/**
* Overrides \Drupal\Core\Entity\Entity::label().
*/
public function label() {
if ($this->countryCode == 'ZZ') {
return t('Generic');
}
$countries = \Drupal::service('address.country_repository')->getList();
if (isset($countries[$this->countryCode])) {
$label = $countries[$this->countryCode];
}
else {
$label = $this->countryCode;
}
return $label;
}
/**
* {@inheritdoc}
*/
public function getCountryCode() {
return $this->countryCode;
}
/**
* {@inheritdoc}
*/
public function setCountryCode($country_code) {
$this->countryCode = $country_code;
return $this;
}
/**
* {@inheritdoc}
*/
public function getRequiredFields() {