Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
116 / 116
100.00% covered (success)
100.00%
8 / 8
CRAP
100.00% covered (success)
100.00%
1 / 1
NameFormatter
100.00% covered (success)
100.00%
116 / 116
100.00% covered (success)
100.00%
8 / 8
22
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
1
 create
100.00% covered (success)
100.00%
14 / 14
100.00% covered (success)
100.00%
1 / 1
1
 defaultSettings
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
1
 settingsForm
100.00% covered (success)
100.00%
36 / 36
100.00% covered (success)
100.00%
1 / 1
2
 settingsSummary
100.00% covered (success)
100.00%
15 / 15
100.00% covered (success)
100.00%
1 / 1
2
 viewElements
100.00% covered (success)
100.00%
23 / 23
100.00% covered (success)
100.00%
1 / 1
9
 parseAdditionalComponents
100.00% covered (success)
100.00%
12 / 12
100.00% covered (success)
100.00%
1 / 1
5
 getFieldDefinition
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3declare(strict_types=1);
4
5namespace Drupal\name\Plugin\Field\FieldFormatter;
6
7use Drupal\Core\Field\Attribute\FieldFormatter;
8use Drupal\Core\Field\FieldDefinitionInterface;
9use Drupal\Core\Field\FieldItemListInterface;
10use Drupal\Core\Field\FormatterBase;
11use Drupal\Core\Form\FormStateInterface;
12use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
13use Drupal\Core\StringTranslation\TranslatableMarkup;
14use Drupal\name\Service\AdditionalComponentInterface;
15use Drupal\name\Service\FormatOptionInterface;
16use Drupal\name\Service\LinkTargetInterface;
17use Drupal\name\Service\NameFormatterInterface;
18use Drupal\name\Service\NameFormatterSummaryInterface;
19use Drupal\name\Traits\NameAdditionalPreferredTrait;
20use Drupal\name\Utility\NameFormatHelp;
21use Symfony\Component\DependencyInjection\ContainerInterface;
22
23/**
24 * Plugin implementation of the 'name' formatter.
25 *
26 * The 'Default' formatter is different for integer fields on the one hand, and
27 * for decimal and float fields on the other hand, in order to be able to use
28 * different settings.
29 */
30#[FieldFormatter(
31  id: "name_default",
32  label: new TranslatableMarkup("Name formatter"),
33  field_types: ["name"]
34)]
35class NameFormatter extends FormatterBase implements ContainerFactoryPluginInterface {
36
37  use NameAdditionalPreferredTrait;
38
39  /**
40   * The name formatter.
41   *
42   * @var \Drupal\name\Service\NameFormatterInterface
43   */
44  protected $formatter;
45
46  /**
47   * Format entity label/pattern options.
48   *
49   * @var \Drupal\name\Service\FormatOptionInterface|null
50   */
51  protected $formatOptions;
52
53  /**
54   * Additional component values for preferred/alternative references.
55   *
56   * @var \Drupal\name\Service\AdditionalComponentInterface|null
57   */
58  protected $additionalComponent;
59
60  /**
61   * Resolves formatter link targets and URLs.
62   *
63   * @var \Drupal\name\Service\LinkTargetInterface
64   */
65  protected LinkTargetInterface $linkTarget;
66
67  /**
68   * Builds formatter settings summary lines.
69   *
70   * @var \Drupal\name\Service\NameFormatterSummaryInterface
71   */
72  protected NameFormatterSummaryInterface $formatterSummary;
73
74  /**
75   * Constructs a NameFormatter instance.
76   *
77   * @param string $plugin_id
78   *   The plugin_id for the formatter.
79   * @param mixed $plugin_definition
80   *   The plugin implementation definition.
81   * @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition
82   *   The definition of the field to which the formatter is associated.
83   * @param array $settings
84   *   The formatter settings.
85   * @param string $label
86   *   The formatter label display setting.
87   * @param string $view_mode
88   *   The view mode.
89   * @param array $third_party_settings
90   *   Any third party settings settings.
91   * @param \Drupal\name\Service\NameFormatterInterface $formatter
92   *   The name formatter.
93   * @param \Drupal\name\Service\FormatOptionInterface|null $format_options
94   *   The name format options service.
95   * @param \Drupal\name\Service\AdditionalComponentInterface|null $additional_component
96   *   The additional component resolver.
97   * @param \Drupal\name\Service\LinkTargetInterface $link_target
98   *   The link target service.
99   * @param \Drupal\name\Service\NameFormatterSummaryInterface $formatter_summary
100   *   The formatter settings summary builder.
101   */
102  public function __construct($plugin_id, $plugin_definition, FieldDefinitionInterface $field_definition, array $settings, $label, $view_mode, array $third_party_settings, NameFormatterInterface $formatter, ?FormatOptionInterface $format_options, ?AdditionalComponentInterface $additional_component, LinkTargetInterface $link_target, NameFormatterSummaryInterface $formatter_summary) {
103    parent::__construct($plugin_id, $plugin_definition, $field_definition, $settings, $label, $view_mode, $third_party_settings);
104
105    $this->formatter = $formatter;
106    $this->formatOptions = $format_options;
107    $this->additionalComponent = $additional_component;
108    $this->linkTarget = $link_target;
109    $this->formatterSummary = $formatter_summary;
110  }
111
112  /**
113   * {@inheritdoc}
114   */
115  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
116    return new static(
117      $plugin_id,
118      $plugin_definition,
119      $configuration['field_definition'],
120      $configuration['settings'],
121      $configuration['label'],
122      $configuration['view_mode'],
123      $configuration['third_party_settings'],
124      $container->get('name.formatter'),
125      $container->get('name.format_options', ContainerInterface::NULL_ON_INVALID_REFERENCE),
126      $container->get('name.additional_component', ContainerInterface::NULL_ON_INVALID_REFERENCE),
127      $container->get('name.link_target'),
128      $container->get('name.formatter_summary'),
129    );
130  }
131
132  /**
133   * {@inheritdoc}
134   */
135  public static function defaultSettings() {
136    $settings = parent::defaultSettings();
137    $settings += [
138      "format" => "default",
139      "markup" => "none",
140      "list_format" => "",
141      "link_target" => "",
142    ];
143    $settings += self::getDefaultAdditionalPreferredSettings();
144    return $settings;
145  }
146
147  /**
148   * {@inheritdoc}
149   */
150  public function settingsForm(array $form, FormStateInterface $form_state) {
151    $elements = parent::settingsForm($form, $form_state);
152    $elements['format'] = [
153      '#type' => 'select',
154      '#title' => $this->t('Name format'),
155      '#default_value' => $this->getSetting('format'),
156      '#options' => $this->formatOptions?->getCustomFormatOptions() ?? [],
157      '#required' => TRUE,
158    ];
159
160    $elements['list_format'] = [
161      '#type' => 'select',
162      '#title' => $this->t('List format'),
163      '#default_value' => $this->getSetting('list_format'),
164      '#empty_option' => $this->t('-- individually --'),
165      '#options' => $this->formatOptions?->getCustomListFormatOptions() ?? [],
166    ];
167
168    $elements['markup'] = [
169      '#type' => 'select',
170      '#title' => $this->t('Markup'),
171      '#default_value' => $this->getSetting('markup'),
172      '#options' => NameFormatHelp::markupOptions(),
173      '#description' => $this->t('This option wraps the individual components of the name in SPAN elements with corresponding classes to the component.'),
174      '#required' => TRUE,
175    ];
176    if (!empty($this->fieldDefinition->getTargetBundle())) {
177      $elements['link_target'] = [
178        '#type' => 'select',
179        '#title' => $this->t('Link Target'),
180        '#default_value' => $this->getSetting('link_target'),
181        '#empty_option' => $this->t('-- no link --'),
182        '#options' => $this->linkTarget->getTargets(
183          $this->fieldDefinition,
184          $this->t('Entity URL'),
185        ),
186      ];
187
188      $elements += $this->getNameAdditionalPreferredSettingsForm();
189    }
190    return $elements;
191  }
192
193  /**
194   * {@inheritdoc}
195   */
196  public function settingsSummary() {
197    $settings = $this->getSettings();
198    $link_targets = !empty($settings['link_target'])
199      ? $this->linkTarget->getTargets(
200        $this->fieldDefinition,
201        $this->t('Entity URL'),
202      )
203      : NULL;
204
205    $summary = $this->formatterSummary->build(
206      $settings,
207      $this->fieldDefinition,
208      $this->getSetting('markup'),
209      $link_targets,
210    );
211
212    $this->settingsNameAdditionalPreferredSummary($summary);
213
214    return $summary;
215  }
216
217  /**
218   * {@inheritdoc}
219   */
220  public function viewElements(FieldItemListInterface $items, $langcode) {
221    $elements = [];
222    $items_count = $items->count();
223    if (!$items_count) {
224      return $elements;
225    }
226
227    $settings = $this->settings;
228
229    $format = $settings['format'] ?? 'default';
230    $is_multiple = $this->fieldDefinition->getFieldStorageDefinition()->isMultiple() && $items_count > 1;
231    $list_format = $is_multiple && !empty($settings['list_format']) ? $settings['list_format'] : '';
232
233    $extra = $this->parseAdditionalComponents($items);
234    $extra['url'] = empty($settings['link_target'])
235      ? NULL
236      : $this->linkTarget->resolveUrl($items, $settings['link_target']);
237
238    $item_array = [];
239    foreach ($items as $item) {
240      $components = $item->toArray() + $extra;
241      $item_array[] = $components;
242    }
243
244    $this->formatter->setSetting('markup', $this->getSetting('markup'));
245
246    if ($list_format) {
247      $elements[0]['#markup'] = $this->formatter->formatList($item_array, $format, $list_format, $langcode);
248      return $elements;
249    }
250
251    foreach ($item_array as $delta => $item) {
252      $elements[$delta]['#markup'] = $this->formatter->format($item, $format, $langcode);
253    }
254
255    return $elements;
256  }
257
258  /**
259   * Gets any additional linked components.
260   *
261   * @param \Drupal\Core\Field\FieldItemListInterface $items
262   *   The name formatters FieldItemList.
263   *
264   * @return array
265   *   An array of any additional components if set.
266   */
267  protected function parseAdditionalComponents(FieldItemListInterface $items) {
268    $extra = [];
269    foreach (['preferred', 'alternative'] as $key) {
270      $key_value = $this->getSetting($key . '_field_reference');
271      $sep_value = $this->getSetting($key . '_field_reference_separator');
272      if (!$key_value) {
273        $key_value = $this->fieldDefinition->getSetting($key . '_field_reference');
274        $sep_value = $this->fieldDefinition->getSetting($key . '_field_reference_separator');
275      }
276      if ($this->additionalComponent) {
277        $value = $this->additionalComponent->getAdditionalComponent($items, $key_value, $sep_value);
278        if ($value) {
279          $extra[$key] = $value;
280        }
281      }
282    }
283
284    return $extra;
285  }
286
287  /**
288   * Gets the field definition.
289   *
290   * This is used by NameAdditionalPreferredTrait.
291   *
292   * @return \Drupal\Core\Field\FieldDefinitionInterface
293   *   The field definition.
294   */
295  protected function getFieldDefinition() {
296    return $this->fieldDefinition;
297  }
298
299}