diff --git a/css/metadata_profile.css b/css/metadata_profile.css
new file mode 100644
index 0000000..5c453a8
--- /dev/null
+++ b/css/metadata_profile.css
@@ -0,0 +1,17 @@
+.field-info-table {
+ max-width: 40rem;
+}
+.field-info-table td {
+ max-width: 49%;
+}
+.field-info {
+ padding-bottom: 3rem;
+ border-bottom: gainsboro 1px solid;
+ margin-bottom: 3rem;
+}
+.field-info h2 {
+ display: inline-block;
+}
+.field-info .edit-link {
+ display: block;
+}
diff --git a/metadata_profile.libraries.yml b/metadata_profile.libraries.yml
new file mode 100644
index 0000000..ffb39c4
--- /dev/null
+++ b/metadata_profile.libraries.yml
@@ -0,0 +1,4 @@
+metadata_profile:
+ css:
+ theme:
+ css/metadata_profile.css: {}
diff --git a/metadata_profile.routing.yml b/metadata_profile.routing.yml
new file mode 100644
index 0000000..a069f2f
--- /dev/null
+++ b/metadata_profile.routing.yml
@@ -0,0 +1,13 @@
+metadata_profile.node_profile:
+ path: '/admin/structure/types/manage/{content_type}/metadata_profile'
+ defaults:
+ _controller: '\Drupal\metadata_profile\Controller\MetadataProfileController::profile'
+ _title: 'Metadata Profile'
+ requirements:
+ _access: 'TRUE'
+ content_type: '[a-zA-Z_]+'
+ options:
+ parameters:
+ content_type:
+ type: string
+
diff --git a/src/Controller/MetadataProfileController.php b/src/Controller/MetadataProfileController.php
new file mode 100644
index 0000000..cb07b74
--- /dev/null
+++ b/src/Controller/MetadataProfileController.php
@@ -0,0 +1,214 @@
+entityFieldManager = $entity_field_manager;
+ $this->fieldTypePluginManager = $field_type_plugin_manager;
+ }
+
+ public static function create(ContainerInterface $container) {
+ return new static(
+ $container->get('entity_field.manager'),
+ $container->get('plugin.manager.field.field_type')
+ );
+ }
+
+
+ public function profile( $content_type) {
+
+ // Get core content type information.
+ $node_type = $this->config('node.type.' . $content_type);
+ if (!$node_type) {
+ return ['#markup'=> 'Not a valid content type.'];
+ }
+ $build = $this->format_bundle($node_type);
+
+ $build['children'] = [
+ '#type' => 'container',
+ '#weight' => '9',
+ ];
+ // Get field information.
+ $field_definitions = $this->entityFieldManager->getFieldDefinitions('node', $content_type);
+ foreach ($field_definitions as $field_name => $field_definition) {
+ $build['children'][$field_name] = $this->format_field($field_name, $field_definition);
+ }
+
+ return $build;
+ }
+
+ /**
+ * Format information about a bundle.
+ */
+ protected function format_bundle(Config $bundle) {
+ $build = [
+ '#type' => 'container',
+ '#attached' => ['library' => ['metadata_profile/metadata_profile']],
+
+ 'title' => [
+ '#plain_text' => $bundle->get('name'),
+ '#prefix' => '
',
+ '#suffix' => '
',
+ ],
+ 'machine_name' => [
+ '#plain_text' => $bundle->get('type'),
+ '#prefix' => ' (',
+ '#suffix' => ')',
+ ],
+ 'description' => [
+ '#plain_text' => $bundle->get('description'),
+ '#prefix' => '',
+ '#suffix' => '
',
+ ],
+ ];
+ return $build;
+ }
+
+ protected function format_field(string $field_name, FieldDefinitionInterface $field_definition) {
+ $render_array = [];
+ if (str_starts_with($field_name, 'field_') or $field_name == 'title') {
+ $render_array = [
+ '#type' => 'container',
+ '#attributes' => ['class' => ['field-info']],
+ '#weight' => $this->format_weight($field_definition),
+ 'title' => [
+ '#plain_text' => $field_definition->getLabel(),
+ '#prefix' => '',
+ '#suffix' => '
',
+ ],
+ 'machine_name' => [
+ '#plain_text' => $field_name,
+ '#prefix' => '(',
+ '#suffix' => ') ',
+ ],
+ 'edit_link' => [
+ '#type' => 'link',
+ '#url' => Url::fromRoute('entity.field_config.node_field_edit_form', [
+ 'node_type' => $field_definition->getTargetBundle(),
+ 'field_config' => $field_definition->id(),
+ 'destination' => Url::fromRoute('metadata_profile.node_profile', ['content_type' => $field_definition->getTargetBundle()], ['fragment' => $field_name])->toString(),
+ ]),
+ '#title' => $this->t('Edit'),
+ '#attributes' => ['class' => ['edit-link']],
+ ],
+ 'table' => [
+ '#type' => 'table',
+ '#header' => ['',''],
+ '#rows' => $this->getFieldTableRows($field_definition),
+ '#attributes' => ['class' => ['field-info-table']],
+ ],
+ 'description' => [
+ '#type' => 'markup',
+ '#markup' => $field_definition->getDescription() ?: $this->t('[No description]'),
+ ],
+ 'target_bundles' => [
+ '#title' => $this->t('Target Bundles'),
+ '#type' => 'container',
+ 'bundles' => $this->format_target_bundles($field_definition),
+ ],
+ ];
+ }
+
+ return $render_array;
+ }
+
+ protected function getFieldTableRows(FieldDefinitionInterface $field_definition) {
+ $rows = [
+ [$this->t('Type:'), $this->format_type($field_definition)],
+ [$this->t('Required:'), $this->format_required($field_definition)],
+ [$this->t('Repeatable:'), $this->format_cardinality($field_definition)],
+ ];
+ // TODO: use a class inheritance method to get entity reference and typed relation in one shot.
+ if (in_array($field_definition->getType(), ['entity_reference', 'typed_relation'])) {
+ $rows[] = [$this->t('Create new'), $this->format_create_new($field_definition)];
+ }
+
+ return $rows;
+ }
+
+ protected function format_type(FieldDefinitionInterface $field_definition) {
+ $type = $field_definition->getType();
+ $type_label = $this->fieldTypePluginManager->getDefinition($type)['label'];
+ if (in_array($type, ['entity_reference', 'typed_relation'])) {
+ $type_label = $type_label . ' (' . $field_definition->getSetting('target_type') . ')';
+ }
+ return $type_label;
+ }
+ protected function format_required(FieldDefinitionInterface $field_definition) {
+ if ($field_definition->isRequired()) {
+ return $this->t('Required');
+ }
+ else {
+ return $this->t('Not required');
+ }
+ }
+
+ protected function format_weight(FieldDefinitionInterface $field_definition) {
+ return $field_definition->getDisplayOptions('form')['weight'];
+ }
+
+ protected function format_cardinality(FieldDefinitionInterface $field_definition) {
+ $cardinality = $field_definition->getFieldStorageDefinition()->getCardinality();
+ if ($cardinality == 1) {
+ return $this->t('Not repeatable');
+ } elseif ($cardinality < 0) {
+ return $this->t('Repeatable');
+ } elseif ($cardinality > 1) {
+ return $this->t('Repeatable, limit :limit', [':limit' => $cardinality]);
+ }
+ return NULL;
+ }
+
+ protected function format_create_new(FieldDefinitionInterface $field_definition) {
+ $create_new_bundle = $field_definition->getSetting('handler_settings')['auto_create_bundle'];
+ $create_new = $field_definition->getSetting('handler_settings')['auto_create_bundle'];
+ if ($create_new) {
+ return $create_new_bundle ? 'Create new (' . $create_new_bundle . ')' : 'Create new';
+ }
+ else {
+ return $this->t('Do not create new');
+ }
+ }
+
+ protected function format_target_bundles(FieldDefinitionInterface $field_definition) {
+ $handler = $field_definition->getSetting('handler');
+ $setting = $field_definition->getSetting('handler_settings');
+ if (!$setting) {
+ return [];
+ }
+ $target_bundles = $setting['target_bundles'];
+ foreach ($target_bundles as $index => $bundle) {
+ if ($handler == 'default:taxonomy_term') {
+ $bundle_config = $this->entityTypeManager()->getStorage('taxonomy_vocabulary')->load($bundle);
+ }
+ // TODO: ADD NODE ETC
+ if ($bundle_config) {
+ $target_bundles[$index] = $bundle_config->get('name') . ' (' . $bundle . ')';
+ }
+ }
+ return [
+ '#theme' => 'item_list',
+ '#title' => $this->t('Target bundles:'),
+ '#items' => $target_bundles,
+ '#type' => 'ul'
+ ];
+ }
+
+}