Browse Source

Add download CSV and add facets.

main
Rosie Le Faive 3 weeks ago
parent
commit
42ececd064
  1. 25
      metadata_profile.module
  2. 3
      metadata_profile.permissions.yml
  3. 503
      src/Controller/MetadataProfileController.php
  4. 25
      src/Routing/RouteSubscriber.php

25
metadata_profile.module

@ -10,6 +10,31 @@ function metadata_profile_entity_type_alter(array &$entity_types) {
foreach ($entity_types as $entity_type) { foreach ($entity_types as $entity_type) {
if ($entity_type->getBundleOf() && $entity_type->hasLinkTemplate('edit-form')) { if ($entity_type->getBundleOf() && $entity_type->hasLinkTemplate('edit-form')) {
$entity_type->setLinkTemplate('metadata-profile', $entity_type->getLinkTemplate('edit-form') . "/metadata-profile"); $entity_type->setLinkTemplate('metadata-profile', $entity_type->getLinkTemplate('edit-form') . "/metadata-profile");
$entity_type->setLinkTemplate('metadata-download', $entity_type->getLinkTemplate('edit-form') . "/metadata-profile/download");
} }
} }
} }
/**
* Implements hook_file_download().
*/
function metadata_profile_file_download($uri){
$stream_wrapper_manager = \Drupal::service('stream_wrapper_manager');
$scheme = $stream_wrapper_manager->getScheme($uri);
$target = $stream_wrapper_manager->getTarget($uri);
if ($scheme == 'temporary' && $target) {
$request = \Drupal::request();
$route = $request->attributes->get('_route');
// Check if we were called by Profile download route.
// No additional access checking needed here: route requires
// "export configuration" permission, token is validated by the controller.
// @see \Drupal\features\Controller\FeaturesController::downloadExport()
if (str_ends_with($route, 'metadata_profile.download')) {
return [
'Content-disposition' => 'attachment; filename="' . $target . '"',
];
}
}
return NULL;
}

3
metadata_profile.permissions.yml

@ -0,0 +1,3 @@
view metadata profiles:
description: "Access the metadata profiles tab from bundle edit pages."
title: "View metadata profiles"

503
src/Controller/MetadataProfileController.php

@ -2,29 +2,47 @@
namespace Drupal\metadata_profile\Controller; namespace Drupal\metadata_profile\Controller;
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\EntityFieldManagerInterface;
use Drupal\Core\Field\BaseFieldDefinition; use Drupal\Core\Field\BaseFieldDefinition;
use Drupal\Core\Field\FieldDefinitionInterface; use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\Core\Field\FieldTypePluginManagerInterface; use Drupal\Core\Field\FieldTypePluginManagerInterface;
use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\Link; use Drupal\Core\Link;
use Drupal\Core\Messenger\MessengerTrait; use Drupal\Core\Messenger\MessengerTrait;
use Drupal\Core\Config\Config;
use Drupal\Core\Routing\RouteMatchInterface; use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Url; use Drupal\Core\Url;
use Drupal\field_permissions\Plugin\FieldPermissionType\Base; use Drupal\system\FileDownloadController;
use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\Core\Entity\EntityFieldManagerInterface; use Symfony\Component\HttpFoundation\Request;
class MetadataProfileController extends ControllerBase { class MetadataProfileController extends ControllerBase {
use MessengerTrait; use MessengerTrait;
/**
* The entity field manager.
*
* @var EntityFieldManagerInterface
*/
protected EntityFieldManagerInterface $entityFieldManager; protected EntityFieldManagerInterface $entityFieldManager;
/**
* The Field Type Plugin Manager.
*
* @var FieldTypePluginManagerInterface
*/
protected FieldTypePluginManagerInterface $fieldTypePluginManager; protected FieldTypePluginManagerInterface $fieldTypePluginManager;
/**
* The config factory.
*
* @var ConfigFactoryInterface
*/
protected $configFactory; protected $configFactory;
/** /**
* The route matcher. * The route matcher.
* *
@ -33,31 +51,46 @@ class MetadataProfileController extends ControllerBase {
protected $routeMatch; protected $routeMatch;
/** /**
* The entity type machine name. * The entity type machine name, e.g. 'node_type'.
* *
* @var string * @var string
*/ */
protected $entityType; protected $entityType;
/** /**
* The bundle machine name. * The bundle machine name, e.g. 'article'.
* *
* @var string * @var string
*/ */
protected $entityBundle; protected $entityBundle;
/** /**
* The entity type that our config entity describes bundles of. * The entity type that our config entity describes bundles of, e.g. 'node'.
* *
* @var string * @var string
*/ */
protected $entityTypeBundleOf; protected $entityTypeBundleOf;
/**
* File system interface.
*
* @var \Drupal\Core\File\FileSystemInterface
*/
protected $fileSystem;
/**
* The file download controller.
*
* @var \Drupal\system\FileDownloadController
*/
protected $fileDownloadController;
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,
FileDownloadController $file_download_controller) {
$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;
@ -68,6 +101,8 @@ class MetadataProfileController extends ControllerBase {
$entity_type = $this->routeMatch->getParameter($this->entityType); $entity_type = $this->routeMatch->getParameter($this->entityType);
$this->entityBundle = $entity_type->id(); $this->entityBundle = $entity_type->id();
$this->entityTypeBundleOf = $entity_type->getEntityType()->getBundleOf(); $this->entityTypeBundleOf = $entity_type->getEntityType()->getBundleOf();
$this->fileSystem = $file_system;
$this->fileDownloadController = $file_download_controller;
} }
public static function create(ContainerInterface $container) { public static function create(ContainerInterface $container) {
@ -75,28 +110,27 @@ class MetadataProfileController extends ControllerBase {
$container->get('entity_field.manager'), $container->get('entity_field.manager'),
$container->get('plugin.manager.field.field_type'), $container->get('plugin.manager.field.field_type'),
$container->get('config.factory'), $container->get('config.factory'),
$container->get('current_route_match') $container->get('current_route_match'),
$container->get('file_system'),
FileDownloadController::create($container)
); );
} }
/** /**
* Returns a render array displaying the metadata profile for $content_type. * Returns a page (render array) displaying the metadata profile.
* *
* @param $content_type
* @return array * @return array
*/ */
public function profile($content_type = NULL) { public function profile() {
if (!$content_type) {
$content_type = $this->entityBundle;
}
// Get core content type information. // Get core content type information.
$bundle_config = $this->config(str_replace('_', '.', $this->entityType) . '.' . $content_type); $bundle_config = $this->config(str_replace('_', '.', $this->entityType) . '.' . $this->entityBundle);
if (!$bundle_config) { if (!$bundle_config) {
return ['#markup'=> 'Not a valid content type.']; return ['#markup'=> 'Not a valid content type.'];
} }
$build = $this->format_bundle($bundle_config); $build = $this->formatBundle($bundle_config);
$metadata_profile = $this->getMetadataProfile($content_type); $metadata_profile = $this->getMetadataProfile();
$build['summary_table'] = [ $build['summary_table'] = [
'#type' => 'container', '#type' => 'container',
@ -108,19 +142,19 @@ class MetadataProfileController extends ControllerBase {
'#type' => 'container', '#type' => 'container',
'#weight' => '9', '#weight' => '9',
]; ];
// Get field information. // Refactor this to not loop; each thing called by displayField should use metadata profile.
$field_definitions = $this->entityFieldManager->getFieldDefinitions($this->entityTypeBundleOf, $content_type); $field_definitions = $this->entityFieldManager->getFieldDefinitions($this->entityTypeBundleOf, $this->entityBundle);
foreach ($field_definitions as $field_name => $field_definition) { foreach ($field_definitions as $field_name => $field_definition) {
$build['fields'][$field_name] = $this->display_field($field_name, $field_definition, $metadata_profile[$field_name]); $build['fields'][$field_name] = $this->buildField($metadata_profile[$field_name]);
} }
return $build; return $build;
} }
/** /**
* Format information about a bundle. * Format basic information about a bundle.
*/ */
protected function format_bundle(Config $bundle) { protected function formatBundle(Config $bundle) {
if (str_starts_with($bundle->getName(), 'node.type')) { if (str_starts_with($bundle->getName(), 'node.type')) {
$label = $bundle->get('name'); $label = $bundle->get('name');
$machine_name = $bundle->get('type'); $machine_name = $bundle->get('type');
@ -160,13 +194,14 @@ class MetadataProfileController extends ControllerBase {
return $build; return $build;
} }
public function getMetadataProfile($bundle) { public function getMetadataProfile() {
// $metadata_profile is an array of arrays. Its keys are the "short" machine names of the fields // $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: // such as field_abstract. The values are arrays with the following keys:
// * 'label' - text. the bundle's human-readable label. // * 'label' - text. the bundle's human-readable label.
// * 'machine_name' - text. The short machine name such as 'field_abstract'. // * 'machine_name' - text. The short machine name such as 'field_abstract'.
// * 'id' - text. The long machine name such as 'node.islandora_object.field_abstract'. (same as this array's key) // * 'id' - text. The long machine name such as 'node.islandora_object.field_abstract'. (same as this array's key)
// * 'edit_url' - Url object. The link to the edit page for that field (or to the base field override page). // * '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.
// * 'type' - text. The human readable type of the field. (e.g. "Entity Reference") // * 'type' - text. The human readable type of the field. (e.g. "Entity Reference")
// * 'type_machine_name' - text. The machine name of the type (e.g. 'entity_reference') // * 'type_machine_name' - text. The machine name of the type (e.g. 'entity_reference')
// * 'required' - 'Required'|'Not required'. Whether the field is required. // * 'required' - 'Required'|'Not required'. Whether the field is required.
@ -175,84 +210,176 @@ class MetadataProfileController extends ControllerBase {
// * 'target_bundles' - array. List of bundle names that are the target of this field. // * 'target_bundles' - array. List of bundle names that are the target of this field.
// * 'search_api' - associative array. Has the following keys: // * 'search_api' - associative array. Has the following keys:
// * 'in_search_api' - True|False. True if some field matches. // * 'in_search_api' - True|False. True if some field matches.
// * 'has_facet' - True|False. True if some field has a facet.
// * 'fields' - array. The 'fields' array is keyed by the machine names of the search api fields, // * 'fields' - array. The 'fields' array is keyed by the machine names of the search api fields,
// which are arrays with the following fields: // which are arrays with the following fields:
// * 'search_api_field_name' - the machine name of the search api field. // * 'search_api_field_name' - the machine name of the search api field.
// * 'search_api_field_label' - the human readable label of the search api field. // * 'search_api_field_label' - the human readable label of the search api field.
// * 'property_path' - the method for getting the values. // * 'property_path' - the method for getting the values.
// * 'type' = the search api field type.
// * 'index_name' - the name of the Search API index (in case there are more than one) // * 'index_name' - the name of the Search API index (in case there are more than one)
// * 'fields_included' - for aggregate and EDTF processor fields, which fields are in that field. // * 'fields_included' - for aggregate and EDTF processor fields, which fields are in that field.
// * 'facets' - associative array. has the following keys // * 'facets' - associative array. has the following keys
// * 'has_facet' - True|False. True if there is a facet, even if not showing up (can use with url alias) // * 'has_facet' - True|False. True if there is a facet, even if not showing up (can use with url alias)
// * 'facets' - array. the 'facets' array is keyed by the machine name of the facet. each facet is an // * 'facets' - array. the 'facets' array is keyed by the machine name of the facet. each facet is an
// array with keys: // array with keys:
// * 'facet_name' // * 'facet_name'
// * 'facet_machine_name' // * 'facet_machine_name'
// * 'facet_source' // * 'facet_source'
// * 'url_alias' // * 'url_alias'
// * 'block_visible' // * 'block_visible'
$metadata_profile = []; $metadata_profile = [];
$field_definitions = $this->entityFieldManager->getFieldDefinitions($this->entityTypeBundleOf, $bundle); $field_definitions = $this->entityFieldManager->getFieldDefinitions($this->entityTypeBundleOf, $this->entityBundle);
foreach ($field_definitions as $field_name => $field_definition) { foreach ($field_definitions as $field_name => $field_definition) {
$metadata_profile[$field_name] = [ $metadata_profile[$field_name] = [
'label' => $field_definition->getLabel(), 'label' => $field_definition->getLabel(),
'machine_name' => $field_name, 'machine_name' => $field_name,
'id' => method_exists($field_definition, 'id') ? $field_definition->id() : $field_definition->getUniqueIdentifier(), 'id' => method_exists($field_definition, 'id') ? $field_definition->id() : $field_definition->getUniqueIdentifier(),
'edit_url' => $this->getFieldEditUrl($field_definition), 'edit_url' => $this->getFieldEditUrl($field_definition),
'details_link' => $this->getDetailsFragmentLink($field_name, $field_definition), 'details_link' => $this->getFieldDetailsFragmentLink($field_name, $field_definition),
'description' => $field_definition->getDescription(),
'type' => $this->formatType($field_definition), 'type' => $this->formatType($field_definition),
'type_machine_name' => $field_definition->getType(), 'type_machine_name' => $field_definition->getType(),
'required' => $this->formatRequired($field_definition), 'required' => $this->formatRequired($field_definition),
'repeatable' => $this->formatCardinality($field_definition), 'repeatable' => $this->formatCardinality($field_definition),
'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,
]; ];
// Add solr $metadata_profile[$field_name]['search_api'] = $this->getSearchApi($field_definition);
} }
return $metadata_profile; return $metadata_profile;
} }
private function getSearchApi($field_definition) {
if (!$this->moduleHandler()->moduleExists('search_api')) {
return FALSE;
}
$search_api = [
'in_search_api' => FALSE,
'fields' => [],
];
$storage = $field_definition->getFieldStorageDefinition();
if ($storage instanceof BaseFieldDefinition) {
$field_id = $this->entityTypeBundleOf . '.' . $storage->getName();
}
else {
$field_id = 'field.storage.' . $storage->get('id');
}
$search_api_indexes = $this->configFactory->listAll('search_api.index');
foreach ($search_api_indexes as $index) {
$index_config = $this->config($index);
// Loop over fields.
foreach ($index_config->get('field_settings') as $search_api_field_name => $search_api_field_setting) {
$indexed_field_name = $index_config->getName() . '.' .$search_api_field_name;
// Get Aggregated Fields.
if ($search_api_field_setting['property_path'] == 'aggregated_field') {
if (in_array('entity:node/' . $field_definition->getName(), $search_api_field_setting['configuration']['fields'])) {
$search_api['fields'][$indexed_field_name] = $this->getSearchApiField($search_api_field_name, $search_api_field_setting, $index_config);
}
}
// Get EDTF fields.
else if ($field_definition->getType() == 'edtf') {
// Get EDTF year.
if ($search_api_field_setting['property_path'] == 'edtf_year') {
$edtf_year_fields = $index_config->get('processor_settings')['edtf_year_only']['fields'] ?: [];
if (in_array(str_replace('.', '|', $field_definition->id()), $edtf_year_fields)) {
$search_api['fields'][$indexed_field_name] = $this->getSearchApiField($search_api_field_name, $search_api_field_setting, $index_config);
}
}
// Get EDTF Date
else if ($search_api_field_setting['property_path'] == 'edtf_dates') {
$edtf_date_fields = $index_config->get('processor_settings')['edtf_date_processor']['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);
}
}
}
// Check dependencies for a dependency on this field.
if (isset($search_api_field_setting['dependencies']) and isset($search_api_field_setting['dependencies']['config'])) {
$field_dependencies = $search_api_field_setting['dependencies']['config'];
if (in_array($field_id, $field_dependencies)) {
$search_api['fields'][$indexed_field_name] = $this->getSearchApiField($search_api_field_name, $search_api_field_setting, $index_config);
}
}
// Check if the property path equals this field.
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);
}
}
if (count($search_api['fields']) > 0) {
$search_api['in_search_api'] = TRUE;
}
if (in_array(TRUE, array_column($search_api['fields'], 'has_facet'), true)) {
$search_api['has_facet'] = TRUE;
}
else {
$search_api['has_facet'] = FALSE;
}
}
return $search_api;
}
protected function buildSummaryTable($metadata_profile) { protected function buildSummaryTable($metadata_profile) {
$rows = $this->getRows($metadata_profile, TRUE);
return [
'#type' => 'table',
'#header' => $this->getHeaders(),
'#rows' => $rows,
];
}
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'])) {
$rows[] = [ $rows[] = [
$field_profile['details_link'], $display ? $field_profile['details_link'] : $field_profile['label'],
$field_profile['machine_name'], $field_profile['machine_name'],
$field_profile['description'],
$field_profile['type'], $field_profile['type'],
$field_profile['required'], $field_profile['required'],
$field_profile['repeatable'], $field_profile['repeatable'],
$field_profile['auto_create'], $field_profile['auto_create'],
$this->formatListForTable($field_profile['target_bundles']), $display ? $this->formatListForTable($field_profile['target_bundles']) : $field_profile['target_bundles'],
]; $field_profile['search_api']['in_search_api'] ? 'Indexed' : '',
$field_profile['search_api']['has_facet'] ? 'Facet' : '',
];
} }
} }
return $rows;
}
protected function getHeaders() {
return [ return [
'#type' => 'table', $this->t('Field'),
'#header' => [ $this->t('Machine name'),
$this->t('Field'), $this->t('Description'),
$this->t('Machine name'), $this->t('Type'),
$this->t('Type'), $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('Target bundles') $this->t('In Search API'),
// TODO: add more columns $this->t('Has Facet'),
], // TODO: add more columns
'#rows' => $rows,
]; ];
} }
protected function display_field(string $field_name, FieldDefinitionInterface $field_definition, array $field_profile) { protected function buildField(array $field_profile) {
$render_array = []; $render_array = [];
$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']],
'#weight' => $this->formatWeight($field_definition), // This doesn't work. // TODO: add weight here from form display defaults.
'title' => [ 'title' => [
'#plain_text' => $field_profile['label'], '#plain_text' => $field_profile['label'],
'#prefix' => '<h2 id="' . $field_name . '">', '#prefix' => '<h2 id="' . $field_name . '">',
@ -272,10 +399,11 @@ class MetadataProfileController extends ControllerBase {
], ],
'description' => [ 'description' => [
'#type' => 'markup', '#type' => 'markup',
'#markup' => $field_definition->getDescription() ?: $this->t('[No description]'), '#markup' => $field_profile['description'] ?: $this->t('[No description]'),
'#prefix' => '<b>Description:</b> ', '#prefix' => '<b>Description:</b> ',
], ],
'search_api' => $this->formatSearchApi($field_definition), 'search_api' => $this->formatSearchApi($field_profile),
'facets' => $this->formatFacets($field_profile),
]; ];
} }
@ -297,7 +425,6 @@ class MetadataProfileController extends ControllerBase {
else { else {
return NULL; return NULL;
} }
} }
else { else {
return NULL; return NULL;
@ -312,6 +439,13 @@ class MetadataProfileController extends ControllerBase {
} }
return $edit_url; return $edit_url;
} }
private function getFieldDetailsFragmentLink(string $field_name, FieldDefinitionInterface $field_definition)
{
$url = Url::fromRoute('<current>', [], ['fragment' => $field_name]);
return Link::fromTextAndUrl($field_definition->getLabel(), $url);
}
protected function formatFieldEditLink(Url $edit_url) { protected function formatFieldEditLink(Url $edit_url) {
return [ return [
'#type' => 'link', '#type' => 'link',
@ -321,6 +455,8 @@ 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']],
@ -375,8 +511,8 @@ class MetadataProfileController extends ControllerBase {
protected function formatCreateNew(FieldDefinitionInterface $field_definition) { protected function formatCreateNew(FieldDefinitionInterface $field_definition) {
if (in_array($field_definition->getType(), ['entity_reference', 'typed_relation'])) { if (in_array($field_definition->getType(), ['entity_reference', 'typed_relation'])) {
$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_bundle']; $create_new = $field_definition->getSetting('handler_settings')['auto_create'] || '';
if ($create_new) { if ($create_new) {
return $create_new_bundle ? 'Create new (' . $create_new_bundle . ')' : 'Create new'; return $create_new_bundle ? 'Create new (' . $create_new_bundle . ')' : 'Create new';
} }
@ -426,119 +562,182 @@ class MetadataProfileController extends ControllerBase {
'#type' => 'ul', '#type' => 'ul',
]]; ]];
} }
protected function formatSearchApi($field_definition) {
if ($this->moduleHandler()->moduleExists('search_api')) {
$build = [
'#type' => 'table',
'#header' => [
'col1' => $this->t('Search API field name'),
'col2' => $this->t('Search API machine name'),
'col3' => $this->t('Search API property path'),
'col4' => $this->t('Search API field type'),
'col0' => $this->t('Search API index'),
],
'#rows' => [],
];
$storage = $field_definition->getFieldStorageDefinition();
if ($storage instanceof BaseFieldDefinition) {
// Use property_path to find related fields.
$field_id = $this->entityTypeBundleOf . '.' . $storage->getName();
}
else {
$field_id = 'field.storage.' . $storage->get('id');
}
$search_api_indexes = $this->configFactory->listAll('search_api.index'); protected function formatSearchApi($field_profile) {
foreach ($search_api_indexes as $index) { if (!$field_profile['search_api']['in_search_api']) {
$index_config = $this->config($index); return [];
// Loop over fields. }
foreach ($index_config->get('field_settings') as $field_setting_name => $field_setting) { $build = [
// Check dependencies. '#type' => 'table',
$field_dependencies = $field_setting['dependencies']['config'] ?: []; '#header' => [
if (in_array($field_id, $field_dependencies)) { 'col1' => $this->t('Search API field name'),
$build['#rows'][$field_setting_name] = $this->format_search_api_field($field_setting_name, $field_setting, $index_config); 'col2' => $this->t('Search API machine name'),
} 'col3' => $this->t('Search API property path'),
// Check by property path. 'col4' => $this->t('Search API field type'),
if ($field_setting['datasource_id'] == 'entity:node' and $field_setting['property_path'] == $field_definition->getName()) { 'col5' => $this->t('Aggregate field includes'),
$build['#rows'][$field_setting_name] = $this->format_search_api_field($field_setting_name, $field_setting, $index_config); 'col0' => $this->t('Search API index'),
} 'col6' => $this->t('Has facet'),
// Get Aggregated Fields. ],
if ($field_setting['property_path'] == 'aggregated_field') { '#rows' => [],
if (in_array('entity:node/' . $field_definition->getName(), $field_setting['configuration']['fields'])) { ];
$build['#rows'][$field_setting_name] = $this->format_search_api_field($field_setting_name, $field_setting, $index_config); foreach ($field_profile['search_api']['fields'] as $search_api_field) {
} $build['#rows'][] = $this->formatSearchApiField($search_api_field);
} }
if ($field_definition->getType() == 'edtf') {
// Get EDTF year.
if ($field_setting['property_path'] == 'edtf_year') {
$edtf_year_fields = $index_config->get('processor_settings')['edtf_year_only']['fields'] ?: [];
if (in_array(str_replace('.', '|', $field_definition->id()), $edtf_year_fields)) {
$build['#rows'][$field_setting_name] = $this->format_search_api_field($field_setting_name, $field_setting, $index_config);
}
}
// Get EDTF Date
if ($field_setting['property_path'] == 'edtf_dates') {
$edtf_date_fields = $index_config->get('processor_settings')['edtf_date_processor']['fields'] ?: [];
if (in_array(str_replace('.', '|', $field_definition->id()), $edtf_date_fields)) {
$build['#rows'][$field_setting_name] = $this->format_search_api_field($field_setting_name, $field_setting, $index_config);
}
}
}
} if (count($build['#rows']) == 0) {
if (count($build['#rows']) == 0) { return [];
return []; }
} else {
}
return $build; return $build;
} }
}
protected function getSearchApiField($field_setting_name, $field_setting, $index_config) {
$search_api_field_array = [
'search_api_field_name' => $field_setting_name,
'search_api_field_label' => $field_setting['label'],
'property_path' => $field_setting['property_path'],
'type' => $field_setting['type'],
'index_name' => $index_config->get('name'),
];
// Get fields included for aggregated fields.
if ($field_setting['property_path'] == 'aggregated_field') {
$search_api_field_array['fields_included'] = $field_setting['configuration']['fields'];
}
else if ($field_setting['property_path'] == 'edtf_year') {
$search_api_field_array['fields_included'] = $index_config->get('processor_settings')['edtf_year_only']['fields'];
}
else if ($field_setting['property_path'] == 'edtf') {
$search_api_field_array['fields_included'] = $index_config->get('processor_settings')['edtf_date_processor']['fields'];
}
else { else {
return []; $search_api_field_array['fields_included'] = [];
}
// Get facet info.
$search_api_field_array['has_facet'] = FALSE;
if ($this->moduleHandler()->moduleExists('facets')) {
$all_facets = \Drupal::entityTypeManager()->getStorage('facets_facet')->loadMultiple();
foreach ($all_facets as $facet_id => $facet) {
// If facet uses this solr field... then add it to the array.
if ($facet->get('field_identifier') == $field_setting_name) {
$search_api_field_array['has_facet'] = True;
$search_api_field_array['facets'][] = [
'field_identifier' => $facet->get('field_identifier'),
'facet_name' => $facet->getName(),
'facet_machine_name' => $facet_id,
'facet_source' => $facet->getFacetSourceId(),
'url_alias' => $facet->getUrlAlias(),
'block_visible' => $this->getBlockVisible($facet),
];
}
}
} }
return $search_api_field_array;
} }
protected function format_search_api_field($field_setting_name, $field_setting, $index_config) { protected function getBlockVisible($facet) {
$build = [ return '';
}
protected function formatSearchApiField($search_api_field_profile) {
return [
'data' => [ 'data' => [
$field_setting['label'], $search_api_field_profile['search_api_field_label'],
$field_setting_name, $search_api_field_profile['search_api_field_name'],
$field_setting['property_path'], $search_api_field_profile['property_path'],
$field_setting['type'], $search_api_field_profile['type'],
$index_config->get('name'), $this->formatListForTable($search_api_field_profile['fields_included']),
$search_api_field_profile['index_name'],
$search_api_field_profile['has_facet'] ? 'True' : '',
] ]
]; ];
if ($field_setting['property_path'] == 'aggregated_field') { }
$list_render_array = [
'#theme' => 'item_list',
'#items' => $field_setting['configuration']['fields']
];
$cell_element = [ 'data' => [
'#type' => 'container',
'label' => ['#markup' => $build['data'][2]],
'list' => $list_render_array,
]];
$build['data'][2] = $cell_element;
public function sanitizeRowsForCSV($rows) {
foreach ($rows as $row_key => $row) {
foreach ($row as $element_key => $element) {
if ($element instanceof Link) {
$rows[$row_key][$element_key] = $element->getText();
}
else if (is_array($element)) {
$rows[$row_key][$element_key] = implode('|', $element);
}
}
} }
if (in_array($field_setting['property_path'], ['edtf_year', 'edtf_dates'])) { return $rows;
$list_render_array = [ }
'#theme' => 'item_list', public function download() {
'#items' => $index_config->get('processor_settings')['edtf_year_only']['fields'] ?: $this->t('No fields avaailable') $contentType = $this->entityBundle;
]; $entityKey = $this->entityTypeBundleOf;
$cell_element = [ 'data' => [ $headers = $this->getHeaders();
'#type' => 'container', $metadata_profile = $this->getMetadataProfile();
'label' => ['#markup' => $build['data'][2]], $rows = $this->getRows($metadata_profile);
'list' => $list_render_array, $rows = $this->sanitizeRowsForCSV($rows);
]]; $filename_slug = "{$entityKey}__{$contentType}.csv";
$filename = $this->fileSystem->getTempDirectory() . '/' . $filename_slug;
// Write file to temporary filesystem.
if (file_exists($filename)) {
$this->fileSystem->delete($filename);
}
$fh = fopen($filename, 'w');
fputcsv($fh, $headers);
foreach ($rows as $row) {
fputcsv($fh, $row);
}
fclose($fh);
$request = new Request(['file' => $filename_slug]);
return $this->fileDownloadController->download($request, 'temporary');
}
$build['data'][2] = $cell_element; private function formatFacets(array $field_profile)
{
if (!$field_profile['search_api']['has_facet']) {
return [];
}
$build = [
'#type' => 'table',
'#header' => [
$this->t('Search API field'),
$this->t('Facet name'),
$this->t('Facet machine name'),
$this->t('Facet source'),
$this->t('URL fragment alias'),
$this->t('Block is placed'),
],
'#rows' => [],
];
foreach ($field_profile['search_api']['fields'] as $field) {
if ($field['has_facet']) {
foreach ($field['facets'] as $facet) {
$build['#rows'][] = $this->formatFacet($facet);
}
}
}
if (count($build['#rows']) == 0) {
return [];
}
else {
return $build;
} }
return $build;
} }
private function getDetailsFragmentLink(string $field_name, FieldDefinitionInterface $field_definition) private function formatFacet($facet)
{ {
$url = Url::fromRoute('<current>', [], ['fragment' => $field_name]); return [
return Link::fromTextAndUrl($field_definition->getLabel(), $url); 'data' => [
$facet['field_identifier'],
$facet['facet_name'],
$facet['facet_machine_name'],
$facet['facet_source'],
$facet['url_alias'],
$facet['block_visible'],
]
];
} }
} }

25
src/Routing/RouteSubscriber.php

@ -39,6 +39,9 @@ class RouteSubscriber extends RouteSubscriberBase {
if ($route = $this->getEntityProfileRoute($entity_type)) { if ($route = $this->getEntityProfileRoute($entity_type)) {
$collection->add("entity.$entity_type_id.metadata_profile", $route); $collection->add("entity.$entity_type_id.metadata_profile", $route);
} }
if ($route = $this->getEntityDownloadRoute($entity_type)) {
$collection->add("entity.$entity_type_id.metadata_profile.download", $route);
}
} }
} }
@ -60,6 +63,28 @@ class RouteSubscriber extends RouteSubscriberBase {
'_controller' => '\Drupal\metadata_profile\Controller\MetadataProfileController::profile', '_controller' => '\Drupal\metadata_profile\Controller\MetadataProfileController::profile',
'_title' => 'Metadata Profile', '_title' => 'Metadata Profile',
]) ])
->addRequirements([
'_permission' => 'view metadata profiles',
])
->setOption('_admin_route', TRUE)
->setOption('parameters', [
$entity_type_id => ['type' => 'entity:' . $entity_type_id],
]);
return $route;
}
return NULL;
}
protected function getEntityDownloadRoute(EntityTypeInterface $entity_type) {
if ($route_load = $entity_type->getLinkTemplate('metadata-download')) {
$entity_type_id = $entity_type->id();
$route = new Route($route_load);
$route
->addDefaults([
'_controller' => '\Drupal\metadata_profile\Controller\MetadataProfileController::download',
'_title' => 'Metadata Profile Download',
])
->addRequirements([ ->addRequirements([
'_permission' => 'administer content', '_permission' => 'administer content',
]) ])

Loading…
Cancel
Save