Skip to content
Snippets Groups Projects
Commit 1e2374be authored by Steve Wirt's avatar Steve Wirt
Browse files

Issue #3386369 by swirt: CM Document of field should show link to basefield document if one exists

parent f2467484
No related branches found
No related tags found
No related merge requests found
<?php
namespace Drupal\content_model_documentation;
use Drupal\content_model_documentation\Entity\CMDocumentInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityViewBuilder;
/**
* Defines a class for entity view builder for linky entities.
*/
class CmDocumentViewBuilder extends EntityViewBuilder {
use CMDocumentConnectorTrait;
/**
* {@inheritdoc}
*/
public function view(EntityInterface $cm_document, $view_mode = 'full', $langcode = NULL) {
$build = parent::view($cm_document, $view_mode, $langcode);
$add_ons = $this->getAddOns($cm_document);
$build = array_merge($build, $add_ons);
return $build;
}
/**
* Grabs all the add on render arrays for a given kind of documentation.
*
* @param \Drupal\content_model_documentation\Entity\CMDocumentInterface $cm_document
* The current document to process.
*
* @return array
* An array of render arrays to be added on.
*/
protected function getAddOnTypes(CMDocumentInterface $cm_document): array {
$documentation_for = $cm_document->get('documented_entity')->value;
$type = $cm_document->getDocumentedEntityParameter('type');
$bundle = $cm_document->getDocumentedEntityParameter('bundle');
$field = $cm_document->getDocumentedEntityParameter('field');
// Order of the addons specified determines their order on the page.
switch (TRUE) {
case ($type === 'base' && !empty($field)):
$add_ons = ['SiblingFields'];
break;
case (!empty($field)):
$add_ons = ['AppearsOn', 'BaseField', 'SiblingFields'];
break;
default:
$add_ons = [];
break;
}
return $add_ons;
}
/**
* Gets all the add ons that should appear on a CM Document.
*
* @param \Drupal\content_model_documentation\Entity\CMDocumentInterface $cm_document
* The current document to process.
*
* @return array
* An array of render arrays for each of the related add ons.
*/
protected function getAddOns(CMDocumentInterface $cm_document): array {
$add_on_types = $this->getAddOnTypes($cm_document);
$add_ons = [];
foreach ($add_on_types as $i => $add_on) {
$func = "get{$add_on}";
$add_ons["$add_on"] = $this->$func($cm_document);
}
return $add_ons;
}
/**
* Gets a render array showing the content type this field appears on.
*
* @param \Drupal\content_model_documentation\Entity\CMDocumentInterface $cm_document
* The current document to process.
*
* @return array
* A renderable array for the appears on section of the page.
*/
protected function getAppearsOn(CMDocumentInterface $cm_document): array {
$add_on = [];
$type = $cm_document->getDocumentedEntityParameter('type');
$bundle = $cm_document->getDocumentedEntityParameter('bundle');
$field = $cm_document->getDocumentedEntityParameter('field');
$documented_entity = $cm_document->getDocumentedEntity();
$label = (empty($documented_entity)) ? $this->t('undefined') : $documented_entity->label();
$cm_doc_link = $this->getCmDocumentLink($type, $bundle);
if ($cm_doc_link) {
$add_on = $cm_doc_link->toRenderable();
$add_on['#title'] = "$type $label ($bundle)";
}
else {
$add_on = [
'#type' => 'html_tag',
'#tag' => 'span',
'#value' => "$type $label ($bundle)",
];
}
$add_on['#prefix'] = "<span class=\"field__label\">{$this->t('Appears on: ')}</span>";
// This one should be near the top of the page.
$add_on['#weight'] = -10;
return $add_on;
}
/**
* Gets a link to the base field CM Document if it exists.
*
* @param \Drupal\content_model_documentation\Entity\CMDocumentInterface $cm_document
* The current document to process.
*
* @return array
* A render array for a link if one exists, or an empty array.
*/
protected function getBaseField(CMDocumentInterface $cm_document): array {
$add_on = [];
$field = $cm_document->getDocumentedEntityParameter('field');
$base_cm_doc = "base.field.$field";
// Does documentation for the base field exist?
$cm_doc_link = $this->getCmDocumentLink('base', 'field', $field);
if ($cm_doc_link) {
$add_on = $cm_doc_link->toRenderable();
$add_on['#title'] = $this->t('Base @field documentation', ['@field' => $field]);
$add_on['#weight'] = 10;
}
return $add_on;
}
/**
* Gets a a table of siblings if they exist.
*
* @param \Drupal\content_model_documentation\Entity\CMDocumentInterface $cm_document
* The current document to process.
*
* @return array
* A render array for a table if siblings exists, or an empty array.
*/
protected function getSiblingFields(CMDocumentInterface $cm_document): array {
$add_on = [];
$rows = $this->buildSiblingRows($cm_document);
if (!empty($rows)) {
$type = $cm_document->getDocumentedEntityParameter('type');
$field = $cm_document->getDocumentedEntityParameter('field');
// Adjust the count for display where the documented field was removed.
$count = ($type === 'base') ? count($rows) : count($rows) + 1;
$add_on['table'] = [
'#type' => 'table',
'#header' => [
$this->t("Field Name"),
$this->t("Entity Type"),
$this->t("Bundle"),
$this->t("Field Type"),
$this->t("Documentation"),
],
'#rows' => $rows,
'#footer' => [["Total instances: $count", '', '', '', '']],
'#empty' => $this->t('No table content found.'),
'#caption' => $this->t("Sibling instances of field @field.", ['@field' => $field]),
'#attributes' => [
'class' => ['sortable'],
],
'#attached' => ['library' => ['content_model_documentation/sortable-init']],
];
$add_on['#weight'] = 20;
}
return $add_on;
}
/**
* Builds the rows of all instances of a field.
*
* @param \Drupal\content_model_documentation\Entity\CMDocumentInterface $cm_document
* The current document to process.
*
* @return array
* An array of table rows.
*/
protected function buildSiblingRows(CMDocumentInterface $cm_document): array {
$sibling_rows = [];
$field = $cm_document->getDocumentedEntityParameter('field');
$src_bundle = $cm_document->getDocumentedEntityParameter('bundle');
$mapped_types = $cm_document->entityFieldManager->getFieldMap();
foreach ($mapped_types as $entity_type => $fields) {
if (!empty($fields[$field])) {
foreach ($fields[$field]['bundles'] as $bundle) {
// Do not include CM Documents in this list, or the current instance.
if ($bundle !== 'cm_document' && $src_bundle !== $bundle) {
$definitions = $cm_document->entityFieldManager->getFieldDefinitions($entity_type, $bundle);
$sibling_rows[] = [
'Field Name' => $definitions[$field]->getLabel(),
'Entity Type' => $entity_type,
'Bundle' => $bundle,
'Field Type' => $fields[$field]['type'],
'Document' => $this->getCmDocumentLink($entity_type, $bundle, $field),
];
}
}
}
}
return $sibling_rows;
}
}
...@@ -20,6 +20,13 @@ use Symfony\Component\DependencyInjection\ContainerInterface; ...@@ -20,6 +20,13 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
*/ */
class ContentModelDocumentController extends ControllerBase implements ContainerInjectionInterface { class ContentModelDocumentController extends ControllerBase implements ContainerInjectionInterface {
/**
* The date formatter.
*
* @var \Drupal\Core\Datetime\DateFormatterInterface
*/
protected $dateFormatter;
/** /**
* The renderer. * The renderer.
* *
......
...@@ -104,7 +104,7 @@ class DocumentableEntityProvider extends ServiceProviderBase { ...@@ -104,7 +104,7 @@ class DocumentableEntityProvider extends ServiceProviderBase {
$documentable_entities = $this->addEntityBundles($documentable_type, $documentable_entities); $documentable_entities = $this->addEntityBundles($documentable_type, $documentable_entities);
$documentable_entities = $this->addEntityFields($documentable_type, $documentable_entities); $documentable_entities = $this->addEntityFields($documentable_type, $documentable_entities);
} }
// Lets sort them so the make more sense in the list. // Let's sort them so they make more sense in the list.
natcasesort($documentable_entities); natcasesort($documentable_entities);
return $documentable_entities; return $documentable_entities;
} }
......
...@@ -26,7 +26,7 @@ use Drupal\user\UserInterface; ...@@ -26,7 +26,7 @@ use Drupal\user\UserInterface;
* label_collection = @Translation("Content Model Document"), * label_collection = @Translation("Content Model Document"),
* handlers = { * handlers = {
* "storage" = "\Drupal\Core\Entity\Sql\SqlContentEntityStorage", * "storage" = "\Drupal\Core\Entity\Sql\SqlContentEntityStorage",
* "view_builder" = "Drupal\Core\Entity\EntityViewBuilder", * "view_builder" = "Drupal\content_model_documentation\CmDocumentViewBuilder",
* "list_builder" = "Drupal\content_model_documentation\CMDocumentListBuilder", * "list_builder" = "Drupal\content_model_documentation\CMDocumentListBuilder",
* "views_data" = "Drupal\content_model_documentation\Entity\CMDocumentViewsData", * "views_data" = "Drupal\content_model_documentation\Entity\CMDocumentViewsData",
* "form" = { * "form" = {
...@@ -81,12 +81,19 @@ use Drupal\user\UserInterface; ...@@ -81,12 +81,19 @@ use Drupal\user\UserInterface;
class CMDocument extends EditorialContentEntityBase implements CMDocumentInterface { class CMDocument extends EditorialContentEntityBase implements CMDocumentInterface {
use CMDocumentConnectorTrait; use CMDocumentConnectorTrait;
/**
* The entity field manager.
*
* @var \Drupal\Core\Entity\EntityFieldManagerInterface
*/
public $entityFieldManager;
/** /**
* The entity type manager. * The entity type manager.
* *
* @var \Drupal\Core\Entity\EntityTypeManagerInterface * @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/ */
protected $entityTypeManager; public $entityTypeManager;
/** /**
* The entity type manager. * The entity type manager.
...@@ -102,6 +109,7 @@ class CMDocument extends EditorialContentEntityBase implements CMDocumentInterfa ...@@ -102,6 +109,7 @@ class CMDocument extends EditorialContentEntityBase implements CMDocumentInterfa
parent::__construct($values, $entity_type, $bundle, $translations); parent::__construct($values, $entity_type, $bundle, $translations);
// Can't use Dependency Injection on a @ContentEntityType. // Can't use Dependency Injection on a @ContentEntityType.
$this->entityTypeManager = \Drupal::service('entity_type.manager'); $this->entityTypeManager = \Drupal::service('entity_type.manager');
$this->entityFieldManager = \Drupal::service('entity_field.manager');
$this->pathAliasStorage = $this->entityTypeManager->getStorage('path_alias'); $this->pathAliasStorage = $this->entityTypeManager->getStorage('path_alias');
} }
...@@ -249,6 +257,21 @@ class CMDocument extends EditorialContentEntityBase implements CMDocumentInterfa ...@@ -249,6 +257,21 @@ class CMDocument extends EditorialContentEntityBase implements CMDocumentInterfa
return $return; return $return;
} }
/**
* {@inheritdoc}
*/
public function getDocumentedEntity(): object|null {
$content_type = NULL;
$type = $this->getDocumentedEntityParameter('type');
$bundle = $this->getDocumentedEntityParameter('bundle');
$type_map = $this->getStorageMap();
if (!empty($type_map[$type])) {
$storage = $this->entityTypeManager->getStorage($type_map[$type]);
$content_type = $storage->load($bundle);
}
return $content_type;
}
/** /**
* Remove existing aliases that do not match new & return remaining count. * Remove existing aliases that do not match new & return remaining count.
* *
...@@ -464,4 +487,18 @@ class CMDocument extends EditorialContentEntityBase implements CMDocumentInterfa ...@@ -464,4 +487,18 @@ class CMDocument extends EditorialContentEntityBase implements CMDocumentInterfa
return $fields; return $fields;
} }
/**
* {@inheritdoc}
*/
public function getStorageMap(): array {
return [
'node' => 'node_type',
'media' => 'media_type',
'block_content' => 'block_content_type',
'menu_link_content' => 'menu_link_content',
'paragraph' => 'paragraphs_type',
'taxonomy_term' => 'taxonomy_vocabulary',
];
}
} }
...@@ -64,6 +64,14 @@ interface CMDocumentInterface extends ContentEntityInterface, RevisionLogInterfa ...@@ -64,6 +64,14 @@ interface CMDocumentInterface extends ContentEntityInterface, RevisionLogInterfa
*/ */
public function getDocumentedEntityParameter($element): string; public function getDocumentedEntityParameter($element): string;
/**
* Loads and returns the entity that is being documented.
*
* @return object|null
* The object being documented (node, vocabulary, field...) NULL if none.
*/
public function getDocumentedEntity(): object|null;
/** /**
* Calculates the intended alias for the CM Document. * Calculates the intended alias for the CM Document.
* *
...@@ -88,4 +96,12 @@ interface CMDocumentInterface extends ContentEntityInterface, RevisionLogInterfa ...@@ -88,4 +96,12 @@ interface CMDocumentInterface extends ContentEntityInterface, RevisionLogInterfa
*/ */
public static function getOtherDocumentableTypes(): array; public static function getOtherDocumentableTypes(): array;
/**
* Gets an array of entity types mapped to storage types.
*
* @return array
* An array with elements in the form of 'entity type' => 'storage' pairs.
*/
public function getStorageMap(): array;
} }
...@@ -247,14 +247,7 @@ class CMDocumentForm extends ContentEntityForm { ...@@ -247,14 +247,7 @@ class CMDocumentForm extends ContentEntityForm {
if (!empty($bundlename)) { if (!empty($bundlename)) {
// @todo Fix menu human names of the bundle not working. // @todo Fix menu human names of the bundle not working.
$bundlelabel = $bundlename; $bundlelabel = $bundlename;
$storage_map = [ $storage_map = $document->getStorageMap();
'node' => 'node_type',
'media' => 'media_type',
'block_content' => 'block_content_type',
'menu_link_content' => 'menu_link_content',
'paragraph' => 'paragraphs_type',
'taxonomy_term' => 'taxonomy_vocabulary',
];
$storage_name = $storage_map[$entity_type] ?? $bundlename; $storage_name = $storage_map[$entity_type] ?? $bundlename;
$bundle_storage = $this->entityTypeManager->getStorage($storage_name); $bundle_storage = $this->entityTypeManager->getStorage($storage_name);
$bundle = $bundle_storage->load($bundlename); $bundle = $bundle_storage->load($bundlename);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment