Commit 37ce1b14 authored by bojanz's avatar bojanz
Browse files

Move the available_countries setting from the widget to the field.

This will allow the constraints&validators to use it as well, giving us the
same validation for the API and the widget.
parent 5a6a1317
......@@ -41,6 +41,11 @@ field.field_settings.address:
type: mapping
label: 'Address field settings'
mapping:
available_countries:
type: sequence
label: 'Available countries'
sequence:
- type: string
fields:
type: sequence
label: 'Used fields'
......@@ -51,11 +56,6 @@ field.widget.settings.address_default:
type: mapping
label: 'Default address formatter settings'
mapping:
available_countries:
type: sequence
label: 'Available countries'
sequence:
- type: string
default_country:
type: string
label: 'Default country'
......@@ -13,13 +13,13 @@ namespace Drupal\address\Event;
final class AddressEvents {
/**
* Name of the event fired when altering widget settings.
* Name of the event fired when altering the list of available countries.
*
* @Event
*
* @see \Drupal\address\Event\WidgetSettingsEvent
* @see \Drupal\address\Event\AvailableCountriesEvent
*/
const WIDGET_SETTINGS = 'address.widget.settings';
const AVAILABLE_COUNTRIES = 'address.available_countries';
/**
* Name of the event fired when altering initial values.
......
......@@ -2,7 +2,7 @@
/**
* @file
* Contains \Drupal\address\Event\WidgetSettingsEvent.
* Contains \Drupal\address\Event\AvailableCountriesEvent.
*/
namespace Drupal\address\Event;
......@@ -11,19 +11,21 @@ use Drupal\Core\Field\FieldDefinitionInterface;
use Symfony\Component\EventDispatcher\Event;
/**
* Defines the widget settings event.
* Defines the available countries event.
*
* @see \Drupal\address\Event\AddressEvents
* @see \Drupal\address\Plugin\Field\FieldWidget\AddressDefaultWidget::defaultSettings
* @see \Drupal\address\Plugin\Field\FieldType\AddressItem::getAvailableCountries
*/
class WidgetSettingsEvent extends Event {
class AvailableCountriesEvent extends Event {
/**
* The widget settings.
* The available countries.
*
* A list of country codes.
*
* @var array
*/
protected $settings;
protected $availableCountries;
/**
* The field definition.
......@@ -33,35 +35,35 @@ class WidgetSettingsEvent extends Event {
protected $fieldDefinition;
/**
* Constructs a new WidgetSettingsEvent object.
* Constructs a new AvailableCountriesEvent object.
*
* @param array $settings
* The widget settings.
* @param array $availableCountries
* The available countries.
* @param \Drupal\Core\Field\FieldDefinitionInterface $fieldDefinition
* The field definition.
*/
public function __construct(array $settings, FieldDefinitionInterface $fieldDefinition) {
$this->settings = $settings;
public function __construct(array $availableCountries, FieldDefinitionInterface $fieldDefinition) {
$this->availableCountries = $availableCountries;
$this->fieldDefinition = $fieldDefinition;
}
/**
* Gets the widget settings.
* Gets the available countries.
*
* @return array
* The widget settings.
* The available countries.
*/
public function getSettings() {
return $this->settings;
public function getAvailableCountries() {
return $this->availableCountries;
}
/**
* Sets the widget settings.
* Sets the available countries.
*
* @return $this
*/
public function setSettings(array $settings) {
$this->settings = $settings;
public function setAvailableCountries(array $availableCountries) {
$this->availableCountries = $availableCountries;
return $this;
}
......
......@@ -9,6 +9,8 @@ namespace Drupal\address\Plugin\Field\FieldType;
use CommerceGuys\Addressing\Enum\AddressField;
use CommerceGuys\Addressing\Model\AddressInterface;
use Drupal\address\Event\AddressEvents;
use Drupal\address\Event\AvailableCountriesEvent;
use Drupal\address\LabelHelper;
use Drupal\Core\Field\FieldItemBase;
use Drupal\Core\Field\FieldDefinitionInterface;
......@@ -29,6 +31,13 @@ use Drupal\Core\TypedData\DataDefinition;
*/
class AddressItem extends FieldItemBase implements AddressInterface {
/**
* An altered list of available countries.
*
* @var array
*/
protected static $availableCountries = [];
/**
* {@inheritdoc}
*/
......@@ -113,6 +122,7 @@ class AddressItem extends FieldItemBase implements AddressInterface {
*/
public static function defaultFieldSettings() {
return [
'available_countries' => [],
'fields' => array_values(AddressField::getAll()),
] + parent::defaultFieldSettings();
}
......@@ -122,6 +132,15 @@ class AddressItem extends FieldItemBase implements AddressInterface {
*/
public function fieldSettingsForm(array $form, FormStateInterface $form_state) {
$element = [];
$element['available_countries'] = [
'#type' => 'select',
'#title' => $this->t('Available countries'),
'#description' => $this->t('If no countries are selected, all countries will be available.'),
'#options' => \Drupal::service('address.country_repository')->getList(),
'#default_value' => $this->getSetting('available_countries'),
'#multiple' => TRUE,
'#size' => 10,
];
$element['fields'] = [
'#type' => 'checkboxes',
'#title' => $this->t('Used fields'),
......@@ -134,6 +153,27 @@ class AddressItem extends FieldItemBase implements AddressInterface {
return $element;
}
/**
* Gets the available countries for the current field.
*
* @return array
* A list of country codes.
*/
public function getAvailableCountries() {
// Alter the list once per field, instead of once per field delta.
$fieldDefinition = $this->getFieldDefinition();
$definitionId = spl_object_hash($fieldDefinition);
if (!isset(static::$availableCountries[$definitionId])) {
$availableCountries = array_filter($this->getSetting('available_countries'));
$eventDispatcher = \Drupal::service('event_dispatcher');
$event = new AvailableCountriesEvent($availableCountries, $fieldDefinition);
$eventDispatcher->dispatch(AddressEvents::AVAILABLE_COUNTRIES, $event);
static::$availableCountries[$definitionId] = $event->getAvailableCountries();
}
return static::$availableCountries[$definitionId];
}
/**
* {@inheritdoc}
*/
......
......@@ -13,7 +13,6 @@ use CommerceGuys\Addressing\Repository\CountryRepositoryInterface;
use CommerceGuys\Addressing\Repository\SubdivisionRepositoryInterface;
use Drupal\address\Event\AddressEvents;
use Drupal\address\Event\InitialValuesEvent;
use Drupal\address\Event\WidgetSettingsEvent;
use Drupal\address\FieldHelper;
use Drupal\address\LabelHelper;
use Drupal\Component\Utility\Html;
......@@ -76,13 +75,6 @@ class AddressDefaultWidget extends WidgetBase implements ContainerFactoryPluginI
*/
protected $configFactory;
/**
* The altered settings.
*
* @var array
*/
protected $alteredSettings = [];
/**
* The size attributes for fields likely to be inlined.
*
......@@ -154,7 +146,6 @@ class AddressDefaultWidget extends WidgetBase implements ContainerFactoryPluginI
*/
public static function defaultSettings() {
return [
'available_countries' => [],
'default_country' => NULL,
] + parent::defaultSettings();
}
......@@ -166,15 +157,6 @@ class AddressDefaultWidget extends WidgetBase implements ContainerFactoryPluginI
$countryList = $this->countryRepository->getList();
$element = [];
$element['available_countries'] = [
'#type' => 'select',
'#title' => $this->t('Available countries'),
'#description' => $this->t('If no countries are selected, all countries will be available.'),
'#options' => $countryList,
'#default_value' => $this->getSetting('available_countries'),
'#multiple' => TRUE,
'#size' => 10,
];
$element['default_country'] = array(
'#type' => 'select',
'#title' => $this->t('Default country'),
......@@ -186,37 +168,6 @@ class AddressDefaultWidget extends WidgetBase implements ContainerFactoryPluginI
return $element;
}
/**
* Gets the altered settings.
*
* @return array
* The altered settings.
*/
protected function getAlteredSettings() {
if (!$this->alteredSettings) {
$event = new WidgetSettingsEvent($this->getSettings(), $this->fieldDefinition);
$this->eventDispatcher->dispatch(AddressEvents::WIDGET_SETTINGS, $event);
$this->alteredSettings = $event->getSettings();
}
return $this->alteredSettings;
}
/**
* Gets an altered setting.
*
* @param string $key
* The setting name.
*
* @return mixed
* The altered setting.
*/
protected function getAlteredSetting($key) {
$alteredSettings = $this->getAlteredSettings();
return isset($this->alteredSettings[$key]) ? $this->alteredSettings[$key] : NULL;
}
/**
* Gets the initial values for the widget.
*
......@@ -224,22 +175,24 @@ class AddressDefaultWidget extends WidgetBase implements ContainerFactoryPluginI
*
* @see address_form_field_config_edit_form_alter()
*
* @param array $countryList
* The filtered country list, in the country_code => name format.
*
* @return array
* The initial values, keyed by property.
*/
protected function getInitialValues() {
$availableCountries = $this->getAvailableCountries();
$defaultCountry = $this->getAlteredSetting('default_country');
protected function getInitialValues(array $countryList) {
$defaultCountry = $this->getSetting('default_country');
// Resolve the special site_default option.
if ($defaultCountry == 'site_default') {
$defaultCountry = $this->configFactory->get('system.date')->get('country.default');
}
// Fallback to the first country in the list if the default country is not
// available, or is empty even though the field is required.
$notAvailable = $defaultCountry && !isset($availableCountries[$defaultCountry]);
$notAvailable = $defaultCountry && !isset($countryList[$defaultCountry]);
$emptyButRequired = empty($defaultCountry) && $this->fieldDefinition->isRequired();
if ($notAvailable || $emptyButRequired) {
$defaultCountry = key($availableCountries);
$defaultCountry = key($countryList);
}
$initialValues = [
......@@ -262,25 +215,6 @@ class AddressDefaultWidget extends WidgetBase implements ContainerFactoryPluginI
return $initialValues;
}
/**
* Gets the available countries.
*
* @return array
* The available countries (countryCode => name).
*/
protected function getAvailableCountries() {
$countryList = $this->countryRepository->getList();
$availableCountries = array_filter($this->getAlteredSetting('available_countries'));
if (empty($availableCountries)) {
$availableCountries = $countryList;
}
else {
$availableCountries = array_intersect_key($countryList, $availableCountries);
}
return $availableCountries;
}
/**
* {@inheritdoc}
*/
......@@ -288,14 +222,19 @@ class AddressDefaultWidget extends WidgetBase implements ContainerFactoryPluginI
$fieldName = $this->fieldDefinition->getName();
$idPrefix = implode('-', array_merge($element['#field_parents'], [$fieldName]));
$wrapperId = Html::getUniqueId($idPrefix . '-ajax-wrapper');
$item = $items[$delta];
$availableCountries = $item->getAvailableCountries();
$countryList = $this->countryRepository->getList($locale);
if (!empty($availableCountries)) {
$countryList = array_intersect_key($countryList, $availableCountries);
}
// If the form has been rebuilt via AJAX, use the values from user input.
// $formState->getValues() can't be used here because it's empty due to
// #limit_validaiton_errors.
$parents = array_merge($element['#field_parents'], [$fieldName, $delta]);
$values = NestedArray::getValue($formState->getUserInput(), $parents, $hasInput);
if (!$hasInput) {
$item = $items[$delta];
$values = $item->isEmpty() ? $this->getInitialValues() : $item->toArray();
$values = $item->isEmpty() ? $this->getInitialValues($countryList) : $item->toArray();
}
$element += [
......@@ -318,7 +257,7 @@ class AddressDefaultWidget extends WidgetBase implements ContainerFactoryPluginI
$element['country_code'] = [
'#type' => 'select',
'#title' => $this->t('Country'),
'#options' => $this->getAvailableCountries(),
'#options' => $countryList,
'#default_value' => $values['country_code'],
'#empty_value' => '',
'#limit_validation_errors' => [],
......
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