You are here

abstract class Base in Double Field 4.x

Same name and namespace in other branches
  1. 8.3 src/Plugin/Field/FieldFormatter/Base.php \Drupal\double_field\Plugin\Field\FieldFormatter\Base

Base class for Double field formatters.

Hierarchy

Expanded class hierarchy of Base

3 files declare their use of Base
DateTimezoneTest.php in tests/src/Functional/DateTimezoneTest.php
TestBase.php in tests/src/Functional/TestBase.php
TestBase.php in tests/src/FunctionalJavascript/TestBase.php

File

src/Plugin/Field/FieldFormatter/Base.php, line 18

Namespace

Drupal\double_field\Plugin\Field\FieldFormatter
View source
abstract class Base extends FormatterBase {

  /**
   * Subfield types that can be rendered as a link.
   *
   * @var array
   */
  protected static $linkTypes = [
    'email',
    'telephone',
    'uri',
  ];

  /**
   * {@inheritdoc}
   */
  public static function defaultSettings() : array {
    $settings = [];
    foreach ([
      'first',
      'second',
    ] as $subfield) {
      $settings[$subfield] = [
        // Hidden option is useful to display data with Views module.
        'hidden' => FALSE,
        'link' => FALSE,
        'format_type' => 'medium',
        // @todo Create tests for this options.
        'thousand_separator' => '',
        'decimal_separator' => '.',
        'scale' => 2,
        'key' => FALSE,
      ];
    }
    return $settings + parent::defaultSettings();
  }

  /**
   * {@inheritdoc}
   */
  public function settingsForm(array $form, FormStateInterface $form_state) : array {
    $settings = $this
      ->getSettings();
    $field_settings = $this
      ->getFieldSettings();
    $types = DoubleFieldItem::subfieldTypes();
    $element = [];

    // General settings.
    foreach ([
      'first',
      'second',
    ] as $subfield) {
      $type = $field_settings['storage'][$subfield]['type'];
      $title = $subfield == 'first' ? $this
        ->t('First subfield') : $this
        ->t('Second subfield');
      $title .= ' - ' . $types[$type];
      if ($field_settings[$subfield]['list']) {
        $title .= ' (' . $this
          ->t('list') . ')';
      }
      $element[$subfield] = [
        '#title' => $title,
        '#type' => 'details',
      ];
      $element[$subfield]['link'] = [
        '#type' => 'checkbox',
        '#title' => $this
          ->t('Display as link'),
        '#default_value' => $settings[$subfield]['link'],
        '#weight' => -10,
        '#access' => in_array($type, static::$linkTypes),
      ];
      if ($type == 'datetime_iso8601') {
        $format_types = DateFormat::loadMultiple();
        $date_formatter = static::getDateFormatter();
        $time = new DrupalDateTime();
        $options = [];
        foreach ($format_types as $type => $type_info) {
          $format = $date_formatter
            ->format($time
            ->getTimestamp(), $type);
          $options[$type] = $type_info
            ->label() . ' (' . $format . ')';
        }
        $element[$subfield]['format_type'] = [
          '#type' => 'select',
          '#title' => $this
            ->t('Date format'),
          '#description' => $this
            ->t('Choose a format for displaying the date.'),
          '#options' => $options,
          '#default_value' => $settings[$subfield]['format_type'],
        ];
      }
      else {
        $element[$subfield]['format_type'] = [
          '#type' => 'value',
          '#default_value' => $settings[$subfield]['format_type'],
        ];
      }
      $element[$subfield]['hidden'] = [
        '#type' => 'checkbox',
        '#title' => $this
          ->t('Hidden'),
        '#default_value' => $settings[$subfield]['hidden'],
      ];
      if ($field_settings[$subfield]['list']) {
        $element[$subfield]['key'] = [
          '#type' => 'checkbox',
          '#title' => $this
            ->t('Display key instead of label'),
          // @todo Remove the fallback on 5.x.
          '#default_value' => $settings[$subfield]['key'] ?? FALSE,
        ];
      }
      if ($type == 'numeric' || $type == 'float' || $type == 'integer') {
        $options = [
          '' => $this
            ->t('- None -'),
          '.' => $this
            ->t('Decimal point'),
          ',' => $this
            ->t('Comma'),
          ' ' => $this
            ->t('Space'),
          chr(8201) => $this
            ->t('Thin space'),
          "'" => $this
            ->t('Apostrophe'),
        ];
        $element[$subfield]['thousand_separator'] = [
          '#type' => 'select',
          '#title' => $this
            ->t('Thousand marker'),
          '#options' => $options,
          '#default_value' => $settings[$subfield]['thousand_separator'],
        ];
      }
      else {
        $element[$subfield]['thousand_separator'] = [
          '#type' => 'value',
          '#default_value' => $settings[$subfield]['thousand_separator'],
        ];
      }
      if ($type == 'numeric' || $type == 'float') {
        $element[$subfield]['decimal_separator'] = [
          '#type' => 'select',
          '#title' => $this
            ->t('Decimal marker'),
          '#options' => [
            '.' => $this
              ->t('Decimal point'),
            ',' => $this
              ->t('Comma'),
          ],
          '#default_value' => $settings[$subfield]['decimal_separator'],
        ];
        $element[$subfield]['scale'] = [
          '#type' => 'number',
          '#title' => $this
            ->t('Scale', [], [
            'context' => 'decimal places',
          ]),
          '#min' => 0,
          '#max' => 10,
          '#default_value' => $settings[$subfield]['scale'],
          '#description' => $this
            ->t('The number of digits to the right of the decimal.'),
        ];
      }
      else {
        $element[$subfield]['decimal_separator'] = [
          '#type' => 'value',
          '#default_value' => $settings[$subfield]['decimal_separator'],
        ];
        $element[$subfield]['scale'] = [
          '#type' => 'value',
          '#default_value' => $settings[$subfield]['scale'],
        ];
      }
    }
    return $element;
  }

