cache_monitor-1.0.x-dev/src/Storage/Storage.php
src/Storage/Storage.php
<?php
namespace Drupal\cache_monitor\Storage;
use Drupal\Core\Database\Connection;
final class Storage {
/**
* @var \Drupal\Core\Database\Connection
*/
private Connection $db;
/**
* Constructs a new Storage instance.
*
* @param \Drupal\Core\Database\Connection $db
* The database connection.
*/
public function __construct(Connection $db) {
$this->db = $db;
}
/**
* Saves a cache request and its associated metrics.
*
* @param array $req
* The request info: method, uri, uid, ip, context.
* @param array $rows
* The measured metrics: bin, op, calls, items, ms.
* @param array $allBins
* All known cache bins (to ensure we write a row for each).
*
* @return int
* The RID of the saved request.
*/
public function save(array $req, array $rows, array $allBins): int {
$rid = (int) $this->db->insert('cache_monitor_request')
->fields([
'created' => \Drupal::time()->getRequestTime(),
'method' => $req['method'],
'uri' => $req['uri'],
'uid' => $req['uid'],
'ip' => $req['ip'],
'context' => $req['context'] ?? NULL,
])->execute();
// Group measured by bin/op
$by = [];
foreach ($rows as $r) {
$by[$r['bin']][$r['op']] = $r;
}
// Ensure we write a row for every known bin (marking no_activity if none).
foreach ($allBins as $bin) {
if (!isset($by[$bin])) {
$this->db->insert('cache_monitor_metric')
->fields([
'rid' => $rid,
'bin' => $bin,
'backend' => '',
'op' => 'n/a',
'calls' => 0,
'items' => 0,
'ms' => 0,
'ms_avg' => 0,
'no_activity' => 1,
])->execute();
continue;
}
foreach ($by[$bin] as $op => $r) {
$avg = $r['calls'] ? $r['ms'] / $r['calls'] : 0;
$this->db->insert('cache_monitor_metric')
->fields([
'rid' => $rid,
'bin' => $bin,
'backend' => $r['backend'] ?? '',
'op' => $op,
'calls' => (int) $r['calls'],
'items' => (int) $r['items'],
'ms' => round($r['ms'], 3),
'ms_avg' => round($avg, 3),
'no_activity' => 0,
])->execute();
}
}
return $rid;
}
/**
* Retrieves the latest cache requests.
*
* @param int $limit
* The maximum number of requests to retrieve. Default is 50.
* @param int $offset
* The number of requests to skip. Default is 0.
*
* @return array<int,array{rid:int,created:int,method:string,uri:string,uid:int,ip:string,context:string|null}>
* An array of request records keyed by RID.
*/
public function latest(int $limit = 50, int $offset = 0): array {
$q = $this->db->select('cache_monitor_request', 'r')
->fields('r')
->orderBy('rid', 'DESC')
->range($offset, $limit);
return $q->execute()->fetchAllAssoc('rid', \PDO::FETCH_ASSOC) ?: [];
}
/**
* Retrieves a specific cache request by its RID.
*
* @param int $rid
* The request ID.
*
* @return array{rid:int,created:int,method:string,uri:string,uid:int,ip:string,context:string|null}|null
* The request record as an associative array, or NULL if not found.
*/
public function request(int $rid): ?array {
$row = $this->db->select('cache_monitor_request', 'r')->fields('r')
->condition('rid', $rid)->execute()->fetchAssoc();
return $row ?: NULL;
}
/**
* Retrieves all metrics associated with a specific request ID.
*
* @param int $rid
* The request ID.
*
* @return array<int,array{bin:string,op:string,calls:int,items:int,ms:string,ms_avg:string,no_activity:int}>
* An array of metric records associated with the request.
*/
public function metrics(int $rid): array {
$q = $this->db->select('cache_monitor_metric', 'm')->fields('m')
->condition('rid', $rid)->orderBy('bin')->orderBy('op');
return $q->execute()->fetchAll(\PDO::FETCH_ASSOC) ?: [];
}
/**
* Deletes a specific cache request and its associated metrics.
*
* @param int $rid
* The request ID to delete.
*/
public function delete(int $rid): void {
$this->db->delete('cache_monitor_metric')->condition('rid', $rid)->execute();
$this->db->delete('cache_monitor_request')->condition('rid', $rid)->execute();
}
/**
* Removes all stored reports (request + metric rows).
*/
public function clearAll(): void {
$this->db->truncate('cache_monitor_metric')->execute();
$this->db->truncate('cache_monitor_request')->execute();
}
}
