|
|
|
|
@ -23,7 +23,14 @@ use Drupal\node\NodeTypeInterface;
|
|
|
|
|
use Symfony\Component\HttpFoundation\BinaryFileResponse; |
|
|
|
|
use Symfony\Component\HttpFoundation\ResponseHeaderBag; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Controller for displaying and exporting bundle metadata profiles. |
|
|
|
|
* |
|
|
|
|
* The controller inspects the current bundle's field definitions, builds a |
|
|
|
|
* summary of field configuration, Search API usage, facet usage, form-display |
|
|
|
|
* weight, and field usage counts, then renders the results as a Drupal page or |
|
|
|
|
* downloadable CSV. |
|
|
|
|
*/ |
|
|
|
|
class MetadataProfileController extends ControllerBase { |
|
|
|
|
|
|
|
|
|
use MessengerTrait; |
|
|
|
|
@ -112,6 +119,26 @@ class MetadataProfileController extends ControllerBase {
|
|
|
|
|
*/ |
|
|
|
|
protected array $usageCounts = []; |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Constructs a MetadataProfileController object. |
|
|
|
|
* |
|
|
|
|
* @param \Drupal\Core\Entity\EntityFieldManagerInterface $entity_field_manager |
|
|
|
|
* The entity field manager service. |
|
|
|
|
* @param \Drupal\Core\Field\FieldTypePluginManagerInterface $field_type_plugin_manager |
|
|
|
|
* The field type plugin manager service. |
|
|
|
|
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory |
|
|
|
|
* The config factory service. |
|
|
|
|
* @param \Drupal\Core\Routing\RouteMatchInterface $route_match |
|
|
|
|
* The current route match service. |
|
|
|
|
* @param \Drupal\Core\File\FileSystemInterface $file_system |
|
|
|
|
* The file system service. |
|
|
|
|
* @param \Drupal\system\FileDownloadController $file_download_controller |
|
|
|
|
* The file download controller. |
|
|
|
|
* @param \Drupal\Core\Database\Connection $database |
|
|
|
|
* The active database connection. |
|
|
|
|
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager |
|
|
|
|
* The entity type manager service. |
|
|
|
|
*/ |
|
|
|
|
public function __construct( |
|
|
|
|
EntityFieldManagerInterface $entity_field_manager, |
|
|
|
|
FieldTypePluginManagerInterface $field_type_plugin_manager, |
|
|
|
|
@ -138,6 +165,9 @@ class MetadataProfileController extends ControllerBase {
|
|
|
|
|
$this->entityTypeManagerService = $entity_type_manager; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* {@inheritdoc} |
|
|
|
|
*/ |
|
|
|
|
public static function create(ContainerInterface $container) { |
|
|
|
|
return new static( |
|
|
|
|
$container->get('entity_field.manager'), |
|
|
|
|
@ -152,9 +182,11 @@ class MetadataProfileController extends ControllerBase {
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Returns a page (render array) displaying the metadata profile. |
|
|
|
|
* Displays the metadata profile page for the current bundle. |
|
|
|
|
* |
|
|
|
|
* @return array |
|
|
|
|
* A render array containing bundle details, a download link, a sortable |
|
|
|
|
* summary table, and detailed per-field sections. |
|
|
|
|
*/ |
|
|
|
|
public function profile() { |
|
|
|
|
// Get core content type information. |
|
|
|
|
@ -194,7 +226,13 @@ class MetadataProfileController extends ControllerBase {
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Format basic information about a bundle. |
|
|
|
|
* Builds the render array for basic bundle information. |
|
|
|
|
* |
|
|
|
|
* @param \Drupal\Core\Config\Config $bundle |
|
|
|
|
* The bundle configuration object. |
|
|
|
|
* |
|
|
|
|
* @return array |
|
|
|
|
* A render array containing the bundle label, machine name, and description. |
|
|
|
|
*/ |
|
|
|
|
protected function formatBundle(Config $bundle) { |
|
|
|
|
if (str_starts_with($bundle->getName(), 'node.type')) { |
|
|
|
|
@ -427,12 +465,17 @@ class MetadataProfileController extends ControllerBase {
|
|
|
|
|
* @return array |
|
|
|
|
* Render array for a Drupal table. |
|
|
|
|
*/ |
|
|
|
|
protected function buildSummaryTable($metadata_profile) { |
|
|
|
|
protected function buildSummaryTable($metadata_profile): array { |
|
|
|
|
$header = $this->getHeaders(); |
|
|
|
|
$rows = $this->getRows($metadata_profile, TRUE); |
|
|
|
|
|
|
|
|
|
$this->sortRows($rows, $header); |
|
|
|
|
|
|
|
|
|
return [ |
|
|
|
|
'#type' => 'table', |
|
|
|
|
'#header' => $this->getHeaders(), |
|
|
|
|
'#header' => $header, |
|
|
|
|
'#rows' => $rows, |
|
|
|
|
'#empty' => $this->t('No fields found.'), |
|
|
|
|
]; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ -463,14 +506,19 @@ class MetadataProfileController extends ControllerBase {
|
|
|
|
|
* @return array |
|
|
|
|
* A numerically indexed array of row arrays. |
|
|
|
|
*/ |
|
|
|
|
protected function getRows($metadata_profile, $display = NULL) { |
|
|
|
|
protected function getRows($metadata_profile, $display = NULL): array { |
|
|
|
|
$rows = []; |
|
|
|
|
foreach ($metadata_profile as $field_name => $field_profile) { |
|
|
|
|
if (str_starts_with($field_name, 'field_') or in_array($field_name, [ |
|
|
|
|
if (str_starts_with($field_name, 'field_') || in_array($field_name, [ |
|
|
|
|
'title', |
|
|
|
|
'name', |
|
|
|
|
])) { |
|
|
|
|
], TRUE)) { |
|
|
|
|
$bundles = $field_profile['target_bundles'] ?? []; |
|
|
|
|
$search_api = $field_profile['search_api'] ?: [ |
|
|
|
|
'in_search_api' => FALSE, |
|
|
|
|
'has_facet' => FALSE, |
|
|
|
|
]; |
|
|
|
|
|
|
|
|
|
$rows[] = [ |
|
|
|
|
$display ? $field_profile['details_link'] : $field_profile['label'], |
|
|
|
|
$field_profile['machine_name'], |
|
|
|
|
@ -479,9 +527,8 @@ class MetadataProfileController extends ControllerBase {
|
|
|
|
|
$field_profile['required'], |
|
|
|
|
$field_profile['repeatable'], |
|
|
|
|
$field_profile['auto_create'], |
|
|
|
|
|
|
|
|
|
$this->yesNoIcon($field_profile['search_api']['in_search_api'],$this->t('In search api')), |
|
|
|
|
$this->YesNoIcon($field_profile['search_api']['has_facet'], $this->t('Faceted')), |
|
|
|
|
$this->yesNoIcon($search_api['in_search_api'], $this->t('In search api')), |
|
|
|
|
$this->yesNoIcon($search_api['has_facet'], $this->t('Faceted')), |
|
|
|
|
$display |
|
|
|
|
? $this->formatListForTable($bundles) |
|
|
|
|
: $bundles, |
|
|
|
|
@ -490,31 +537,184 @@ class MetadataProfileController extends ControllerBase {
|
|
|
|
|
]; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
usort($rows, function($a, $b) { |
|
|
|
|
return $b[11] <=> $a[11]; |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
return $rows; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
protected function getHeaders() { |
|
|
|
|
/** |
|
|
|
|
* Gets the summary table header definitions. |
|
|
|
|
* |
|
|
|
|
* @return array |
|
|
|
|
* Header definitions for the sortable summary table. |
|
|
|
|
*/ |
|
|
|
|
protected function getHeaders(): array { |
|
|
|
|
return [ |
|
|
|
|
$this->t('Field'), |
|
|
|
|
$this->t('Machine name'), |
|
|
|
|
$this->t('Description'), |
|
|
|
|
$this->t('Type'), |
|
|
|
|
$this->t('Required'), |
|
|
|
|
$this->t('Repeatable'), |
|
|
|
|
$this->t('Create new'), |
|
|
|
|
$this->t('In Search API'), |
|
|
|
|
$this->t('Has Facet'), |
|
|
|
|
$this->t('Target bundles'), |
|
|
|
|
$this->t('Weight'), |
|
|
|
|
$this->t("Usage count"), |
|
|
|
|
[ |
|
|
|
|
'data' => $this->t('Field'), |
|
|
|
|
'field' => 'field', |
|
|
|
|
], |
|
|
|
|
[ |
|
|
|
|
'data' => $this->t('Machine name'), |
|
|
|
|
'field' => 'machine_name', |
|
|
|
|
], |
|
|
|
|
[ |
|
|
|
|
'data' => $this->t('Description'), |
|
|
|
|
'field' => 'description', |
|
|
|
|
], |
|
|
|
|
[ |
|
|
|
|
'data' => $this->t('Type'), |
|
|
|
|
'field' => 'type', |
|
|
|
|
], |
|
|
|
|
[ |
|
|
|
|
'data' => $this->t('Required'), |
|
|
|
|
'field' => 'required', |
|
|
|
|
], |
|
|
|
|
[ |
|
|
|
|
'data' => $this->t('Repeatable'), |
|
|
|
|
'field' => 'repeatable', |
|
|
|
|
], |
|
|
|
|
[ |
|
|
|
|
'data' => $this->t('Create new'), |
|
|
|
|
'field' => 'auto_create', |
|
|
|
|
], |
|
|
|
|
[ |
|
|
|
|
'data' => $this->t('In Search API'), |
|
|
|
|
'field' => 'in_search_api', |
|
|
|
|
], |
|
|
|
|
[ |
|
|
|
|
'data' => $this->t('Has Facet'), |
|
|
|
|
'field' => 'has_facet', |
|
|
|
|
], |
|
|
|
|
[ |
|
|
|
|
'data' => $this->t('Target bundles'), |
|
|
|
|
'field' => 'target_bundles', |
|
|
|
|
], |
|
|
|
|
[ |
|
|
|
|
'data' => $this->t('Weight'), |
|
|
|
|
'field' => 'weight', |
|
|
|
|
], |
|
|
|
|
[ |
|
|
|
|
'data' => $this->t('Usage count'), |
|
|
|
|
'field' => 'usage_count', |
|
|
|
|
'sort' => 'desc', |
|
|
|
|
], |
|
|
|
|
|
|
|
|
|
// TODO: add more columns |
|
|
|
|
]; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Sorts summary table rows using Drupal table sort query parameters. |
|
|
|
|
* |
|
|
|
|
* If no table column has been selected, rows are sorted by usage count in |
|
|
|
|
* descending order. |
|
|
|
|
* |
|
|
|
|
* @param array $rows |
|
|
|
|
* The rows to sort, passed by reference. |
|
|
|
|
* @param array $header |
|
|
|
|
* The table header definition used to map labels to row indexes. |
|
|
|
|
* |
|
|
|
|
* @return void |
|
|
|
|
*/ |
|
|
|
|
protected function sortRows(array &$rows, array $header): void { |
|
|
|
|
$request = \Drupal::request(); |
|
|
|
|
|
|
|
|
|
$order = $request->query->get('order'); |
|
|
|
|
$sort = strtolower((string) $request->query->get('sort', 'desc')); |
|
|
|
|
|
|
|
|
|
// Default sort if no column has been clicked yet. |
|
|
|
|
if (!$order) { |
|
|
|
|
usort($rows, function ($a, $b) { |
|
|
|
|
return ($b[11] ?? 0) <=> ($a[11] ?? 0); |
|
|
|
|
}); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
$column_index = NULL; |
|
|
|
|
|
|
|
|
|
foreach ($header as $index => $column) { |
|
|
|
|
if ((string) $column['data'] === $order) { |
|
|
|
|
$column_index = $index; |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if ($column_index === NULL) { |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
usort($rows, function ($a, $b) use ($column_index, $sort) { |
|
|
|
|
$a_value = $this->extractSortableValue($a[$column_index] ?? ''); |
|
|
|
|
$b_value = $this->extractSortableValue($b[$column_index] ?? ''); |
|
|
|
|
|
|
|
|
|
if (is_numeric($a_value) && is_numeric($b_value)) { |
|
|
|
|
$result = $a_value <=> $b_value; |
|
|
|
|
} |
|
|
|
|
else { |
|
|
|
|
$result = strnatcasecmp((string) $a_value, (string) $b_value); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return $sort === 'desc' ? -$result : $result; |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Extracts value from a renderable table cell for sorting. |
|
|
|
|
* |
|
|
|
|
* @param mixed $cell |
|
|
|
|
* A scalar value, Link object, or render array from a table cell. |
|
|
|
|
* |
|
|
|
|
* @return string|int|float |
|
|
|
|
* The sortable scalar value. |
|
|
|
|
*/ |
|
|
|
|
protected function extractSortableValue($cell): string|int|float { |
|
|
|
|
if (is_scalar($cell) || $cell === NULL) { |
|
|
|
|
return $cell ?? ''; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if ($cell instanceof Link) { |
|
|
|
|
return (string) $cell->getText(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (is_array($cell)) { |
|
|
|
|
if (isset($cell['data']) && is_scalar($cell['data'])) { |
|
|
|
|
return $cell['data']; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (isset($cell['#plain_text'])) { |
|
|
|
|
return $cell['#plain_text']; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (isset($cell['#markup'])) { |
|
|
|
|
return trim(strip_tags((string) $cell['#markup'])); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (isset($cell['data']['#markup'])) { |
|
|
|
|
return trim(strip_tags((string) $cell['data']['#markup'])); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (isset($cell['data']['#plain_text'])) { |
|
|
|
|
return $cell['data']['#plain_text']; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (isset($cell['data']['#items']) && is_array($cell['data']['#items'])) { |
|
|
|
|
return implode(', ', array_map('strval', $cell['data']['#items'])); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return ''; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Builds the detailed render array for a single field profile. |
|
|
|
|
* |
|
|
|
|
* @param array $field_profile |
|
|
|
|
* A field profile array produced by ::getMetadataProfile(). |
|
|
|
|
* |
|
|
|
|
* @return array |
|
|
|
|
* A render array for the field details section, or an empty array if the |
|
|
|
|
* field should not be displayed. |
|
|
|
|
*/ |
|
|
|
|
protected function buildField(array $field_profile) { |
|
|
|
|
$render_array = []; |
|
|
|
|
$field_name = $field_profile['machine_name']; |
|
|
|
|
@ -568,6 +768,15 @@ class MetadataProfileController extends ControllerBase {
|
|
|
|
|
return $render_array; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Gets the edit URL for a configurable field or base field override. |
|
|
|
|
* |
|
|
|
|
* @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition |
|
|
|
|
* The field definition. |
|
|
|
|
* |
|
|
|
|
* @return \Drupal\Core\Url|null |
|
|
|
|
* The edit URL, or NULL when no editable route is available. |
|
|
|
|
*/ |
|
|
|
|
protected function getFieldEditUrl(FieldDefinitionInterface $field_definition) { |
|
|
|
|
$redirect_url = Url::fromRoute('<current>', ['fragment' => $field_definition->getName()]); |
|
|
|
|
if ($field_definition->getFieldStorageDefinition() instanceof BaseFieldDefinition) { |
|
|
|
|
@ -597,11 +806,31 @@ class MetadataProfileController extends ControllerBase {
|
|
|
|
|
return $edit_url; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Builds a link to the field's details section on the current page. |
|
|
|
|
* |
|
|
|
|
* @param string $field_name |
|
|
|
|
* The field machine name, used as the fragment identifier. |
|
|
|
|
* @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition |
|
|
|
|
* The field definition. |
|
|
|
|
* |
|
|
|
|
* @return \Drupal\Core\Link |
|
|
|
|
* A link to the field details anchor. |
|
|
|
|
*/ |
|
|
|
|
private function getFieldDetailsFragmentLink(string $field_name, FieldDefinitionInterface $field_definition) { |
|
|
|
|
$url = Url::fromRoute('<current>', [], ['fragment' => $field_name]); |
|
|
|
|
return Link::fromTextAndUrl($field_definition->getLabel(), $url); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Formats a field edit URL as a Drupal link render array. |
|
|
|
|
* |
|
|
|
|
* @param \Drupal\Core\Url $edit_url |
|
|
|
|
* The field edit URL. |
|
|
|
|
* |
|
|
|
|
* @return array |
|
|
|
|
* A render array for the edit link. |
|
|
|
|
*/ |
|
|
|
|
protected function formatFieldEditLink(Url $edit_url) { |
|
|
|
|
return [ |
|
|
|
|
'#type' => 'link', |
|
|
|
|
@ -611,6 +840,16 @@ class MetadataProfileController extends ControllerBase {
|
|
|
|
|
]; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Builds the configuration rows for a field details table. |
|
|
|
|
* |
|
|
|
|
* @param array $field_profile |
|
|
|
|
* A field profile array produced by ::getMetadataProfile(). |
|
|
|
|
* |
|
|
|
|
* @return array |
|
|
|
|
* A table rows array containing type, required, repeatable, auto-create, |
|
|
|
|
* and target-bundle information where applicable. |
|
|
|
|
*/ |
|
|
|
|
protected function getFieldTableRows(array $field_profile) { |
|
|
|
|
$rows = [ |
|
|
|
|
[$this->t('Type:'), $field_profile['type']], |
|
|
|
|
@ -630,6 +869,18 @@ class MetadataProfileController extends ControllerBase {
|
|
|
|
|
return $rows; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Formats the field type label for display. |
|
|
|
|
* |
|
|
|
|
* Entity reference fields include their target entity type in the display |
|
|
|
|
* label. |
|
|
|
|
* |
|
|
|
|
* @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition |
|
|
|
|
* The field definition. |
|
|
|
|
* |
|
|
|
|
* @return string |
|
|
|
|
* The human-readable field type label. |
|
|
|
|
*/ |
|
|
|
|
protected function formatType(FieldDefinitionInterface $field_definition) { |
|
|
|
|
$type = $field_definition->getType(); |
|
|
|
|
$type_label = $this->fieldTypePluginManager->getDefinition($type)['label']; |
|
|
|
|
@ -639,14 +890,33 @@ class MetadataProfileController extends ControllerBase {
|
|
|
|
|
return $type_label; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Formats the field required setting as a yes/no icon. |
|
|
|
|
* |
|
|
|
|
* @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition |
|
|
|
|
* The field definition. |
|
|
|
|
* |
|
|
|
|
* @return array |
|
|
|
|
* A render array containing the required indicator. |
|
|
|
|
*/ |
|
|
|
|
protected function formatRequired(FieldDefinitionInterface $field_definition) { |
|
|
|
|
$cardinality = $field_definition->isRequired(); |
|
|
|
|
return $this->yesNoIcon($cardinality, $this->t('Required')); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* This does not work - most fields dont have a form weight specified in |
|
|
|
|
* getDisplayOptions. |
|
|
|
|
* Gets a field's effective form-display weight. |
|
|
|
|
* |
|
|
|
|
* Nested fields inherit their parent group weight, which is combined with the |
|
|
|
|
* local field weight to preserve ordering within groups. |
|
|
|
|
* |
|
|
|
|
* @param string $field_name |
|
|
|
|
* The field machine name. |
|
|
|
|
* @param array $form |
|
|
|
|
* The rendered entity form array. |
|
|
|
|
* |
|
|
|
|
* @return int|float |
|
|
|
|
* The effective field weight, or 9999 when the field is not present. |
|
|
|
|
*/ |
|
|
|
|
protected function getWeight(string $field_name, array $form) { |
|
|
|
|
if (isset($form[$field_name])) { |
|
|
|
|
@ -664,6 +934,15 @@ class MetadataProfileController extends ControllerBase {
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Formats a field's cardinality as a repeatable indicator. |
|
|
|
|
* |
|
|
|
|
* @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition |
|
|
|
|
* The field definition. |
|
|
|
|
* |
|
|
|
|
* @return array|\Drupal\Core\StringTranslation\TranslatableMarkup |
|
|
|
|
* A yes/no icon render array, or translated text for limited cardinality. |
|
|
|
|
*/ |
|
|
|
|
protected function formatCardinality(FieldDefinitionInterface $field_definition) { |
|
|
|
|
$cardinality = $field_definition |
|
|
|
|
->getFieldStorageDefinition() |
|
|
|
|
@ -682,6 +961,16 @@ class MetadataProfileController extends ControllerBase {
|
|
|
|
|
]); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Formats whether referenced entities can be auto-created on submission. |
|
|
|
|
* |
|
|
|
|
* @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition |
|
|
|
|
* The field definition. |
|
|
|
|
* |
|
|
|
|
* @return array|null |
|
|
|
|
* A yes/no icon render array for supported reference fields, or NULL for |
|
|
|
|
* non-reference fields. |
|
|
|
|
*/ |
|
|
|
|
protected function formatCreateNew(FieldDefinitionInterface $field_definition) { |
|
|
|
|
if (!in_array($field_definition->getType(), [ |
|
|
|
|
'entity_reference', |
|
|
|
|
@ -696,6 +985,15 @@ class MetadataProfileController extends ControllerBase {
|
|
|
|
|
return $this->yesNoIcon($create_new, $this->t("Creatable")); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Formats target bundle restrictions for an entity reference field. |
|
|
|
|
* |
|
|
|
|
* @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition |
|
|
|
|
* The field definition. |
|
|
|
|
* |
|
|
|
|
* @return array |
|
|
|
|
* A list of allowed target bundles, labelled where supported. |
|
|
|
|
*/ |
|
|
|
|
protected function formatTargetBundles(FieldDefinitionInterface $field_definition) { |
|
|
|
|
$handler = $field_definition->getSetting('handler'); |
|
|
|
|
$setting = $field_definition->getSetting('handler_settings'); |
|
|
|
|
@ -729,6 +1027,15 @@ class MetadataProfileController extends ControllerBase {
|
|
|
|
|
]; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Formats a list as an item-list render array inside a table cell. |
|
|
|
|
* |
|
|
|
|
* @param array $list |
|
|
|
|
* The list items. |
|
|
|
|
* |
|
|
|
|
* @return array |
|
|
|
|
* A table cell render array containing an unordered item list. |
|
|
|
|
*/ |
|
|
|
|
protected function formatListForTable(array $list) { |
|
|
|
|
return [ |
|
|
|
|
'data' => [ |
|
|
|
|
@ -739,6 +1046,16 @@ class MetadataProfileController extends ControllerBase {
|
|
|
|
|
]; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Builds the Search API table for a field profile. |
|
|
|
|
* |
|
|
|
|
* @param array $field_profile |
|
|
|
|
* A field profile array produced by ::getMetadataProfile(). |
|
|
|
|
* |
|
|
|
|
* @return array |
|
|
|
|
* A render array for the Search API table, or an empty array when the field |
|
|
|
|
* is not indexed. |
|
|
|
|
*/ |
|
|
|
|
protected function formatSearchApi($field_profile) { |
|
|
|
|
if (!$field_profile['search_api']['in_search_api']) { |
|
|
|
|
return []; |
|
|
|
|
@ -769,6 +1086,20 @@ class MetadataProfileController extends ControllerBase {
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Builds Search API metadata for one indexed field setting. |
|
|
|
|
* |
|
|
|
|
* @param string $field_setting_name |
|
|
|
|
* The Search API field machine name. |
|
|
|
|
* @param array $field_setting |
|
|
|
|
* The Search API field setting array from index configuration. |
|
|
|
|
* @param \Drupal\Core\Config\ImmutableConfig $index_config |
|
|
|
|
* The Search API index configuration object. |
|
|
|
|
* |
|
|
|
|
* @return array |
|
|
|
|
* Structured Search API field metadata, including included fields and facet |
|
|
|
|
* information where available. |
|
|
|
|
*/ |
|
|
|
|
protected function getSearchApiField($field_setting_name, $field_setting, $index_config) { |
|
|
|
|
$search_api_field_array = [ |
|
|
|
|
'search_api_field_name' => $field_setting_name, |
|
|
|
|
@ -819,10 +1150,28 @@ class MetadataProfileController extends ControllerBase {
|
|
|
|
|
return $search_api_field_array; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Determines whether a facet block is placed. |
|
|
|
|
* |
|
|
|
|
* @param mixed $facet |
|
|
|
|
* The facet entity. |
|
|
|
|
* |
|
|
|
|
* @return string |
|
|
|
|
* Placement status text. Currently returns an empty string. |
|
|
|
|
*/ |
|
|
|
|
protected function getBlockVisible($facet) { |
|
|
|
|
return ''; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Formats one Search API field profile as a table row. |
|
|
|
|
* |
|
|
|
|
* @param array $search_api_field_profile |
|
|
|
|
* Structured Search API field metadata. |
|
|
|
|
* |
|
|
|
|
* @return array |
|
|
|
|
* A table row render array. |
|
|
|
|
*/ |
|
|
|
|
protected function formatSearchApiField($search_api_field_profile) { |
|
|
|
|
return [ |
|
|
|
|
'data' => [ |
|
|
|
|
@ -875,15 +1224,14 @@ class MetadataProfileController extends ControllerBase {
|
|
|
|
|
/** |
|
|
|
|
* Generates and returns a CSV download of the metadata profile. |
|
|
|
|
* |
|
|
|
|
* Writes a temporary CSV file and serves it using Drupal's |
|
|
|
|
* file download controller. |
|
|
|
|
* Writes a temporary CSV file and serves it as an attachment. |
|
|
|
|
* |
|
|
|
|
* @param \Drupal\node\NodeTypeInterface $node_type |
|
|
|
|
* The node type whose metadata profile should be exported. |
|
|
|
|
* |
|
|
|
|
* @return \Symfony\Component\HttpFoundation\BinaryFileResponse |
|
|
|
|
* The file download response. |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function download(NodeTypeInterface $node_type) { |
|
|
|
|
// Rebuild your state from the entity |
|
|
|
|
$this->entityBundle = $node_type->id(); |
|
|
|
|
@ -892,7 +1240,9 @@ class MetadataProfileController extends ControllerBase {
|
|
|
|
|
$contentType = $this->entityBundle; |
|
|
|
|
$entityKey = $this->entityTypeBundleOf; |
|
|
|
|
|
|
|
|
|
$headers = $this->getHeaders(); |
|
|
|
|
$headers = array_map(function ($header) { |
|
|
|
|
return is_array($header) && isset($header['data']) ? (string) $header['data'] : (string) $header; |
|
|
|
|
}, $this->getHeaders()); |
|
|
|
|
$metadata_profile = $this->getMetadataProfile(); |
|
|
|
|
$rows = $this->getRows($metadata_profile); |
|
|
|
|
$rows = $this->sanitizeRowsForCSV($rows); |
|
|
|
|
@ -920,6 +1270,16 @@ class MetadataProfileController extends ControllerBase {
|
|
|
|
|
return $response; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Builds the facets table for a field profile. |
|
|
|
|
* |
|
|
|
|
* @param array $field_profile |
|
|
|
|
* A field profile array produced by ::getMetadataProfile(). |
|
|
|
|
* |
|
|
|
|
* @return array |
|
|
|
|
* A render array for the facets table, or an empty array when no facets are |
|
|
|
|
* present. |
|
|
|
|
*/ |
|
|
|
|
private function formatFacets(array $field_profile) { |
|
|
|
|
if (!$field_profile['search_api']['has_facet']) { |
|
|
|
|
return []; |
|
|
|
|
@ -952,6 +1312,15 @@ class MetadataProfileController extends ControllerBase {
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Formats one facet definition as a table row. |
|
|
|
|
* |
|
|
|
|
* @param array $facet |
|
|
|
|
* A structured facet metadata array. |
|
|
|
|
* |
|
|
|
|
* @return array |
|
|
|
|
* A table row render array. |
|
|
|
|
*/ |
|
|
|
|
private function formatFacet($facet) { |
|
|
|
|
return [ |
|
|
|
|
'data' => [ |
|
|
|
|
@ -965,6 +1334,17 @@ class MetadataProfileController extends ControllerBase {
|
|
|
|
|
]; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Adds form-display weights to field profiles and sorts them by weight. |
|
|
|
|
* |
|
|
|
|
* Weight extraction is currently implemented for node bundles. |
|
|
|
|
* |
|
|
|
|
* @param array $metadata_profile |
|
|
|
|
* Metadata profile array keyed by field machine name. |
|
|
|
|
* |
|
|
|
|
* @return array |
|
|
|
|
* The metadata profile array with weight values added where available. |
|
|
|
|
*/ |
|
|
|
|
private function addWeights(array $metadata_profile) { |
|
|
|
|
if ($this->entityTypeBundleOf == 'node') { |
|
|
|
|
$node = \Drupal\node\Entity\Node::create(['type' => $this->entityBundle]); |
|
|
|
|
@ -980,6 +1360,17 @@ class MetadataProfileController extends ControllerBase {
|
|
|
|
|
return $metadata_profile; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Combines parent and local form weights into a sortable decimal weight. |
|
|
|
|
* |
|
|
|
|
* @param int|float $parent_weight |
|
|
|
|
* The parent element weight. |
|
|
|
|
* @param int|float $local_weight |
|
|
|
|
* The local element weight. |
|
|
|
|
* |
|
|
|
|
* @return float |
|
|
|
|
* The combined sortable weight. |
|
|
|
|
*/ |
|
|
|
|
private function combineWeights($parent_weight, $local_weight) { |
|
|
|
|
$parent_int = (string) floor($parent_weight); |
|
|
|
|
$parent_fraction = (string) ($parent_weight - $parent_int); |
|
|
|
|
@ -1066,6 +1457,8 @@ class MetadataProfileController extends ControllerBase {
|
|
|
|
|
* |
|
|
|
|
* @param bool $value |
|
|
|
|
* TRUE for yes, FALSE for no. |
|
|
|
|
* @param string $tooltip |
|
|
|
|
* Text used in the icon title attribute. |
|
|
|
|
* |
|
|
|
|
* @return array |
|
|
|
|
* Render array containing markup for the icon. |
|
|
|
|
|