entity_references_map-1.0.0-alpha2/src/EntityReferencesMapBuilder.php
src/EntityReferencesMapBuilder.php
<?php
namespace Drupal\entity_references_map;
use Drupal\Component\Utility\NestedArray;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\entity_references_map\Form\MapForm;
use Drupal\node\NodeInterface;
/**
* Provides list builder for ER fields structure.
*/
class EntityReferencesMapBuilder implements EntityReferencesMapBuilderInterface {
use StringTranslationTrait;
/**
* Config Factory.
*
* @var \Drupal\Core\Config\ConfigFactoryInterface
*/
protected ConfigFactoryInterface $configFactory;
/**
* The entity type manager.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected $entityTypeManager;
/**
* Constructs EntityReferencesMapBuilder instance.
*
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
* The ConfigFactory.
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* The entity type manager.
*/
public function __construct(ConfigFactoryInterface $config_factory, EntityTypeManagerInterface $entity_type_manager) {
$this->configFactory = $config_factory;
$this->entityTypeManager = $entity_type_manager;
}
/**
* {@inheritdoc}
*/
public function build(NodeInterface $node): array {
// Initialize main variables.
$node_type = $node->getType();
$config_data = $this->configFactory->get(MapForm::CONFIG_NAME)->get();
// Return empty array if the config is empty or necessary node_type key
// doesn't exist. We can't build the tree structure without this data.
if (empty($config_data) || empty($config_data[$node_type])) {
return [];
}
$forward_reference_fields = $config_data[$node_type]['forward_reference'];
// Build Node tree main wrapper.
$tree = $this->createMapWrapper($node_type, $this->t('The @node_type_label', ['@node_type_label' => node_get_type_label($node)]), $node->getTitle());
// Loop through forward reference fields and build appropriate array for
// jHtree library.
foreach ($forward_reference_fields as $field_path) {
[
$entity_type,
$node_type,
$field_machine_name,
] = explode('.', $field_path);
// Need to ensure that the reference entity type from the field isn't in
// the excluded list.
/** @var \Drupal\field\Entity\FieldStorageConfig $field_config */
$field_config = $this->entityTypeManager
->getStorage('field_storage_config')
->load("{$entity_type}.{$field_machine_name}");
if (in_array($field_config->getSettings()['target_type'], $config_data['excluded_entity_types'] ?? [])) {
continue;
}
// We need to be sure that this field exists, and it is not empty.
// Otherwise, there is not much sense to loop through them.
if ($node->hasField($field_machine_name) && !$node->get($field_machine_name)
->isEmpty()) {
$referenced_entities = $node->get($field_machine_name)
->referencedEntities();
$header_color = NestedArray::getValue($config_data, [
'node',
$node_type,
$field_machine_name,
'header_color',
]) ?: '#cccccc';
$content_color = NestedArray::getValue($config_data, [
'node',
$node_type,
$field_machine_name,
'content_color',
]) ?: '#ffffff';
// Create a "wrapper" for the field. We need this due to the jHtree
// features.
$field_group = $this->createMapWrapper(
implode('-', [
$entity_type,
$node_type,
str_replace('_', '-', $field_machine_name),
]),
$node->get($field_machine_name)->getFieldDefinition()->getLabel(),
$field_machine_name,
$header_color,
$content_color,
);
$nested_levels = NestedArray::getValue($config_data, [
$entity_type,
$node_type,
$field_machine_name,
'nested_levels',
]);
// Safely loop through field values (we always get an array). We need
// this data for proper entity-linking of map elements.
foreach ($referenced_entities as $referenced_entity) {
$nested_levels_parameters = NestedArray::getValue($config_data, [
$entity_type,
$node_type,
$field_machine_name,
$nested_levels,
]);
if (($nested_levels === 'all')
&& !empty($childs = $this->createChildElement($referenced_entity, array_merge($nested_levels_parameters['entity_types'], $config_data['excluded_entity_types']), $nested_levels_parameters['header_color'], $nested_levels_parameters['content_color'], $nested_levels_parameters['levels_depth']))) {
$field_group['children'][] = array_merge($this->createMapElement(
$referenced_entity,
$node,
$node_type,
$header_color,
$content_color,
),
['children' => $childs]);
}
else {
$field_group['children'][] = $this->createMapElement(
$referenced_entity,
$node,
$node_type,
$header_color,
$content_color,
);
}
}
$tree['children'][] = $field_group;
}
}
return $tree;
}
/**
* {@inheritdoc}
*/
public function createMapWrapper(string $id,
string $head,
string $label,
string $header_color = '#cccccc',
string $content_color = '#ffffff'): array {
return [
'id' => $id,
'head' => $head,
'contents' => $label,
'head_color' => $header_color,
'content_color' => $content_color,
];
}
/**
* {@inheritdoc}
*/
public function createMapElement(EntityInterface $entity,
EntityInterface $parent_entity,
string $group,
string $header_color,
string $content_color,
bool $forward_reference = TRUE): array {
try {
$contents = $entity->toLink(NULL, 'canonical', [
'attributes' => ['target' => '_blank'],
])?->toString();
}
catch (\Exception) {
$contents = $entity->label();
}
return [
'id' => implode('-', [
$entity->bundle(),
$entity->id(),
$parent_entity->id(),
]) . ($forward_reference ? '-forward' : '-backward'),
'head' => $group,
'head_color' => $header_color,
'contents' => $contents,
'content_color' => $content_color,
];
}
/**
* {@inheritdoc}
*/
public function createChildElement(EntityInterface $entity, array $excluded_entity_references, string $header_color, string $content_color, int $max_depth = NULL, int $current_depth = 1): array {
$children = [];
$index = 0;
foreach ($entity->referencedEntities() as $referenced_entity) {
if (!in_array($referenced_entity->getEntityType()->id(), array_values($excluded_entity_references), TRUE)) {
$children[] = $this->createMapElement(
$referenced_entity,
$entity,
$entity->bundle(),
$header_color,
$content_color,
);
if ((empty($max_depth) || $current_depth < $max_depth) && !empty($nested_children = $this->createChildElement($referenced_entity, $excluded_entity_references, $header_color, $content_color, $max_depth, ++$current_depth))) {
$children[$index]['children'] = $nested_children;
}
++$index;
}
}
return $children;
}
}
