Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
90 / 90
100.00% covered (success)
100.00%
7 / 7
CRAP
100.00% covered (success)
100.00%
1 / 1
NameFormatterSummaryService
100.00% covered (success)
100.00%
90 / 90
100.00% covered (success)
100.00%
7 / 7
18
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 build
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 buildCore
100.00% covered (success)
100.00%
25 / 25
100.00% covered (success)
100.00%
1 / 1
4
 buildExample
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
2
 listFormatSummary
100.00% covered (success)
100.00%
13 / 13
100.00% covered (success)
100.00%
1 / 1
3
 formatEntitySummary
100.00% covered (success)
100.00%
18 / 18
100.00% covered (success)
100.00%
1 / 1
2
 exampleSummary
100.00% covered (success)
100.00%
21 / 21
100.00% covered (success)
100.00%
1 / 1
5
1<?php
2
3declare(strict_types=1);
4
5namespace Drupal\name\Service;
6
7use Drupal\Component\Render\FormattableMarkup;
8use Drupal\Core\Entity\EntityTypeManagerInterface;
9use Drupal\Core\Field\FieldDefinitionInterface;
10use Drupal\Core\StringTranslation\TranslatableMarkup;
11use Drupal\Core\StringTranslation\TranslationInterface;
12use Drupal\name\Utility\NameFormatHelp;
13
14/**
15 * Builds formatter settings summary lines for the name field.
16 *
17 * @internal
18 */
19final class NameFormatterSummaryService implements NameFormatterSummaryInterface {
20
21  /**
22   * Constructs a NameFormatterSummaryService.
23   *
24   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager
25   *   The entity type manager.
26   * @param \Drupal\name\Service\GeneratorInterface $generator
27   *   The name generator.
28   * @param \Drupal\name\Service\NameFormatterInterface $formatter
29   *   The name formatter service.
30   * @param \Drupal\Core\StringTranslation\TranslationInterface $stringTranslation
31   *   The string translation service.
32   */
33  public function __construct(
34    private readonly EntityTypeManagerInterface $entityTypeManager,
35    private readonly GeneratorInterface $generator,
36    private readonly NameFormatterInterface $formatter,
37    private readonly TranslationInterface $stringTranslation,
38  ) {}
39
40  /**
41   * {@inheritdoc}
42   */
43  public function build(
44    array $settings,
45    FieldDefinitionInterface $fieldDefinition,
46    string $markup,
47    ?array $linkTargets,
48  ): array {
49    $summary = $this->buildCore($settings, $markup, $linkTargets);
50
51    return array_merge($summary, $this->buildExample($settings, $fieldDefinition, $markup));
52  }
53
54  /**
55   * Builds core settings summary lines (excluding preferred/alternative).
56   *
57   * @param array $settings
58   *   Formatter settings.
59   * @param string $markup
60   *   The configured markup mode.
61   * @param array<string, \Drupal\Core\StringTranslation\TranslatableMarkup|string>|null $linkTargets
62   *   Link target options, or NULL when not applicable.
63   *
64   * @return array
65   *   Summary render array lines.
66   */
67  private function buildCore(
68    array $settings,
69    string $markup,
70    ?array $linkTargets,
71  ): array {
72    $summary = [];
73
74    $machine_name = $settings['format'] ?? 'default';
75    $name_format = $this->entityTypeManager->getStorage('name_format')->load($machine_name);
76    $summary = array_merge($summary, $this->formatEntitySummary(
77      'Format',
78      $name_format,
79      $this->stringTranslation->translate('Missing format.'),
80      $this->stringTranslation->translate('This field will be displayed using the Default format.'),
81    ));
82
83    $summary = array_merge($summary, $this->listFormatSummary($settings));
84
85    $markup_options = NameFormatHelp::markupOptions();
86    $summary[] = $this->stringTranslation->translate('Markup: @type', [
87      '@type' => $markup_options[$markup],
88    ]);
89
90    $has_link_target = (
91      !empty($settings['link_target']) && $linkTargets !== NULL
92    );
93    if ($has_link_target) {
94      $target_key = $settings['link_target'];
95      $summary[] = $this->stringTranslation->translate('Link: @target', [
96        '@target' => empty($linkTargets[$target_key])
97          ? $this->stringTranslation->translate('-- invalid --')
98          : $linkTargets[$target_key],
99      ]);
100    }
101
102    return $summary;
103  }
104
105  /**
106   * Appends an example output line when a name format is configured.
107   *
108   * @param array $settings
109   *   Formatter settings.
110   * @param \Drupal\Core\Field\FieldDefinitionInterface $fieldDefinition
111   *   The name field definition.
112   * @param string $markup
113   *   The configured markup mode.
114   *
115   * @return array
116   *   Zero or one example summary line.
117   */
118  private function buildExample(
119    array $settings,
120    FieldDefinitionInterface $fieldDefinition,
121    string $markup,
122  ): array {
123    $machine_name = $settings['format'] ?? 'default';
124    $name_format = $this->entityTypeManager->getStorage('name_format')->load($machine_name);
125    if (!$name_format) {
126      return [];
127    }
128
129    $format_id = $name_format->id() ?? $machine_name;
130
131    return $this->exampleSummary(
132      $format_id,
133      $fieldDefinition,
134      $markup,
135    );
136  }
137
138  /**
139   * Builds list format summary lines.
140   *
141   * @param array $settings
142   *   Formatter settings.
143   *
144   * @return array
145   *   Summary lines for list format.
146   */
147  private function listFormatSummary(array $settings): array {
148    $uses_individual_list = (
149      !isset($settings['list_format']) || $settings['list_format'] === ''
150    );
151    if ($uses_individual_list) {
152      return [$this->stringTranslation->translate('List format: Individually')];
153    }
154
155    $machine_name = $settings['list_format'] ?? 'default';
156    $name_list_format = $this->entityTypeManager->getStorage('name_list_format')->load($machine_name);
157
158    return $this->formatEntitySummary(
159      'List format',
160      $name_list_format,
161      $this->stringTranslation->translate('Missing list format.'),
162      $this->stringTranslation->translate('This field will be displayed using the Default list format.'),
163    );
164  }
165
166  /**
167   * Builds summary lines for a format config entity.
168   *
169   * @param string $label_prefix
170   *   Summary label prefix (e.g. "Format").
171   * @param object|null $entity
172   *   The loaded format entity, or NULL when missing.
173   * @param \Drupal\Core\StringTranslation\TranslatableMarkup $missingText
174   *   Text shown when the format is missing.
175   * @param \Drupal\Core\StringTranslation\TranslatableMarkup $fallbackText
176   *   Fallback description when the format is missing.
177   *
178   * @return array
179   *   One or two summary lines.
180   */
181  private function formatEntitySummary(
182    string $label_prefix,
183    ?object $entity,
184    TranslatableMarkup|string $missingText,
185    TranslatableMarkup|string $fallbackText,
186  ): array {
187    if (!$entity) {
188      return [
189        $this->stringTranslation->translate('@label: @missing@line_break@fallback', [
190          '@label' => $label_prefix,
191          '@missing' => new FormattableMarkup('<strong>@text</strong>', [
192            '@text' => $missingText,
193          ]),
194          '@line_break' => new FormattableMarkup('<br/>', []),
195          '@fallback' => $fallbackText,
196        ]),
197      ];
198    }
199
200    return [
201      $this->stringTranslation->translate('@label: @format (@machine_name)', [
202        '@label' => $label_prefix,
203        '@format' => $entity->label(),
204        '@machine_name' => $entity->id(),
205      ]),
206    ];
207  }
208
209  /**
210   * Builds an example output summary line when sample data exists.
211   *
212   * @param string $formatId
213   *   The name format machine name.
214   * @param \Drupal\Core\Field\FieldDefinitionInterface $fieldDefinition
215   *   The name field definition.
216   * @param string $markup
217   *   The configured markup mode.
218   *
219   * @return array
220   *   Zero or one example summary line.
221   */
222  private function exampleSummary(
223    string $formatId,
224    FieldDefinitionInterface $fieldDefinition,
225    string $markup,
226  ): array {
227    $names = $this->generator->loadSampleValues(1, $fieldDefinition);
228    $name = is_array($names) && $names !== [] ? reset($names) : NULL;
229    if (!$name) {
230      return [];
231    }
232
233    $previous_markup = $this->formatter->getSetting('markup');
234    $this->formatter->setSetting('markup', $markup);
235    $formatted = $this->formatter->format($name, $formatId);
236    $this->formatter->setSetting('markup', $previous_markup);
237
238    if (empty($formatted)) {
239      return [
240        $this->stringTranslation->translate('Example: @empty', [
241          '@empty' => new FormattableMarkup('<em>@text</em>', [
242            '@text' => '<<empty>>',
243          ]),
244        ]),
245      ];
246    }
247
248    return [
249      $this->stringTranslation->translate('Example: @example', [
250        '@example' => $formatted,
251      ]),
252    ];
253  }
254
255}