  /**
   * {@inheritdoc}
   */
  public function settingsSummary() : array {
    $settings = $this
      ->getSettings();
    $field_settings = $this
      ->getFieldSettings();
    $subfield_types = DoubleFieldItem::subfieldTypes();
    $summary = [];
    foreach ([
      'first',
      'second',
    ] as $subfield) {
      $subfield_type = $field_settings['storage'][$subfield]['type'];
      $summary[] = new FormattableMarkup('<b>@subfield - @subfield_type@list</b>', [
        '@subfield' => $subfield == 'first' ? $this
          ->t('First subfield') : $this
          ->t('Second subfield'),
        '@subfield_type' => strtolower($subfield_types[$subfield_type]),
        '@list' => $field_settings[$subfield]['list'] ? ' (' . $this
          ->t('list') . ')' : '',
      ]);
      if ($subfield_type == 'datetime_iso8601') {
        $summary[] = $this
          ->t('Date format: @format', [
          '@format' => $settings[$subfield]['format_type'],
        ]);
      }
      if (in_array($subfield_type, static::$linkTypes)) {
        $summary[] = $this
          ->t('Link: @value', [
          '@value' => $settings[$subfield]['link'] ? $this
            ->t('yes') : $this
            ->t('no'),
        ]);
      }
      $summary[] = $this
        ->t('Hidden: @value', [
        '@value' => $settings[$subfield]['hidden'] ? $this
          ->t('yes') : $this
          ->t('no'),
      ]);
      if ($field_settings[$subfield]['list']) {

        // @todo Remove the fallback in 5.x.
        $display_key = $settings[$subfield]['key'] ?? FALSE;
        $summary[] = $this
          ->t('Display key: @value', [
          '@value' => $display_key ? $this
            ->t('yes') : $this
            ->t('no'),
        ]);
      }
      if ($subfield_type == 'numeric' || $subfield_type == 'float' || $subfield_type == 'integer') {
        $summary[] = $this
          ->t('Number format: @format', [
          '@format' => $this
            ->numberFormat($subfield, 1234.123456789),
        ]);
      }
    }
    return $summary;
  }

  /**
   * {@inheritdoc}
   */
  public function view(FieldItemListInterface $items, $langcode = NULL) : array {
    $elements = [];
    if (count($items) > 0) {

      // A field may appear multiple times in a single view. Since items are
      // passed by reference we need to ensure they are processed only once.
      $items = clone $items;
      $this
        ->prepareItems($items);
      $elements = parent::view($items, $langcode);
    }
    return $elements;
  }

