datafield-1.x-dev/src/Plugin/DataField/FieldFormatter/HierarchicalFormatter.php
src/Plugin/DataField/FieldFormatter/HierarchicalFormatter.php
<?php
namespace Drupal\datafield\Plugin\DataField\FieldFormatter;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Field\Attribute\FieldFormatter;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\datafield\Plugin\DataFieldFormatterInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Plugin implementation of the 'entity taxonomy hierarchical label' formatter.
*/
#[FieldFormatter(
id: 'hierarchical_term_formatter',
label: new TranslatableMarkup('Hierarchical Term'),
description: new TranslatableMarkup('Provides hierarchical term formatters for taxonomy reference fields.'),
field_types: ['entity_reference'],
)]
class HierarchicalFormatter implements DataFieldFormatterInterface, ContainerFactoryPluginInterface {
use StringTranslationTrait;
/**
* Constructs a UrlPlainFormatter object.
*
* @param string $plugin_id
* The plugin_id for the formatter.
* @param mixed $plugin_definition
* The plugin implementation definition.
* @param mixed $field_definition
* The definition of the field to which the formatter is associated.
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager
* The entity type manager.
*/
public function __construct($plugin_id, $plugin_definition, $field_definition, protected EntityTypeManagerInterface $entityTypeManager) {
unset($plugin_id, $plugin_definition, $field_definition);
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, $configuration, $plugin_id, $plugin_definition) {
return new static(
$plugin_id,
$plugin_definition,
$configuration,
$container->get('entity_type.manager'),
);
}
/**
* {@inheritdoc}
*/
public static function defaultSettings() {
return [
'link' => TRUE,
'wrap' => 'ul',
'separator' => ' » ',
'reverse' => TRUE,
];
}
/**
* Returns a list of supported wrapping options.
*
* @return array
* An array whose keys are wrapper machine names
* and whose values are their labels.
*/
private function wrapOptions() {
return [
'span' => $this->t('@tag elements', ['@tag' => '<span>']),
'div' => $this->t('@tag elements', ['@tag' => '<div>']),
'ul' => $this->t('@tag elements surrounded by a @parent_tag', [
'@tag' => '<li>',
'@parent_tag' => '<ul>',
]),
'ol' => $this->t('@tag elements surrounded by a @parent_tag', [
'@tag' => '<li>',
'@parent_tag' => '<ol>',
]),
];
}
/**
* {@inheritdoc}
*/
public function settingsForm(array $form, FormStateInterface $form_state) {
$settings = $form['#settings'];
$elements['link'] = [
'#title' => $this->t('Link label to the referenced entity'),
'#type' => 'checkbox',
'#default_value' => $settings['link'] ?? self::defaultSettings()['link'],
];
$elements['reverse'] = [
'#title' => $this->t('Reverse order'),
'#description' => $this->t('If checked, children display first, parents last.'),
'#type' => 'checkbox',
'#default_value' => $settings['reverse'] ?? self::defaultSettings()['reverse'],
];
$elements['wrap'] = [
'#title' => $this->t('Wrap each term'),
'#description' => $this->t('Choose what type of html elements you would like to wrap the terms in, if any.'),
'#type' => 'select',
'#options' => $this->wrapOptions(),
'#default_value' => $settings['wrap'] ?? self::defaultSettings()['wrap'],
'#empty_options' => $this->t('None'),
];
$elements['separator'] = [
'#title' => $this->t('Separator'),
'#description' => $this->t('Enter some text or markup that will separate each term in the hierarchy. Leave blank for no separator. Example: <em>»</em>'),
'#type' => 'textfield',
'#size' => 20,
'#default_value' => $settings['separator'] ?? self::defaultSettings()['separator'],
];
return $elements;
}
/**
* {@inheritdoc}
*/
public function settingsSummary($settings = []) {
$summary = [];
$summary[] = !empty($settings['link']) ? $this->t('Link to the referenced entity') : $this->t('No link');
if (!empty($settings['wrap'])) {
$summary[] = $this->t('Wrapper: @wrapper.', ['@wrapper' => $settings['wrap']]);
}
$order = !empty($settings['reverse']) ? $this->t('Reverse') : $this->t('Natural');
$summary[] = $this->t('Order: %order.', ['%order' => $order]);
if (!empty($settings['separator'])) {
$summary[] = $this->t('Separator: "%separator".', ['%separator' => $settings['separator']]);
}
return $summary;
}
/**
* {@inheritdoc}
*/
public function viewElements($item, $langcode) {
$explode = explode(':', $item->field_setting["entity_reference_type"]);
$reference_type = end($explode);
$entity_id = $item->value;
$term_tree = $this->entityTypeManager->getStorage($reference_type)->loadAllParents($entity_id);
if (!empty($item->settings["reverse"])) {
$term_tree = array_reverse($term_tree);
}
$term_tree = array_filter($term_tree);
if (empty($term_tree)) {
return '';
}
foreach ($term_tree as $term) {
if ($term->hasTranslation($langcode)) {
$term_tree[] = $term->getTranslation($langcode);
}
}
$terms = [];
$isUl = !empty($item->settings["wrap"]) &&
in_array($item->settings["wrap"], ['ul', 'ol']);
foreach ($term_tree as $entity) {
if (!empty($item->settings["link"]) && $entity->hasLinkTemplate('canonical')) {
$terms[] = [
'#type' => 'link',
'#langcode' => $langcode,
'#title' => $entity->label(),
'#url' => $entity->toUrl(),
'#cache' => ['tags' => $entity->getCacheTags()],
'#wrapper_attributes' => [
'class' => ['list-group-item', 'breadcrumb__item'],
],
];
}
else {
$terms[] = [
'#type' => 'html_tag',
'#value' => $entity->label(),
'#tag' => $item->settings["wrap"] ?? self::defaultSettings()['wrap'],
'#langcode' => $langcode,
'#cache' => ['tags' => $entity->getCacheTags()],
'#attributes' => ['class' => ['list-group-item', 'breadcrumb__item']],
];
}
if (!empty($item->settings["separator"])) {
$tag = 'span';
if ($isUl) {
$tag = 'li';
}
$terms[] = [
'#type' => 'html_tag',
'#value' => $item->settings["separator"],
'#tag' => $tag,
'#cache' => ['tags' => $entity->getCacheTags()],
'#attributes' => ['class' => ['separator']],
];
}
}
if (!empty($item->settings["separator"])) {
array_pop($terms);
}
if ($isUl) {
return [
'#theme' => 'item_list',
'#list_type' => $item->settings["wrap"],
'#items' => $terms,
'#attributes' => [
'class' => [
'list-group',
'list-group-horizontal',
'breadcrumb__list',
],
],
'#wrapper_attributes' => ['class' => 'hierarchical'],
];
}
else {
return $terms;
}
}
}
