cache_monitor-1.0.x-dev/src/Controller/ReportController.php
src/Controller/ReportController.php
<?php
namespace Drupal\cache_monitor\Controller;
use Drupal\Component\Utility\Html;
use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Link;
use Drupal\Core\Url;
use Drupal\cache_monitor\Storage\Storage;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
/**
* Controller for viewing cache request reports.
*/
final class ReportController extends ControllerBase {
/**
* The storage service.
*
* @var \Drupal\cache_monitor\Storage\Storage
*/
private Storage $storage;
/**
* Constructs a new ReportController instance.
*
* @param \Drupal\cache_monitor\Storage\Storage $storage
* The storage service.
*/
public function __construct(Storage $storage) {
$this->storage = $storage;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $c): self {
return new self($c->get('cache_monitor.storage'));
}
/**
* Lists recent cache requests in a table.
*/
public function list(): array {
$limit = 50;
$page = (int) \Drupal::request()->query->get('page', 0);
$offset = $page * $limit;
$rows = $this->storage->latest($limit, $offset);
$header = [
['data' => $this->t('RID')],
['data' => $this->t('Time')],
['data' => $this->t('Method')],
['data' => $this->t('URI')],
['data' => $this->t('User')],
['data' => $this->t('IP')],
['data' => $this->t('Detail')],
];
$build_rows = [];
foreach ($rows as $rid => $r) {
$build_rows[] = [
'data' => [
$rid,
\Drupal::service('date.formatter')->format((int) $r['created'], 'short'),
$r['method'],
['data' => ['#markup' => Html::escape($r['uri'])]],
(int) $r['uid'],
$r['ip'],
Link::fromTextAndUrl($this->t('View'), Url::fromRoute('cache_monitor.report_view', ['rid' => $rid]))->toString(),
Link::fromTextAndUrl($this->t('Delete'), Url::fromRoute('cache_monitor.report_delete', ['rid' => $rid]))->toString(),
],
];
}
$build['settings'] = [
'#type' => 'link',
'#title' => $this->t('Settings'),
'#url' => Url::fromRoute('cache_monitor.settings'),
'#attributes' => ['class' => ['button']],
'#weight' => -12,
];
$build['clear_all'] = [
'#type' => 'link',
'#title' => $this->t('Clear all reports'),
'#url' => Url::fromRoute('cache_monitor.clear_all'),
'#attributes' => ['class' => ['button', 'button--danger']],
'#weight' => -10,
];
$build['table'] = [
'#type' => 'table',
'#header' => $header,
'#rows' => $build_rows,
'#empty' => $this->t('No entries yet.'),
];
// Simple pager.
$build['pager'] = ['#type' => 'pager'];
return $build;
}
/**
* Page title callback for the report view page.
*/
public function title($rid): string {
return $this->t('Cache Request @rid', ['@rid' => $rid]);
}
/**
* Displays details for a specific cache request.
*
* @param int $rid
* The request ID.
*
* @return array
* A render array representing the report details.
*/
public function view($rid): array {
$req = $this->storage->request((int) $rid);
if (!$req) {
return ['#markup' => $this->t('Request not found.')];
}
$metrics = $this->storage->metrics((int) $rid);
$header = [
$this->t('Bin'),
$this->t('Backend'),
$this->t('Operation'),
$this->t('Calls'),
$this->t('Items'),
$this->t('Total ms'),
$this->t('Avg ms'),
$this->t('No activity'),
];
$rows = [];
$sumMs = 0.0;
foreach ($metrics as $m) {
$rows[] = [
$m['bin'],
$m['backend'],
$m['op'],
$m['calls'],
$m['items'],
number_format((float) $m['ms'], 3),
number_format((float) $m['ms_avg'], 3),
$m['no_activity'] ? $this->t('Yes') : '',
];
$sumMs += (float) $m['ms'];
}
// Attach total row.
$rows[] = [
['data' => $this->t('Total'), 'colspan' => 4],
$this->formatDurationMs($sumMs),
'', // kein avg
'',
];
return [
'meta' => [
'#type' => 'item',
'#title' => $this->t('Request'),
'#markup' => $this->t('@method @uri (User @uid, IP @ip, @date)', [
'@method' => $req['method'],
'@uri' => $req['uri'],
'@uid' => $req['uid'],
'@ip' => $req['ip'],
'@date' => \Drupal::service('date.formatter')->format((int) $req['created'], 'short'),
]),
],
'table' => [
'#type' => 'table',
'#header' => $header,
'#rows' => $rows,
],
'back' => [
'#type' => 'link',
'#title' => $this->t('Back to list'),
'#url' => Url::fromRoute('cache_monitor.report_list'),
],
];
}
/**
* Deletes a specific cache request report.
*
* @param int $rid
* The request ID.
*
* @return \Drupal\Core\Url|\Drupal\Core\Link
* A redirect response to the report list page.
*/
public function delete($rid) {
$report = $this->storage->request((int) $rid);
if (!$report) {
throw new NotFoundHttpException();
}
// Delete the report.
$this->storage->delete($rid);
// Display a message and redirect to the list page.
\Drupal::messenger()->addMessage($this->t('The cache report has been deleted.'));
return $this->redirect('cache_monitor.report_list');
}
public function clearAll() {
$this->storage->clearAll();
\Drupal::messenger()->addMessage($this->t('All cache reports have been deleted.'));
return $this->redirect('cache_monitor.report_list');
}
/**
* Formats a duration in milliseconds into a human-readable string.
*
* @param float $ms
* The duration in milliseconds.
*
* @return string
* The formatted duration string.
*/
private function formatDurationMs(float $ms): string {
if ($ms < 1000) {
return sprintf('%d ms', round($ms));
}
$sec = $ms / 1000;
if ($sec < 60) {
return sprintf('%.3f s', $sec);
}
$min = floor($sec / 60);
$sec = $sec - ($min * 60);
if ($min < 60) {
return sprintf('%dm %.1fs', $min, $sec);
}
$h = floor($min / 60);
$min = $min % 60;
return sprintf('%dh %dm %.0fs', $h, $min, $sec);
}
}