  /**
   * Prepare field items.
   *
   * @param \Drupal\Core\Field\FieldItemListInterface $items
   *   List of field items.
   */
  protected function prepareItems(FieldItemListInterface $items) : void {
    $field_settings = $this
      ->getFieldSettings();
    $settings = $this
      ->getSettings();
    foreach ($items as $delta => $item) {
      foreach ([
        'first',
        'second',
      ] as $subfield) {
        if ($settings[$subfield]['hidden']) {
          $item->{$subfield} = NULL;
        }
        else {
          $type = $field_settings['storage'][$subfield]['type'];
          if ($type == 'boolean') {
            $item->{$subfield} = $field_settings[$subfield][$item->{$subfield} ? 'on_label' : 'off_label'];
          }

          // Empty string should already be converted into NULL.
          // @see Drupal\double_field\Plugin\Field\FieldWidget\DoubleField::massageFormValues()
          if ($item->{$subfield} === NULL) {
            continue;
          }
          if ($type == 'numeric' || $type == 'float' || $type == 'integer') {
            $item->{$subfield} = $this
              ->numberFormat($subfield, $item->{$subfield});
          }
          if ($type == 'datetime_iso8601' && $item->{$subfield} && !$field_settings[$subfield]['list']) {

            // We follow the same principles as Drupal Core.
            // In the case of a datetime subfield, the date must be parsed using
            // the storage time zone and converted to the user's time zone while
            // a date-only field should have no timezone conversion performed.
            $timezone = $field_settings['storage'][$subfield]['datetime_type'] === 'datetime' ? date_default_timezone_get() : DoubleFieldItem::DATETIME_STORAGE_TIMEZONE;
            $timestamp = $items[$delta]
              ->createDate($subfield)
              ->getTimestamp();
            $date_formatter = static::getDateFormatter();
            $item->{$subfield} = [
              '#theme' => 'time',
              '#text' => $date_formatter
                ->format($timestamp, $settings[$subfield]['format_type'], '', $timezone),
              '#html' => FALSE,
              '#attributes' => [
                'datetime' => $date_formatter
                  ->format($timestamp, 'custom', 'Y-m-d\\TH:i:s') . 'Z',
              ],
              '#cache' => [
                'contexts' => [
                  'timezone',
                ],
              ],
            ];
          }
          $original_value[$subfield] = $item->{$subfield};
          if ($field_settings[$subfield]['list']) {

            // @todo Remove the fallback in 5.x.
            $display_key = $settings[$subfield]['key'] ?? FALSE;
            if (!$display_key) {

              // Replace the value with its label if possible.
              $item->{$subfield} = $field_settings[$subfield]['allowed_values'][$item->{$subfield}] ?? NULL;
            }
          }
          if (!empty($settings[$subfield]['link'])) {
            $value = isset($original_value) ? $original_value[$subfield] : $item->{$subfield};
            switch ($type) {
              case 'email':
                $item->{$subfield} = [
                  '#type' => 'link',
                  '#title' => $item->{$subfield},
                  '#url' => Url::fromUri('mailto:' . $value),
                ];
                break;
              case 'telephone':
                $item->{$subfield} = [
                  '#type' => 'link',
                  '#title' => $item->{$subfield},
                  '#url' => Url::fromUri('tel:' . rawurlencode(preg_replace('/\\s+/', '', $value))),
                  '#options' => [
                    'external' => TRUE,
                  ],
                ];
                break;
              case 'uri':
                $item->{$subfield} = [
                  '#type' => 'link',
                  '#title' => $item->{$subfield},
                  '#url' => Url::fromUri($value),
                  '#options' => [
                    'external' => TRUE,
                  ],
                ];
                break;
            }
          }
        }
      }
      $items[$delta] = $item;
    }
  }

  /**
   * Formats a number.
   */
  protected function numberFormat(string $subfield, string $number) : string {
    $settings = $this
      ->getSetting($subfield);
    if ($this
      ->getFieldSetting('storage')[$subfield]['type'] == 'integer') {
      $settings['scale'] = 0;
    }
    return number_format($number, $settings['scale'], $settings['decimal_separator'], $settings['thousand_separator']);
  }

  /**
   * Returns date formatter.
   */
  protected static function getDateFormatter() : DateFormatterInterface {
    return \Drupal::service('date.formatter');
  }

}

Members

