errorClassifier(); $ch = $collationHelper !== null ? $collationHelper : $dbCore->collationHelper(); $ns = $noticeState !== null ? $noticeState : $dbCore->noticeState(); if ($rollup instanceof ABJ_404_Solution_LogsHitsRollupServiceInterface) { $this->rollup = $rollup; } else { $this->rollup = new ABJ_404_Solution_LogsHitsRollupService($dbCore, $logger, $rebuildHealth); } $this->lookups = new ABJ_404_Solution_LogsLookupRepository($dbCore); $this->privacy = new ABJ_404_Solution_LogsPrivacyService($dbCore); $this->reads = new ABJ_404_Solution_LogsReadQueries($dbCore, $f, $logger); $this->hitsPopulator = new ABJ_404_Solution_LogsHitsDataPopulator($dbCore); $this->writer = new ABJ_404_Solution_LogsWriter($dbCore, $f, $logger, $ec, $ch, $ns, $this->lookups); } /** * Accessor for callers that need to drive the rollup directly (e.g. tests * inspecting scheduling state). Not part of the LogsRepository interface. * * @return ABJ_404_Solution_LogsHitsRollupServiceInterface */ public function getRollupService(): ABJ_404_Solution_LogsHitsRollupServiceInterface { return $this->rollup; } // ========================================================================= // Log read queries (delegated to LogsReadQueries + LogsHitsDataPopulator) // ========================================================================= /** @inheritDoc */ function populateLogsData($rows) { return $this->hitsPopulator->populate($rows, $this); } /** @inheritDoc */ function getDistinctLoggedUrls( int $recentLogWindow = self::DEFAULT_DISTINCT_RECENT_LOG_WINDOW, int $distinctUrlCap = self::DEFAULT_DISTINCT_URL_CAP ): array { return $this->reads->getDistinctLoggedUrls($recentLogWindow, $distinctUrlCap); } /** @inheritDoc */ function getLogsIDandURL($specificURL = '') { return $this->reads->getLogsIDandURL($specificURL); } /** @inheritDoc */ function getLogsIDandURLLike($specificURL, $limitResults) { return $this->reads->getLogsIDandURLLike($specificURL, $limitResults); } /** @inheritDoc */ function getLogRecords($tableOptions) { return $this->reads->getLogRecords($tableOptions); } /** @inheritDoc */ public function getDailyActivityTrend(int $days = 30): array { return $this->reads->getDailyActivityTrend($days, $this); } // ========================================================================= // GDPR (delegated to LogsPrivacyService) // ========================================================================= /** @inheritDoc */ public function getLogsv2IdsForLookupValue($lkupValue, $page = 1, $perPage = 100) { return $this->privacy->getLogsv2IdsForLookupValue($lkupValue, $page, $perPage); } /** @inheritDoc */ public function getLogsv2RowsForLookupValue($lkupValue, $page = 1, $perPage = 50) { return $this->privacy->getLogsv2RowsForLookupValue($lkupValue, $page, $perPage); } /** @inheritDoc */ public function anonymizeLogsv2RowsByIds($ids) { return $this->privacy->anonymizeLogsv2RowsByIds($ids); } // ========================================================================= // Log writes (delegated to LogsWriter) // ========================================================================= /** @inheritDoc */ function logRedirectHit(ABJ_404_Solution_RedirectHitLogEntry $entry): void { $this->writer->logRedirectHit($entry); } /** @inheritDoc */ function queueLogEntry(array $entry): void { $this->writer->queueLogEntry($entry); } /** @inheritDoc */ function flushLogQueue(): void { $this->writer->flushLogQueue(); } /** * Backwards-compatible accessor (not on the interface). Forwarded to the * writer; DataAccess re-exports it as a pass-through for legacy callers. */ public function isTableFullError(string $error): bool { return $this->writer->isTableFullError($error); } /** * Backwards-compatible accessor (not on the interface). Forwarded to the * writer. */ public function autoTrimLogsv2IfNeeded(string $tableName, string $errorMessage): bool { return $this->writer->autoTrimLogsv2IfNeeded($tableName, $errorMessage); } /** * Backwards-compatible accessor (not on the interface). Forwarded to the * writer. * * @param array $entry * @return array|null */ public function sanitizeLogEntry(array $entry): ?array { return $this->writer->sanitizeLogEntry($entry); } // ========================================================================= // Lookup table (delegated to LogsLookupRepository) // ========================================================================= /** @inheritDoc */ function insertLookupValueAndGetID($valueToInsert) { return $this->lookups->insertLookupValueAndGetID($valueToInsert); } /** @inheritDoc */ function getLookupIDForUser($userName) { return $this->lookups->getLookupIDForUser($userName); } /** @inheritDoc */ public function correctDuplicateLookupValues(): void { $this->lookups->correctDuplicateLookupValues(); } // ========================================================================= // Pipeline trace decode (static; the codec stays on the facade so existing // ABJ_404_Solution_LogsRepository::decompressPipelineTrace() call sites // in View_Logs and DataAccess keep working without rewiring). // ========================================================================= /** @inheritDoc */ public static function decompressPipelineTrace(?string $raw): ?array { if ($raw === null || $raw === '') { return null; } $decoded = base64_decode($raw, true); if ($decoded === false) { return null; } $json = @gzuncompress($decoded); if ($json === false) { return null; } $result = json_decode($json, true); return is_array($result) ? $result : null; } // ========================================================================= // Hits-table rollup: thin forwarders to ABJ_404_Solution_LogsHitsRollupService // ========================================================================= /** @inheritDoc */ function recordLogsHitsRollupStalenessSignal(): void { $this->rollup->recordLogsHitsRollupStalenessSignal(); } /** @inheritDoc */ function hitsTableNeedsRebuild() { return $this->rollup->hitsTableNeedsRebuild(); } /** @inheritDoc */ function getLogsHitsTableLastUpdated() { return $this->rollup->getLogsHitsTableLastUpdated(); } /** @inheritDoc */ function createRedirectsForViewHitsTable(): bool { return $this->rollup->createRedirectsForViewHitsTable(); } /** @inheritDoc */ function logsHitsTableExists() { return $this->rollup->logsHitsTableExists(); } /** @inheritDoc */ function scheduleHitsTableRebuild(): void { $this->rollup->scheduleHitsTableRebuild(); } /** @inheritDoc */ function getMaxLogId() { return $this->rollup->getMaxLogId(); } /** @inheritDoc */ function getMinLogId() { return $this->rollup->getMinLogId(); } /** @inheritDoc */ function getStoredMaxLogId() { return $this->rollup->getStoredMaxLogId(); } /** @inheritDoc */ function getLogsHitsTableLastScheduledAt() { return $this->rollup->getLogsHitsTableLastScheduledAt(); } /** * Backwards-compatible accessor used by some integration tests that need * the rollup-internal collation resolution. Delegates to the rollup * service. Not part of LogsRepositoryInterface. * * @return string */ public function resolveHitsJoinCollation(): string { if (method_exists($this->rollup, 'resolveHitsJoinCollation')) { return $this->rollup->resolveHitsJoinCollation(); } return ''; } }