class ListUsageController in Entity Usage 8.3
Same name and namespace in other branches
- 8.4 src/Controller/ListUsageController.php \Drupal\entity_usage\Controller\ListUsageController
- 8 src/Controller/ListUsageController.php \Drupal\entity_usage\Controller\ListUsageController
- 8.2 src/Controller/ListUsageController.php \Drupal\entity_usage\Controller\ListUsageController
Controller for our pages.
Hierarchy
- class \Drupal\Core\Controller\ControllerBase implements ContainerInjectionInterface uses LoggerChannelTrait, MessengerTrait, LinkGeneratorTrait, RedirectDestinationTrait, UrlGeneratorTrait, StringTranslationTrait
- class \Drupal\entity_usage\Controller\ListUsageController
Expanded class hierarchy of ListUsageController
2 files declare their use of ListUsageController
- EntityUsageSettingsForm.php in src/
Form/ EntityUsageSettingsForm.php - entity_usage.install in ./
entity_usage.install - Install, update and uninstall functions for entity_usage module.
File
- src/
Controller/ ListUsageController.php, line 22
Namespace
Drupal\entity_usage\ControllerView source
class ListUsageController extends ControllerBase {
/**
* Number of items per group to use when nothing was configured.
*/
const ITEMS_PER_GROUP_DEFAULT = 25;
/**
* The entity field manager.
*
* @var \Drupal\Core\Entity\EntityFieldManagerInterface
*/
protected $entityFieldManager;
/**
* The EntityUsage service.
*
* @var \Drupal\entity_usage\EntityUsageInterface
*/
protected $entityUsage;
/**
* The Entity Usage settings config object.
*
* @var \Drupal\Core\Config\ImmutableConfig
*/
protected $entityUsageConfig;
/**
* The database connection.
*
* @var \Drupal\Core\Database\Connection
*/
protected $database;
/**
* ListUsageController constructor.
*
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* The entity type manager.
* @param \Drupal\Core\Entity\EntityFieldManagerInterface $entity_field_manager
* The entity field manager.
* @param \Drupal\entity_usage\EntityUsageInterface $entity_usage
* The EntityUsage service.
* @param \Drupal\Core\Config\ImmutableConfig $config_factory
* The config factory.
* @param \Drupal\Core\Database\Connection $database
* The database connection.
*/
public function __construct(EntityTypeManagerInterface $entity_type_manager, EntityFieldManagerInterface $entity_field_manager, EntityUsageInterface $entity_usage, ConfigFactoryInterface $config_factory, Connection $database) {
$this->entityTypeManager = $entity_type_manager;
$this->entityFieldManager = $entity_field_manager;
$this->entityUsage = $entity_usage;
$this->entityUsageConfig = $config_factory
->get('entity_usage.settings');
$this->database = $database;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static($container
->get('entity_type.manager'), $container
->get('entity_field.manager'), $container
->get('entity_usage.usage'), $container
->get('config.factory'), $container
->get('database'));
}
/**
* Lists the usage of a given entity.
*
* @param string $entity_type
* The entity type.
* @param int $entity_id
* The entity ID.
*
* @return array
* The page build to be rendered.
*
* @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
*/
public function listUsagePage($entity_type, $entity_id) {
// Alert users that there may be hidden info in past revisions, if that's
// the case.
$target_has_hidden_usages = $this
->checkHiddenUsages($entity_type, $entity_id);
$items_per_group = $this->entityUsageConfig
->get('usage_controller_items_per_group') ?: self::ITEMS_PER_GROUP_DEFAULT;
$total = $this
->getPageRows($entity_type, $entity_id, NULL, NULL, TRUE);
$page = pager_default_initialize($total, $items_per_group);
$value_rows = $this
->getPageRows($entity_type, $entity_id, $page * $items_per_group, $items_per_group);
if (empty($value_rows)) {
if ($target_has_hidden_usages) {
$empty_message = $this
->t('There are no recorded usages for entity of type: @type with id: @id, but some usages were found in past versions (revisions) of some nodes.', [
'@type' => $entity_type,
'@id' => $entity_id,
]);
}
else {
$empty_message = $this
->t('There are no recorded usages for entity of type: @type with id: @id', [
'@type' => $entity_type,
'@id' => $entity_id,
]);
}
return [
'#markup' => $empty_message,
];
}
$header = [
$this
->t('Entity'),
$this
->t('Type'),
$this
->t('Language'),
$this
->t('Status'),
];
$entity_types = $this->entityTypeManager
->getDefinitions();
$languages = $this
->languageManager()
->getLanguages(LanguageInterface::STATE_ALL);
foreach ($value_rows as $row) {
$type_storage = $this->entityTypeManager
->getStorage($row['source_type']);
$source_entity = $type_storage
->load($row['source_id']);
if (!$source_entity) {
// If for some reason this record is broken, just skip it.
continue;
}
// Prepare the link to the source entity.
$source_link = $this
->getSourceEntityCanonicalLink($source_entity);
// Prepare the language name to display.
$lang_label = !empty($languages[$row['source_langcode']]) ? $languages[$row['source_langcode']]
->getName() : '-';
// Prepare the status text.
$published = '-';
if ($source_entity instanceof EntityPublishedInterface) {
$published = $source_entity
->isPublished() ? $this
->t('Published') : $this
->t('Unpublished');
}
$rows[] = [
$source_link,
$entity_types[$row['source_type']]
->getLabel(),
$lang_label,
$published,
];
}
$build[] = [
'#theme' => 'table',
'#rows' => $rows,
'#header' => $header,
];
$build[] = [
'#type' => 'pager',
];
if ($target_has_hidden_usages) {
$build[] = [
'#markup' => $this
->t('Note: This page only includes usages in the current revisions of referencing entities. This entity is also being used in nodes that no longer reference it on their current revision.'),
];
}
return $build;
}
/**
* Query the DB for the next page of items to display.
*
* @param string $target_type
* The target entity type.
* @param string $target_id
* The target entity ID.
* @param int $start
* The initial position to start the query range.
* @param int $items_per_page
* The number of items per page to use in the query range.
* @param bool $count_only
* (optional) Whether to return an integer with the total number of
* rows in the query, which can be used when calculating the pager output.
* Defaults to FALSE.
*
* @return array|int
* An indexed array of source entities info, where values are:
* - source_type: The source entity type.
* - source_id: The ID of the source entity.
* - source_langcode: The langcode of the source entity.
* Will return an integer with the total rows for this query if the flag
* $count_only is passed in.
*/
protected function getPageRows($target_type, $target_id, $start, $items_per_page, $count_only = FALSE) {
$rows = [];
$top_level_types = EntityUsageSourceLevel::getTopLevelEntityTypes();
foreach ($top_level_types as $source_type) {
$source_definition = \Drupal::entityTypeManager()
->getDefinition($source_type);
$source_base_table = $source_definition
->getBaseTable();
$source_revision_key = $source_definition
->hasKey('revision') ? $source_definition
->getKey('revision') : NULL;
$query = $this->database
->select('entity_usage', 'eu')
->fields('eu', [
'source_id',
'source_id_string',
'source_langcode',
])
->orderBy('source_id', 'DESC')
->condition('target_type', $target_type)
->condition('target_id', $target_id);
// If the source is revisionable, join so we only include default
// revisions in the results.
if (!empty($source_base_table) && !empty($source_revision_key)) {
$query
->innerJoin($source_base_table, 'sbt', "sbt.{$source_revision_key} = eu.source_vid");
}
if ($count_only) {
return (int) $query
->countQuery()
->execute()
->fetchField();
}
$db_rows = $query
->range($start, $items_per_page)
->execute()
->fetchAll();
foreach ($db_rows as $db_row) {
$rows[] = [
'source_type' => $source_type,
'source_id' => $db_row->source_id ?? $db_row->source_id_string,
'source_langcode' => $db_row->source_langcode,
];
}
}
// Sort by entity type ASC and then by entity ID DESC.
array_multisort(array_column($rows, 'source_type'), SORT_ASC, $rows);
array_multisort(array_column($rows, 'source_id'), SORT_DESC, $rows);
return $rows;
}
/**
* Checks whether there are hidden (past-revisions-only) usages.
*
* @param string $target_type
* The entity type name.
* @param string $target_id
* The entity ID.
*
* @return bool
* TRUE if there are usages recorded in past (non-default) revisions which
* ARE NOT present in current (default) revisions, FALSE otherwise.
*/
protected function checkHiddenUsages($target_type, $target_id) {
// For now deal only with nodes.
if (!$this
->moduleHandler()
->moduleExists('node') || !in_array('node', EntityUsageSourceLevel::getTopLevelEntityTypes())) {
return FALSE;
}
// @todo Use the DB API for this, and remove workarounds.
// What we want here is to check whether there are records in the
// entity_usage table that match this target type/id, and are NOT present
// in the node table, which means they are only present in past revisions.
$query_string = "SELECT DISTINCT node.vid FROM {entity_usage}\n LEFT JOIN {node}\n ON entity_usage.source_id = node.nid\n WHERE entity_usage.source_vid NOT IN (SELECT node.vid FROM {node})\n AND entity_usage.target_type = :target_type\n AND entity_usage.target_id = :target_id";
try {
$result = $this->database
->query($query_string, [
':target_type' => $target_type,
':target_id' => $target_id,
])
->fetchField();
} catch (DatabaseExceptionWrapper $e) {
return FALSE;
}
return !empty($result);
}
/**
* Retrieve a link to the source entity on its canonical page.
*
* @param \Drupal\Core\Entity\EntityInterface $source_entity
* The source entity.
*
* @return \Drupal\Core\Link|string
* A link to the entity, or its non-linked label, in case it was impossible
* to correctly build a link.
*/
protected function getSourceEntityCanonicalLink(EntityInterface $source_entity, $text = NULL) {
$entity_label = $source_entity
->access('view label') ? $source_entity
->label() : $this
->t('- Restricted access -');
// Prevent 404s by exposing the label unlinked if the user has no access
// to view the entity.
if ($source_entity
->hasLinkTemplate('canonical') && $source_entity
->access('view')) {
return $source_entity
->toLink();
}
else {
return $entity_label;
}
}
/**
* Checks access based on whether the user can view the current entity.
*
* @param string $entity_type
* The entity type.
* @param int $entity_id
* The entity ID.
*
* @return \Drupal\Core\Access\AccessResultInterface
* The access result.
*/
public function checkAccess($entity_type, $entity_id) {
$entity = $this->entityTypeManager
->getStorage($entity_type)
->load($entity_id);
if (!$entity || !$entity
->access('view')) {
return AccessResult::forbidden();
}
return AccessResult::allowed();
}
/**
* Title page callback.
*
* @param string $entity_type
* The entity type.
* @param int $entity_id
* The entity id.
*
* @return string
* The title to be used on this page.
*/
public function getTitle($entity_type, $entity_id) {
$entity = $this->entityTypeManager
->getStorage($entity_type)
->load($entity_id);
if ($entity) {
return $this
->t('Entity usage information for %entity_label', [
'%entity_label' => $entity
->label(),
]);
}
return $this
->t('Entity Usage List');
}
}
Members
Name | Modifiers | Type | Description | Overrides |
---|---|---|---|---|
ControllerBase:: |
protected | property | The configuration factory. | |
ControllerBase:: |
protected | property | The current user service. | 1 |
ControllerBase:: |
protected | property | The entity form builder. | |
ControllerBase:: |
protected | property | The entity manager. | |
ControllerBase:: |
protected | property | The entity type manager. | |
ControllerBase:: |
protected | property | The form builder. | 2 |
ControllerBase:: |
protected | property | The key-value storage. | 1 |
ControllerBase:: |
protected | property | The language manager. | 1 |
ControllerBase:: |
protected | property | The module handler. | 2 |
ControllerBase:: |
protected | property | The state service. | |
ControllerBase:: |
protected | function | Returns the requested cache bin. | |
ControllerBase:: |
protected | function | Retrieves a configuration object. | |
ControllerBase:: |
private | function | Returns the service container. | |
ControllerBase:: |
protected | function | Returns the current user. | 1 |
ControllerBase:: |
protected | function | Retrieves the entity form builder. | |
ControllerBase:: |
protected | function | Retrieves the entity manager service. | |
ControllerBase:: |
protected | function | Retrieves the entity type manager. | |
ControllerBase:: |
protected | function | Returns the form builder service. | 2 |
ControllerBase:: |
protected | function | Returns a key/value storage collection. | 1 |
ControllerBase:: |
protected | function | Returns the language manager service. | 1 |
ControllerBase:: |
protected | function | Returns the module handler. | 2 |
ControllerBase:: |
protected | function |
Returns a redirect response object for the specified route. Overrides UrlGeneratorTrait:: |
|
ControllerBase:: |
protected | function | Returns the state storage service. | |
LinkGeneratorTrait:: |
protected | property | The link generator. | 1 |
LinkGeneratorTrait:: |
protected | function | Returns the link generator. | |
LinkGeneratorTrait:: |
protected | function | Renders a link to a route given a route name and its parameters. | |
LinkGeneratorTrait:: |
public | function | Sets the link generator service. | |
ListUsageController:: |
protected | property | The database connection. | |
ListUsageController:: |
protected | property | The entity field manager. | |
ListUsageController:: |
protected | property | The EntityUsage service. | |
ListUsageController:: |
protected | property | The Entity Usage settings config object. | |
ListUsageController:: |
public | function | Checks access based on whether the user can view the current entity. | |
ListUsageController:: |
protected | function | Checks whether there are hidden (past-revisions-only) usages. | |
ListUsageController:: |
public static | function |
Instantiates a new instance of this class. Overrides ControllerBase:: |
|
ListUsageController:: |
protected | function | Query the DB for the next page of items to display. | |
ListUsageController:: |
protected | function | Retrieve a link to the source entity on its canonical page. | |
ListUsageController:: |
public | function | Title page callback. | |
ListUsageController:: |
constant | Number of items per group to use when nothing was configured. | ||
ListUsageController:: |
public | function | Lists the usage of a given entity. | |
ListUsageController:: |
public | function | ListUsageController constructor. | |
LoggerChannelTrait:: |
protected | property | The logger channel factory service. | |
LoggerChannelTrait:: |
protected | function | Gets the logger for a specific channel. | |
LoggerChannelTrait:: |
public | function | Injects the logger channel factory. | |
MessengerTrait:: |
protected | property | The messenger. | 29 |
MessengerTrait:: |
public | function | Gets the messenger. | 29 |
MessengerTrait:: |
public | function | Sets the messenger. | |
RedirectDestinationTrait:: |
protected | property | The redirect destination service. | 1 |
RedirectDestinationTrait:: |
protected | function | Prepares a 'destination' URL query parameter for use with \Drupal\Core\Url. | |
RedirectDestinationTrait:: |
protected | function | Returns the redirect destination service. | |
RedirectDestinationTrait:: |
public | function | Sets the redirect destination service. | |
StringTranslationTrait:: |
protected | property | The string translation service. | 1 |
StringTranslationTrait:: |
protected | function | Formats a string containing a count of items. | |
StringTranslationTrait:: |
protected | function | Returns the number of plurals supported by a given language. | |
StringTranslationTrait:: |
protected | function | Gets the string translation service. | |
StringTranslationTrait:: |
public | function | Sets the string translation service to use. | 2 |
StringTranslationTrait:: |
protected | function | Translates a string to the current language or to a given language. | |
UrlGeneratorTrait:: |
protected | property | The url generator. | |
UrlGeneratorTrait:: |
protected | function | Returns the URL generator service. | |
UrlGeneratorTrait:: |
public | function | Sets the URL generator service. | |
UrlGeneratorTrait:: |
protected | function | Generates a URL or path for a specific route based on the given parameters. |