Browse Source

added usage count

main
astanley 4 days ago
parent
commit
e7d03ed94c
  1. 7
      css/metadata_profile.css
  2. 19
      metadata_profile.module
  3. 433
      src/Controller/MetadataProfileController.php

7
css/metadata_profile.css

@ -18,3 +18,10 @@
.scrolling-table-container { .scrolling-table-container {
overflow-x: auto; overflow-x: auto;
} }
.yes-icon {
color: #2e7d32;
}
.no-icon {
color: #c62828;
}

19
metadata_profile.module

@ -1,5 +1,6 @@
<?php <?php
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Url;
/** /**
* Implements hook_entity_type_alter(). * Implements hook_entity_type_alter().
* *
@ -38,3 +39,19 @@ function metadata_profile_file_download($uri){
} }
return NULL; return NULL;
} }
/**
* Implements hook_entity_operation_alter().
*/
function metadata_profile_entity_operation_alter(array &$operations, EntityInterface $entity) {
if ($entity->getEntityTypeId() === 'node_type') {
$operations['metadata_profile'] = [
'title' => t('Metadata profile'),
'weight' => 50,
'url' => Url::fromRoute('entity.node_type.metadata_profile', [
'node_type' => $entity->id(),
]),
];
}
}

433
src/Controller/MetadataProfileController.php

@ -5,7 +5,6 @@ namespace Drupal\metadata_profile\Controller;
use Drupal\Core\Config\Config; use Drupal\Core\Config\Config;
use Drupal\Core\Config\ConfigFactoryInterface; use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Controller\ControllerBase; use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Entity\ContentEntityForm;
use Drupal\Core\Entity\EntityFieldManagerInterface; use Drupal\Core\Entity\EntityFieldManagerInterface;
use Drupal\Core\Field\BaseFieldDefinition; use Drupal\Core\Field\BaseFieldDefinition;
use Drupal\Core\Field\FieldDefinitionInterface; use Drupal\Core\Field\FieldDefinitionInterface;
@ -15,13 +14,14 @@ use Drupal\Core\Link;
use Drupal\Core\Messenger\MessengerTrait; use Drupal\Core\Messenger\MessengerTrait;
use Drupal\Core\Routing\RouteMatchInterface; use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Url; use Drupal\Core\Url;
use Drupal\node\NodeForm;
use Drupal\system\FileDownloadController; use Drupal\system\FileDownloadController;
use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
use Drupal\Core\Database\Connection;
use Drupal\Core\Entity\EntityTypeManagerInterface;
class MetadataProfileController extends ControllerBase { class MetadataProfileController extends ControllerBase {
use MessengerTrait; use MessengerTrait;
/** /**
@ -79,6 +79,7 @@ class MetadataProfileController extends ControllerBase {
* @var \Drupal\Core\File\FileSystemInterface * @var \Drupal\Core\File\FileSystemInterface
*/ */
protected $fileSystem; protected $fileSystem;
/** /**
* The file download controller. * The file download controller.
* *
@ -86,13 +87,30 @@ class MetadataProfileController extends ControllerBase {
*/ */
protected $fileDownloadController; protected $fileDownloadController;
/**
* The Database connection.
*
* @var \Drupal\Core\Database\Connection
*/
protected Connection $database;
/**
* The Entity type manager.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected EntityTypeManagerInterface $entityTypeManagerService;
public function __construct(EntityFieldManagerInterface $entity_field_manager, public function __construct(
EntityFieldManagerInterface $entity_field_manager,
FieldTypePluginManagerInterface $field_type_plugin_manager, FieldTypePluginManagerInterface $field_type_plugin_manager,
ConfigFactoryInterface $config_factory, ConfigFactoryInterface $config_factory,
RouteMatchInterface $route_match, RouteMatchInterface $route_match,
FileSystemInterface $file_system, FileSystemInterface $file_system,
FileDownloadController $file_download_controller) { FileDownloadController $file_download_controller,
Connection $database,
EntityTypeManagerInterface $entity_type_manager // ✅ ADD THIS
) {
$this->entityFieldManager = $entity_field_manager; $this->entityFieldManager = $entity_field_manager;
$this->fieldTypePluginManager = $field_type_plugin_manager; $this->fieldTypePluginManager = $field_type_plugin_manager;
$this->configFactory = $config_factory; $this->configFactory = $config_factory;
@ -105,6 +123,8 @@ class MetadataProfileController extends ControllerBase {
$this->entityTypeBundleOf = $entity_type->getEntityType()->getBundleOf(); $this->entityTypeBundleOf = $entity_type->getEntityType()->getBundleOf();
$this->fileSystem = $file_system; $this->fileSystem = $file_system;
$this->fileDownloadController = $file_download_controller; $this->fileDownloadController = $file_download_controller;
$this->database = $database;
$this->entityTypeManagerService = $entity_type_manager;
} }
public static function create(ContainerInterface $container) { public static function create(ContainerInterface $container) {
@ -114,7 +134,9 @@ class MetadataProfileController extends ControllerBase {
$container->get('config.factory'), $container->get('config.factory'),
$container->get('current_route_match'), $container->get('current_route_match'),
$container->get('file_system'), $container->get('file_system'),
FileDownloadController::create($container) FileDownloadController::create($container),
$container->get('database'),
$container->get('entity_type.manager'),
); );
} }
@ -124,7 +146,6 @@ class MetadataProfileController extends ControllerBase {
* @return array * @return array
*/ */
public function profile() { public function profile() {
// Get core content type information. // Get core content type information.
$bundle_config = $this->config(str_replace('_', '.', $this->entityType) . '.' . $this->entityBundle); $bundle_config = $this->config(str_replace('_', '.', $this->entityType) . '.' . $this->entityBundle);
if (!$bundle_config) { if (!$bundle_config) {
@ -194,40 +215,73 @@ class MetadataProfileController extends ControllerBase {
return $build; return $build;
} }
/**
* Builds a metadata profile for the current entity bundle.
*
* The returned array is keyed by field machine name and contains
* structured metadata describing each field.
*
* Each field profile contains:
* - label: string
* - machine_name: string
* - id: string
* - edit_url: \Drupal\Core\Url|null
* - details_link: \Drupal\Core\Link
* - description: string
* - type: string (human readable)
* - type_machine_name: string
* - required: render array
* - repeatable: render array|string
* - auto_create: render array|null
* - target_bundles: array
* - base_field: bool
* - usage_count: int
* - search_api: array
*
* @return array
* Metadata profile keyed by field machine name.
*/
public function getMetadataProfile() { public function getMetadataProfile() {
// $metadata_profile is an array of arrays. Its keys are the "short" machine names of the fields /**
// such as field_abstract. The values are arrays with the following keys: * Metadata profile structure.
// * 'label' - text. the bundle's human-readable label. *
// * 'machine_name' - text. The short machine name such as 'field_abstract'. * $metadata_profile is an associative array keyed by field machine names
// * 'id' - text. The long machine name such as 'node.islandora_object.field_abstract'. (same as this array's key) * (e.g. "field_abstract"). Each value is an array with the following keys:
// * 'edit_url' - Url object. The link to the edit page for that field (or to the base field override page). *
// * 'description' - the help text for the field. * - label: (string) Human-readable field label.
// * 'type' - text. The human readable type of the field. (e.g. "Entity Reference") * - machine_name: (string) Short machine name (e.g. "field_abstract").
// * 'type_machine_name' - text. The machine name of the type (e.g. 'entity_reference') * - id: (string) Full machine name
// * 'required' - 'Required'|'Not required'. Whether the field is required. * (e.g. "node.islandora_object.field_abstract").
// * 'cardinality' - 'Not repeatable'|'Repeatable'|'Repeatable, limit N' * - edit_url: (\Drupal\Core\Url) Link to edit the field configuration.
// * 'auto_create' - 'Create new'|'Create new #bundle'|'Do not create new'|NULL Whether a relationship field allows new entity creation on the fly. * - description: (string) Field help text.
// * 'target_bundles' - array. List of bundle names that are the target of this field. * - type: (string) Human-readable field type (e.g. "Entity Reference").
// * 'search_api' - associative array. Has the following keys: * - type_machine_name: (string) Field type machine name
// * 'in_search_api' - True|False. True if some field matches. * (e.g. "entity_reference").
// * 'has_facet' - True|False. True if some field has a facet. * - required: (string) "Required" or "Not required".
// * 'fields' - array. The 'fields' array is keyed by the machine names of the search api fields, * - cardinality: (string) "Not repeatable", "Repeatable",
// which are arrays with the following fields: * or "Repeatable, limit N".
// * 'search_api_field_name' - the machine name of the search api field. * - auto_create: (string|null) Whether referenced entities can be created:
// * 'search_api_field_label' - the human readable label of the search api field. * "Create new", "Create new (bundle)", or "Do not create new".
// * 'property_path' - the method for getting the values. * - target_bundles: (string[]) List of allowed target bundles.
// * 'type' = the search api field type. * - search_api: (array) Search API metadata:
// * 'index_name' - the name of the Search API index (in case there are more than one) * - in_search_api: (bool) TRUE if indexed.
// * 'fields_included' - for aggregate and EDTF processor fields, which fields are in that field. * - has_facet: (bool) TRUE if any facet exists.
// * 'facets' - associative array. has the following keys * - fields: (array) Indexed by Search API field machine name:
// * 'has_facet' - True|False. True if there is a facet, even if not showing up (can use with url alias) * - search_api_field_name: (string)
// * 'facets' - array. the 'facets' array is keyed by the machine name of the facet. each facet is an * - search_api_field_label: (string)
// array with keys: * - property_path: (string)
// * 'facet_name' * - type: (string)
// * 'facet_machine_name' * - index_name: (string)
// * 'facet_source' * - fields_included: (array) Included fields (aggregated/EDTF).
// * 'url_alias' * - facets: (array) Facet definitions:
// * 'block_visible' -- not yet implemented. * - has_facet: (bool)
* - facets: (array) Each facet contains:
* - facet_name: (string)
* - facet_machine_name: (string)
* - facet_source: (string)
* - url_alias: (string)
* - block_visible: (string) Not yet implemented.
*/
$metadata_profile = []; $metadata_profile = [];
$field_definitions = $this->entityFieldManager->getFieldDefinitions($this->entityTypeBundleOf, $this->entityBundle); $field_definitions = $this->entityFieldManager->getFieldDefinitions($this->entityTypeBundleOf, $this->entityBundle);
@ -246,6 +300,7 @@ class MetadataProfileController extends ControllerBase {
'auto_create' => $this->formatCreateNew($field_definition), 'auto_create' => $this->formatCreateNew($field_definition),
'target_bundles' => $this->formatTargetBundles($field_definition), 'target_bundles' => $this->formatTargetBundles($field_definition),
'base_field' => $field_definition->getFieldStorageDefinition() instanceof BaseFieldDefinition, 'base_field' => $field_definition->getFieldStorageDefinition() instanceof BaseFieldDefinition,
'usage_count' => $this->getUsageCount($field_name),
]; ];
$metadata_profile[$field_name]['search_api'] = $this->getSearchApi($field_definition); $metadata_profile[$field_name]['search_api'] = $this->getSearchApi($field_definition);
} }
@ -253,6 +308,19 @@ class MetadataProfileController extends ControllerBase {
return $metadata_profile; return $metadata_profile;
} }
/**
* Builds Search API metadata for a field definition.
*
* @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition
* The field definition.
*
* @return array|false
* An associative array containing:
* - in_search_api: bool
* - has_facet: bool
* - fields: array
* Or FALSE if Search API module is not enabled.
*/
private function getSearchApi($field_definition) { private function getSearchApi($field_definition) {
if (!$this->moduleHandler()->moduleExists('search_api')) { if (!$this->moduleHandler()->moduleExists('search_api')) {
return FALSE; return FALSE;
@ -282,7 +350,8 @@ class MetadataProfileController extends ControllerBase {
} }
} }
// Get EDTF fields. // Get EDTF fields.
else if ($field_definition->getType() == 'edtf') { else {
if ($field_definition->getType() == 'edtf') {
// Get EDTF year. // Get EDTF year.
if ($search_api_field_setting['property_path'] == 'edtf_year') { if ($search_api_field_setting['property_path'] == 'edtf_year') {
$edtf_year_fields = $index_config->get('processor_settings')['edtf_year_only']['fields'] ?: []; $edtf_year_fields = $index_config->get('processor_settings')['edtf_year_only']['fields'] ?: [];
@ -291,13 +360,16 @@ class MetadataProfileController extends ControllerBase {
} }
} }
// Get EDTF Date // Get EDTF Date
else if ($search_api_field_setting['property_path'] == 'edtf_dates') { else {
if ($search_api_field_setting['property_path'] == 'edtf_dates') {
$edtf_date_fields = $index_config->get('processor_settings')['edtf_date_processor']['fields'] ?: []; $edtf_date_fields = $index_config->get('processor_settings')['edtf_date_processor']['fields'] ?: [];
if (in_array(str_replace('.', '|', $field_definition->id()), $edtf_date_fields)) { if (in_array(str_replace('.', '|', $field_definition->id()), $edtf_date_fields)) {
$search_api['fields'][$indexed_field_name] = $this->getSearchApiField($search_api_field_name, $search_api_field_setting, $index_config); $search_api['fields'][$indexed_field_name] = $this->getSearchApiField($search_api_field_name, $search_api_field_setting, $index_config);
} }
} }
} }
}
}
// Check dependencies for a dependency on this field. // Check dependencies for a dependency on this field.
if (isset($search_api_field_setting['dependencies']) and isset($search_api_field_setting['dependencies']['config'])) { if (isset($search_api_field_setting['dependencies']) and isset($search_api_field_setting['dependencies']['config'])) {
$field_dependencies = $search_api_field_setting['dependencies']['config']; $field_dependencies = $search_api_field_setting['dependencies']['config'];
@ -310,22 +382,29 @@ class MetadataProfileController extends ControllerBase {
if (isset($search_api_field_setting['datasource_id']) and $search_api_field_setting['property_path'] == $field_definition->getName()) { if (isset($search_api_field_setting['datasource_id']) and $search_api_field_setting['property_path'] == $field_definition->getName()) {
$search_api['fields'][$indexed_field_name] = $this->getSearchApiField($search_api_field_name, $search_api_field_setting, $index_config); $search_api['fields'][$indexed_field_name] = $this->getSearchApiField($search_api_field_name, $search_api_field_setting, $index_config);
} }
} }
if (count($search_api['fields']) > 0) { if (count($search_api['fields']) > 0) {
$search_api['in_search_api'] = TRUE; $search_api['in_search_api'] = TRUE;
} }
if (in_array(TRUE, array_column($search_api['fields'], 'has_facet'), true)) { if (in_array(TRUE, array_column($search_api['fields'], 'has_facet'), TRUE)) {
$search_api['has_facet'] = TRUE; $search_api['has_facet'] = TRUE;
} }
else { else {
$search_api['has_facet'] = FALSE; $search_api['has_facet'] = FALSE;
} }
} }
return $search_api; return $search_api;
} }
/**
* Builds a render array for the summary table.
*
* @param array $metadata_profile
* Metadata profile array.
*
* @return array
* Render array for a Drupal table.
*/
protected function buildSummaryTable($metadata_profile) { protected function buildSummaryTable($metadata_profile) {
$rows = $this->getRows($metadata_profile, TRUE); $rows = $this->getRows($metadata_profile, TRUE);
return [ return [
@ -333,13 +412,43 @@ class MetadataProfileController extends ControllerBase {
'#header' => $this->getHeaders(), '#header' => $this->getHeaders(),
'#rows' => $rows, '#rows' => $rows,
]; ];
} }
/**
* Builds table rows from a metadata profile array.
*
* Each row is a numerically indexed array representing a table row:
* 0 => Field label or link
* 1 => Machine name
* 2 => Description
* 3 => Field type (human readable)
* 4 => Required indicator (render array)
* 5 => Repeatable indicator (render array)
* 6 => Auto-create indicator (render array|null)
* 7 => In Search API (render array)
* 8 => Has Facet (render array)
* 9 => Target bundles (array|string|render array)
* 10 => Weight (int|float)
* 11 => Usage count (int)
*
* Rows are sorted descending by usage count (index 11).
*
* @param array $metadata_profile
* Structured metadata profile keyed by field machine name.
* @param bool|null $display
* Whether to return renderable values (TRUE) or raw values (FALSE/NULL).
*
* @return array
* A numerically indexed array of row arrays.
*/
protected function getRows($metadata_profile, $display = NULL) { protected function getRows($metadata_profile, $display = NULL) {
$rows = []; $rows = [];
foreach ($metadata_profile as $field_name => $field_profile) { foreach ($metadata_profile as $field_name => $field_profile) {
if (str_starts_with( $field_name, 'field_') or in_array($field_name, ['title', 'name'])) { if (str_starts_with($field_name, 'field_') or in_array($field_name, [
'title',
'name',
])) {
$bundles = $field_profile['target_bundles'] ?? [];
$rows[] = [ $rows[] = [
$display ? $field_profile['details_link'] : $field_profile['label'], $display ? $field_profile['details_link'] : $field_profile['label'],
$field_profile['machine_name'], $field_profile['machine_name'],
@ -348,13 +457,20 @@ class MetadataProfileController extends ControllerBase {
$field_profile['required'], $field_profile['required'],
$field_profile['repeatable'], $field_profile['repeatable'],
$field_profile['auto_create'], $field_profile['auto_create'],
$display ? $this->formatListForTable($field_profile['target_bundles']) : $field_profile['target_bundles'],
$field_profile['search_api']['in_search_api'] ? 'Indexed' : '', $this->yesNoIcon($field_profile['search_api']['in_search_api']),
$field_profile['search_api']['has_facet'] ? 'Facet' : '', $this->YesNoIcon($field_profile['search_api']['has_facet']),
$display
? $this->formatListForTable($bundles)
: $bundles,
$field_profile['weight'], $field_profile['weight'],
$field_profile['usage_count'],
]; ];
} }
} }
usort($rows, function($a, $b) {
return $b[11] <=> $a[11];
});
return $rows; return $rows;
} }
@ -367,10 +483,11 @@ class MetadataProfileController extends ControllerBase {
$this->t('Required'), $this->t('Required'),
$this->t('Repeatable'), $this->t('Repeatable'),
$this->t('Create new'), $this->t('Create new'),
$this->t('Target bundles'),
$this->t('In Search API'), $this->t('In Search API'),
$this->t('Has Facet'), $this->t('Has Facet'),
$this->t('Target bundles'),
$this->t('Weight'), $this->t('Weight'),
$this->t("Usage count"),
// TODO: add more columns // TODO: add more columns
]; ];
@ -379,7 +496,10 @@ class MetadataProfileController extends ControllerBase {
protected function buildField(array $field_profile) { protected function buildField(array $field_profile) {
$render_array = []; $render_array = [];
$field_name = $field_profile['machine_name']; $field_name = $field_profile['machine_name'];
if (str_starts_with($field_name, 'field_') or in_array($field_name, ['title', 'name'])) { if (str_starts_with($field_name, 'field_') or in_array($field_name, [
'title',
'name',
])) {
$render_array = [ $render_array = [
'#type' => 'container', '#type' => 'container',
'#attributes' => ['class' => ['field-info']], '#attributes' => ['class' => ['field-info']],
@ -395,6 +515,16 @@ class MetadataProfileController extends ControllerBase {
'#prefix' => '(', '#prefix' => '(',
'#suffix' => ') ', '#suffix' => ') ',
], ],
'usage_count' => [
'#markup' => $this->formatPlural(
$field_profile['usage_count'],
"Used <strong>1</strong> time.",
"Used <strong>@count</strong> times."
),
'#prefix' => '</ br>',
],
'edit_link' => $field_profile['edit_url'] ? $this->formatFieldEditLink($field_profile['edit_url']) : [], 'edit_link' => $field_profile['edit_url'] ? $this->formatFieldEditLink($field_profile['edit_url']) : [],
'table' => [ 'table' => [
'#type' => 'table', '#type' => 'table',
@ -411,9 +541,6 @@ class MetadataProfileController extends ControllerBase {
'search_api' => $this->formatSearchApi($field_profile), 'search_api' => $this->formatSearchApi($field_profile),
'facets' => $this->formatFacets($field_profile), 'facets' => $this->formatFacets($field_profile),
]; ];
} }
return $render_array; return $render_array;
@ -427,7 +554,7 @@ class MetadataProfileController extends ControllerBase {
$edit_url = Url::fromRoute('entity.base_field_override.' . $this->entityTypeBundleOf . '_base_field_override_edit_form', [ $edit_url = Url::fromRoute('entity.base_field_override.' . $this->entityTypeBundleOf . '_base_field_override_edit_form', [
$this->entityType => $field_definition->getTargetBundle(), $this->entityType => $field_definition->getTargetBundle(),
'base_field_override' => $field_definition->id(), 'base_field_override' => $field_definition->id(),
'destination' => $redirect_url->toString() 'destination' => $redirect_url->toString(),
]); ]);
} }
else { else {
@ -448,8 +575,7 @@ class MetadataProfileController extends ControllerBase {
return $edit_url; return $edit_url;
} }
private function getFieldDetailsFragmentLink(string $field_name, FieldDefinitionInterface $field_definition) private function getFieldDetailsFragmentLink(string $field_name, FieldDefinitionInterface $field_definition) {
{
$url = Url::fromRoute('<current>', [], ['fragment' => $field_name]); $url = Url::fromRoute('<current>', [], ['fragment' => $field_name]);
return Link::fromTextAndUrl($field_definition->getLabel(), $url); return Link::fromTextAndUrl($field_definition->getLabel(), $url);
} }
@ -463,8 +589,6 @@ class MetadataProfileController extends ControllerBase {
]; ];
} }
protected function getFieldTableRows(array $field_profile) { protected function getFieldTableRows(array $field_profile) {
$rows = [ $rows = [
[$this->t('Type:'), $field_profile['type']], [$this->t('Type:'), $field_profile['type']],
@ -475,7 +599,10 @@ class MetadataProfileController extends ControllerBase {
$rows[] = [$this->t('Create new:'), $field_profile['auto_create']]; $rows[] = [$this->t('Create new:'), $field_profile['auto_create']];
} }
if ($field_profile['target_bundles']) { if ($field_profile['target_bundles']) {
$rows[] = [$this->t('Target bundles:'), $this->formatListForTable($field_profile['target_bundles'])]; $rows[] = [
$this->t('Target bundles:'),
$this->formatListForTable($field_profile['target_bundles']),
];
} }
return $rows; return $rows;
@ -489,24 +616,22 @@ class MetadataProfileController extends ControllerBase {
} }
return $type_label; return $type_label;
} }
protected function formatRequired(FieldDefinitionInterface $field_definition) { protected function formatRequired(FieldDefinitionInterface $field_definition) {
if ($field_definition->isRequired()) { $cardinality = $field_definition->isRequired();
return $this->t('Required'); return $this->yesNoIcon($cardinality);
}
else {
return $this->t('Not required');
}
} }
/** /**
* This does not work - most fields dont have a form weight specified in getDisplayOptions. * This does not work - most fields dont have a form weight specified in
* getDisplayOptions.
*/ */
protected function getWeight(string $field_name, array $form) { protected function getWeight(string $field_name, array $form) {
if (isset($form[$field_name])) { if (isset($form[$field_name])) {
$local_weight = $form[$field_name]['#weight']; $local_weight = $form[$field_name]['#weight'];
if ($parent = $form['#group_children'][$field_name]) { if ($parent = $form['#group_children'][$field_name]) {
$parent_weight = $this->getWeight($parent, $form); $parent_weight = $this->getWeight($parent, $form);
return $this->combine_weights($parent_weight, $local_weight); return $this->combineWeights($parent_weight, $local_weight);
} }
else { else {
return $local_weight; return $local_weight;
@ -518,32 +643,35 @@ class MetadataProfileController extends ControllerBase {
} }
protected function formatCardinality(FieldDefinitionInterface $field_definition) { protected function formatCardinality(FieldDefinitionInterface $field_definition) {
$cardinality = $field_definition->getFieldStorageDefinition()->getCardinality(); $cardinality = $field_definition
if ($cardinality == 1) { ->getFieldStorageDefinition()
return $this->t('Not repeatable'); ->getCardinality();
} elseif ($cardinality < 0) {
return $this->t('Repeatable');
} elseif ($cardinality > 1) {
return $this->t('Repeatable, limit :limit', [':limit' => $cardinality]);
}
return NULL;
}
protected function formatCreateNew(FieldDefinitionInterface $field_definition) { if ($cardinality === 1) {
if (in_array($field_definition->getType(), ['entity_reference', 'typed_relation'])) { return $this->yesNoIcon($cardinality);
$create_new_bundle = $field_definition->getSetting('handler_settings')['auto_create_bundle'] ? $create_new_bundle = $field_definition->getSetting('handler_settings')['auto_create_bundle'] : '';
$create_new = $field_definition->getSetting('handler_settings')['auto_create'] || '';
if ($create_new) {
return $create_new_bundle ? 'Create new (' . $create_new_bundle . ')' : 'Create new';
} }
else {
return $this->t('Do not create new'); if ($cardinality === -1) {
return $this->yesNoIcon($cardinality);
} }
return $this->t('Yes (max @limit)', [
'@limit' => $cardinality,
]);
} }
else {
protected function formatCreateNew(FieldDefinitionInterface $field_definition) {
if (!in_array($field_definition->getType(), [
'entity_reference',
'typed_relation',
], TRUE)) {
return NULL; return NULL;
} }
$settings = $field_definition->getSetting('handler_settings') ?? [];
$create_new = !empty($settings['auto_create']);
return $this->yesNoIcon($create_new);
} }
protected function formatTargetBundles(FieldDefinitionInterface $field_definition) { protected function formatTargetBundles(FieldDefinitionInterface $field_definition) {
@ -555,10 +683,14 @@ class MetadataProfileController extends ControllerBase {
$target_bundles = $setting['target_bundles']; $target_bundles = $setting['target_bundles'];
foreach ($target_bundles as $index => $bundle) { foreach ($target_bundles as $index => $bundle) {
if ($handler == 'default:taxonomy_term') { if ($handler == 'default:taxonomy_term') {
$bundle_config = $this->entityTypeManager()->getStorage('taxonomy_vocabulary')->load($bundle); $bundle_config = $this->entityTypeManager()
->getStorage('taxonomy_vocabulary')
->load($bundle);
} }
if ($handler == 'default:node') { if ($handler == 'default:node') {
$bundle_config = $this->entityTypeManager()->getStorage('node_type')->load($bundle); $bundle_config = $this->entityTypeManager()
->getStorage('node_type')
->load($bundle);
} }
// TODO: ADD MEDIA, PARAGRAPHS ETC // TODO: ADD MEDIA, PARAGRAPHS ETC
if ($bundle_config) { if ($bundle_config) {
@ -571,16 +703,18 @@ class MetadataProfileController extends ControllerBase {
'#theme' => 'item_list', '#theme' => 'item_list',
'#title' => $this->t('Target bundles:'), '#title' => $this->t('Target bundles:'),
'#items' => $target_bundles, '#items' => $target_bundles,
'#type' => 'ul' '#type' => 'ul',
]; ];
} }
protected function formatListForTable(array $list) { protected function formatListForTable(array $list) {
return ['data' => [ return [
'data' => [
'#theme' => 'item_list', '#theme' => 'item_list',
'#items' => array_values($list), '#items' => array_values($list),
'#type' => 'ul', '#type' => 'ul',
]]; ],
];
} }
protected function formatSearchApi($field_profile) { protected function formatSearchApi($field_profile) {
@ -613,7 +747,6 @@ class MetadataProfileController extends ControllerBase {
} }
} }
protected function getSearchApiField($field_setting_name, $field_setting, $index_config) { protected function getSearchApiField($field_setting_name, $field_setting, $index_config) {
$search_api_field_array = [ $search_api_field_array = [
'search_api_field_name' => $field_setting_name, 'search_api_field_name' => $field_setting_name,
@ -626,24 +759,30 @@ class MetadataProfileController extends ControllerBase {
if ($field_setting['property_path'] == 'aggregated_field') { if ($field_setting['property_path'] == 'aggregated_field') {
$search_api_field_array['fields_included'] = $field_setting['configuration']['fields']; $search_api_field_array['fields_included'] = $field_setting['configuration']['fields'];
} }
else if ($field_setting['property_path'] == 'edtf_year') { else {
if ($field_setting['property_path'] == 'edtf_year') {
$search_api_field_array['fields_included'] = $index_config->get('processor_settings')['edtf_year_only']['fields']; $search_api_field_array['fields_included'] = $index_config->get('processor_settings')['edtf_year_only']['fields'];
} }
else if ($field_setting['property_path'] == 'edtf') { else {
if ($field_setting['property_path'] == 'edtf') {
$search_api_field_array['fields_included'] = $index_config->get('processor_settings')['edtf_date_processor']['fields']; $search_api_field_array['fields_included'] = $index_config->get('processor_settings')['edtf_date_processor']['fields'];
} }
else { else {
$search_api_field_array['fields_included'] = []; $search_api_field_array['fields_included'] = [];
} }
}
}
// Get facet info. // Get facet info.
$search_api_field_array['has_facet'] = FALSE; $search_api_field_array['has_facet'] = FALSE;
if ($this->moduleHandler()->moduleExists('facets')) { if ($this->moduleHandler()->moduleExists('facets')) {
$all_facets = \Drupal::entityTypeManager()->getStorage('facets_facet')->loadMultiple(); $all_facets = \Drupal::entityTypeManager()
->getStorage('facets_facet')
->loadMultiple();
foreach ($all_facets as $facet_id => $facet) { foreach ($all_facets as $facet_id => $facet) {
// If facet uses this solr field... then add it to the array. // If facet uses this solr field... then add it to the array.
if ($facet->get('field_identifier') == $field_setting_name) { if ($facet->get('field_identifier') == $field_setting_name) {
$search_api_field_array['has_facet'] = True; $search_api_field_array['has_facet'] = TRUE;
$search_api_field_array['facets'][] = [ $search_api_field_array['facets'][] = [
'field_identifier' => $facet->get('field_identifier'), 'field_identifier' => $facet->get('field_identifier'),
'facet_name' => $facet->getName(), 'facet_name' => $facet->getName(),
@ -661,6 +800,7 @@ class MetadataProfileController extends ControllerBase {
protected function getBlockVisible($facet) { protected function getBlockVisible($facet) {
return ''; return '';
} }
protected function formatSearchApiField($search_api_field_profile) { protected function formatSearchApiField($search_api_field_profile) {
return [ return [
'data' => [ 'data' => [
@ -671,26 +811,48 @@ class MetadataProfileController extends ControllerBase {
$this->formatListForTable($search_api_field_profile['fields_included']), $this->formatListForTable($search_api_field_profile['fields_included']),
$search_api_field_profile['index_name'], $search_api_field_profile['index_name'],
$search_api_field_profile['has_facet'] ? 'True' : '', $search_api_field_profile['has_facet'] ? 'True' : '',
] ],
]; ];
} }
/**
* Sanitizes table rows for CSV export.
*
* Converts renderable elements and objects into scalar values:
* - Link objects are converted to their text.
* - Arrays are flattened into pipe-delimited strings.
*
* @param array $rows
* A numerically indexed array of row arrays.
*
* @return array
* Sanitized rows suitable for fputcsv().
*/
public function sanitizeRowsForCSV($rows) { public function sanitizeRowsForCSV($rows) {
foreach ($rows as $row_key => $row) { foreach ($rows as $row_key => $row) {
foreach ($row as $element_key => $element) { foreach ($row as $element_key => $element) {
if ($element instanceof Link) { if ($element instanceof Link) {
$rows[$row_key][$element_key] = $element->getText(); $rows[$row_key][$element_key] = $element->getText();
} }
else if (is_array($element)) { else {
if (is_array($element)) {
$rows[$row_key][$element_key] = implode('|', $element); $rows[$row_key][$element_key] = implode('|', $element);
} }
} }
} }
}
return $rows; return $rows;
} }
/**
* Generates and returns a CSV download of the metadata profile.
*
* Writes a temporary CSV file and serves it using Drupal's
* file download controller.
*
* @return \Symfony\Component\HttpFoundation\BinaryFileResponse
* The file download response.
*/
public function download() { public function download() {
$contentType = $this->entityBundle; $contentType = $this->entityBundle;
$entityKey = $this->entityTypeBundleOf; $entityKey = $this->entityTypeBundleOf;
@ -714,8 +876,7 @@ class MetadataProfileController extends ControllerBase {
return $this->fileDownloadController->download($request, 'temporary'); return $this->fileDownloadController->download($request, 'temporary');
} }
private function formatFacets(array $field_profile) private function formatFacets(array $field_profile) {
{
if (!$field_profile['search_api']['has_facet']) { if (!$field_profile['search_api']['has_facet']) {
return []; return [];
} }
@ -738,7 +899,6 @@ class MetadataProfileController extends ControllerBase {
$build['#rows'][] = $this->formatFacet($facet); $build['#rows'][] = $this->formatFacet($facet);
} }
} }
} }
if (count($build['#rows']) == 0) { if (count($build['#rows']) == 0) {
return []; return [];
@ -748,8 +908,7 @@ class MetadataProfileController extends ControllerBase {
} }
} }
private function formatFacet($facet) private function formatFacet($facet) {
{
return [ return [
'data' => [ 'data' => [
$facet['field_identifier'], $facet['field_identifier'],
@ -758,12 +917,11 @@ class MetadataProfileController extends ControllerBase {
$facet['facet_source'], $facet['facet_source'],
$facet['url_alias'], $facet['url_alias'],
$facet['block_visible'], $facet['block_visible'],
] ],
]; ];
} }
private function addWeights(array $metadata_profile) private function addWeights(array $metadata_profile) {
{
if ($this->entityTypeBundleOf == 'node') { if ($this->entityTypeBundleOf == 'node') {
$node = \Drupal\node\Entity\Node::create(['type' => $this->entityBundle]); $node = \Drupal\node\Entity\Node::create(['type' => $this->entityBundle]);
$form = \Drupal::service('entity.form_builder')->getForm($node); $form = \Drupal::service('entity.form_builder')->getForm($node);
@ -773,14 +931,12 @@ class MetadataProfileController extends ControllerBase {
$weights = array_column($metadata_profile, 'weight'); $weights = array_column($metadata_profile, 'weight');
array_multisort($weights, SORT_ASC, $metadata_profile); array_multisort($weights, SORT_ASC, $metadata_profile);
} }
return $metadata_profile; return $metadata_profile;
} }
private function combine_weights($parent_weight, $local_weight) private function combineWeights($parent_weight, $local_weight) {
{
$parent_int = (string) floor($parent_weight); $parent_int = (string) floor($parent_weight);
$parent_fraction = (string) ($parent_weight - $parent_int); $parent_fraction = (string) ($parent_weight - $parent_int);
$parent_fraction = str_replace('0.', '', $parent_fraction); $parent_fraction = str_replace('0.', '', $parent_fraction);
@ -803,4 +959,53 @@ class MetadataProfileController extends ControllerBase {
return (float) $combined_weight; return (float) $combined_weight;
} }
/**
* Gets usage count for a field.
*
* For configurable fields, counts rows in the field table.
* For base fields, counts nodes of the current bundle.
*
* @param string $field_name
* The field machine name.
*
* @return int
* Number of usages.
*/
private function getUsageCount($field_name) {
if (str_starts_with($field_name, 'field_')) {
$connection = $this->database;
$count = $connection->select("node__{$field_name}", 'f')
->countQuery()
->execute()
->fetchField();
return $count;
}
return $this->entityTypeManagerService
->getStorage('node')
->getQuery()
->accessCheck(FALSE)
->condition('type', $this->entityBundle)
->count()
->execute();
}
/**
* Returns a render array representing a yes/no icon.
*
* @param bool $value
* TRUE for yes, FALSE for no.
*
* @return array
* Render array containing markup for the icon.
*/
protected function yesNoIcon(bool $value): array {
return [
'data' => [
'#markup' => $value
? '<span class="yes-icon" title="Yes"></span>'
: '<span class="no-icon" title="No"></span>',
],
];
}
} }

Loading…
Cancel
Save