Namesort descending Modifiers Type Description Overrides
Base::$linkTypes protected static property Subfield types that can be rendered as a link.
Base::defaultSettings public static function Defines the default settings for this plugin. Overrides PluginSettingsBase::defaultSettings 3
Base::getDateFormatter protected static function Returns date formatter.
Base::numberFormat protected function Formats a number.
Base::prepareItems protected function Prepare field items.
Base::settingsForm public function Returns a form to configure settings for the formatter. Overrides FormatterBase::settingsForm 3
Base::settingsSummary public function Returns a short summary for the current formatter settings. Overrides FormatterBase::settingsSummary 3
Base::view public function Builds a renderable array for a fully themed field. Overrides FormatterBase::view
DependencySerializationTrait::$_entityStorages protected property
DependencySerializationTrait::$_serviceIds protected property
DependencySerializationTrait::__sleep public function 2
DependencySerializationTrait::__wakeup public function 2
FormatterBase::$fieldDefinition protected property The field definition.
FormatterBase::$label protected property The label display setting.
FormatterBase::$settings protected property The formatter settings. Overrides PluginSettingsBase::$settings
FormatterBase::$viewMode protected property The view mode.
FormatterBase::create public static function Creates an instance of the plugin. Overrides ContainerFactoryPluginInterface::create 12
FormatterBase::getFieldSetting protected function Returns the value of a field setting.
FormatterBase::getFieldSettings protected function Returns the array of field settings.
FormatterBase::isApplicable public static function Returns if the formatter can be used for the provided field. Overrides FormatterInterface::isApplicable 14
FormatterBase::prepareView public function Allows formatters to load information for field values being displayed. Overrides FormatterInterface::prepareView 2
FormatterBase::__construct public function Constructs a FormatterBase object. Overrides PluginBase::__construct 12
FormatterInterface::viewElements public function Builds a renderable array for a field value. 47
MessengerTrait::$messenger protected property The messenger. 27
MessengerTrait::messenger public function Gets the messenger. 27
MessengerTrait::setMessenger public function Sets the messenger.
PluginBase::$configuration protected property Configuration information passed into the plugin. 1
PluginBase::$pluginDefinition protected property The plugin implementation definition. 1
PluginBase::$pluginId protected property The plugin_id.
PluginBase::DERIVATIVE_SEPARATOR constant A string which is used to separate base plugin IDs from the derivative ID.
PluginBase::getBaseId public function Gets the base_plugin_id of the plugin instance. Overrides DerivativeInspectionInterface::getBaseId
PluginBase::getDerivativeId public function Gets the derivative_id of the plugin instance. Overrides DerivativeInspectionInterface::getDerivativeId
PluginBase::getPluginDefinition public function Gets the definition of the plugin implementation. Overrides PluginInspectionInterface::getPluginDefinition 2
PluginBase::getPluginId public function Gets the plugin_id of the plugin instance. Overrides PluginInspectionInterface::getPluginId
PluginBase::isConfigurable public function Determines if the plugin is configurable.
PluginSettingsBase::$defaultSettingsMerged protected property Whether default settings have been merged into the current $settings.
PluginSettingsBase::$thirdPartySettings protected property The plugin settings injected by third party modules.
PluginSettingsBase::calculateDependencies public function Calculates dependencies for the configured plugin. Overrides DependentPluginInterface::calculateDependencies 6
PluginSettingsBase::getSetting public function Returns the value of a setting, or its default value if absent. Overrides PluginSettingsInterface::getSetting
PluginSettingsBase::getSettings public function Returns the array of settings, including defaults for missing settings. Overrides PluginSettingsInterface::getSettings
PluginSettingsBase::getThirdPartyProviders public function Gets the list of third parties that store information. Overrides ThirdPartySettingsInterface::getThirdPartyProviders
PluginSettingsBase::getThirdPartySetting public function Gets the value of a third-party setting. Overrides ThirdPartySettingsInterface::getThirdPartySetting
PluginSettingsBase::getThirdPartySettings public function Gets all third-party settings of a given module. Overrides ThirdPartySettingsInterface::getThirdPartySettings
PluginSettingsBase::mergeDefaults protected function Merges default settings values into $settings.
PluginSettingsBase::onDependencyRemoval public function Informs the plugin that some configuration it depends on will be deleted. Overrides PluginSettingsInterface::onDependencyRemoval 3
PluginSettingsBase::setSetting public function Sets the value of a setting for the plugin. Overrides PluginSettingsInterface::setSetting
PluginSettingsBase::setSettings public function Sets the settings for the plugin. Overrides PluginSettingsInterface::setSettings
PluginSettingsBase::setThirdPartySetting public function Sets the value of a third-party setting. Overrides ThirdPartySettingsInterface::setThirdPartySetting
PluginSettingsBase::unsetThirdPartySetting public function Unsets a third-party setting. Overrides ThirdPartySettingsInterface::unsetThirdPartySetting
StringTranslationTrait::$stringTranslation protected property The string translation service. 4
StringTranslationTrait::formatPlural protected function Formats a string containing a count of items.
StringTranslationTrait::getNumberOfPlurals protected function Returns the number of plurals supported by a given language.
StringTranslationTrait::getStringTranslation protected function Gets the string translation service.
StringTranslationTrait::setStringTranslation public function Sets the string translation service to use. 2
StringTranslationTrait::t protected function Translates a string to the current language or to a given language.