| 1 |
<?php |
| 2 |
|
| 3 |
if (!defined('ABSPATH')) { |
| 4 |
exit; |
| 5 |
} |
| 6 |
|
| 7 |
/** |
| 8 |
* Decides whether the wp_abj404_logs_hits aggregate-rollup table needs a |
| 9 |
* rebuild before the admin redirect-list view renders a hits/last-used column. |
| 10 |
* |
| 11 |
* The decision short-circuits in four cases: |
| 12 |
* 1. Non-essential DB writes are in cooldown. |
| 13 |
* 2. Hits table is missing -- defer creation to the cron rebuild scheduler. |
| 14 |
* 3. logsRepo reports no rebuild needed. |
| 15 |
* 4. Otherwise, ask logsRepo to schedule the deferred rebuild. |
| 16 |
* |
| 17 |
* Extracted from ViewReadService (i858 / design-audit-2026-06-04 M201) so the |
| 18 |
* view-read facade keeps a single responsibility: serving the staged view-read |
| 19 |
* pipeline. This class owns the rebuild-or-skip lifecycle. |
| 20 |
*/ |
| 21 |
class ABJ_404_Solution_HitsTableRebuildPolicy { |
| 22 |
|
| 23 |
/** @var ABJ_404_Solution_DatabaseCore */ |
| 24 |
private $dbCore; |
| 25 |
|
| 26 |
/** @var ABJ_404_Solution_LogsRepository */ |
| 27 |
private $logsRepo; |
| 28 |
|
| 29 |
/** @var ABJ_404_Solution_Logging */ |
| 30 |
private $logger; |
| 31 |
|
| 32 |
/** |
| 33 |
* @param ABJ_404_Solution_DatabaseCore $dbCore |
| 34 |
* @param ABJ_404_Solution_LogsRepository $logsRepo |
| 35 |
* @param ABJ_404_Solution_Logging $logger |
| 36 |
*/ |
| 37 |
public function __construct( |
| 38 |
ABJ_404_Solution_DatabaseCore $dbCore, |
| 39 |
ABJ_404_Solution_LogsRepository $logsRepo, |
| 40 |
$logger |
| 41 |
) { |
| 42 |
$this->dbCore = $dbCore; |
| 43 |
$this->logsRepo = $logsRepo; |
| 44 |
$this->logger = $logger; |
| 45 |
} |
| 46 |
|
| 47 |
/** |
| 48 |
* Schedule a rebuild only if logsRepo reports the rollup is stale |
| 49 |
* relative to logsv2. |
| 50 |
* |
| 51 |
* @return void |
| 52 |
*/ |
| 53 |
public function maybeUpdateRedirectsForViewHitsTable(): void { |
| 54 |
if ($this->dbCore->noticeState()->shouldSkipNonEssentialDbWrites()) { |
| 55 |
$this->logger->debugMessage(__METHOD__ . ' skipped due to temporary DB write cooldown.'); |
| 56 |
return; |
| 57 |
} |
| 58 |
|
| 59 |
if (!$this->logsRepo->logsHitsTableExists()) { |
| 60 |
$this->logger->debugMessage(__METHOD__ . " table doesn't exist, deferring creation to WP-Cron."); |
| 61 |
$this->logsRepo->scheduleHitsTableRebuild(); |
| 62 |
return; |
| 63 |
} |
| 64 |
|
| 65 |
$this->logsRepo->recordLogsHitsRollupStalenessSignal(); |
| 66 |
|
| 67 |
if (!$this->logsRepo->hitsTableNeedsRebuild()) { |
| 68 |
return; |
| 69 |
} |
| 70 |
|
| 71 |
$this->logsRepo->scheduleHitsTableRebuild(); |
| 72 |
} |
| 73 |
} |
| 74 |
|