From 668a50e714393f1c72122c6e5333a60f031d88dd Mon Sep 17 00:00:00 2001 From: Cedric Abonnel Date: Tue, 12 May 2026 23:25:31 +0200 Subject: [PATCH] =?UTF-8?q?perf:=20cache=20fichier=20pour=20les=20r=C3=A9t?= =?UTF-8?q?roliens,=20invalid=C3=A9=20sur=20create/update/delete/link?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/ArticleManager.php | 92 +++++++++++++++++++++++++++++++++--------- 1 file changed, 73 insertions(+), 19 deletions(-) diff --git a/src/ArticleManager.php b/src/ArticleManager.php index 096cbfe..faf316b 100644 --- a/src/ArticleManager.php +++ b/src/ArticleManager.php @@ -117,6 +117,7 @@ class ArticleManager $this->writeMeta($dir, $meta); file_put_contents($dir . '/index.md', ltrim($content)); $this->rebuildSearchIndex(); + $this->rebuildBacklinksCache(); return $uuid; } @@ -181,6 +182,7 @@ class ArticleManager $this->writeMeta($dir, $meta); file_put_contents($dir . '/index.md', ltrim($content)); $this->rebuildSearchIndex(); + $this->rebuildBacklinksCache(); } public function autosave(string $uuid, string $title, string $content, string $slug): bool @@ -414,6 +416,7 @@ class ArticleManager } $meta['external_links'][] = $entry; $this->writeMeta($dir, $meta); + $this->rebuildBacklinksCache(); return true; } @@ -466,6 +469,7 @@ class ArticleManager static fn ($l) => $l['url'] !== $url )); $this->writeMeta($dir, $meta); + $this->rebuildBacklinksCache(); return true; } @@ -547,6 +551,75 @@ class ArticleManager $this->removeDir($dir); } $this->rebuildSearchIndex(); + $this->rebuildBacklinksCache(); + } + + // ------------------------------------------------------------------ // + // Cache des rétroliens + // ------------------------------------------------------------------ // + + private function backlinksPath(): string + { + return $this->dataDir . '/_cache/backlinks.json'; + } + + /** + * Reconstruit le cache des rétroliens. + * Produit un index slug → [article minimal, ...] pour tous les articles publiés + * qui pointent vers un autre article interne via leurs external_links. + */ + public function rebuildBacklinksCache(): void + { + $cacheDir = $this->dataDir . '/_cache'; + if (!is_dir($cacheDir)) { + mkdir($cacheDir, 0755, true); + } + + $index = []; + foreach ($this->getAll(publishedOnly: true) as $article) { + foreach ($article['external_links'] ?? [] as $link) { + $path = rtrim(parse_url($link['url'] ?? '', PHP_URL_PATH) ?? '', '/'); + if (!preg_match('#^/post/([a-z0-9][a-z0-9-]*)$#', $path, $m)) { + continue; + } + $target = $m[1]; + $index[$target][] = [ + 'uuid' => $article['uuid'], + 'slug' => $article['slug'] ?? '', + 'title' => $article['title'] ?? '', + 'cover' => $article['cover'] ?? '', + 'category' => $article['category'] ?? '', + 'published_at' => $article['published_at'] ?? '', + 'created_at' => $article['created_at'] ?? '', + ]; + } + } + + file_put_contents( + $this->backlinksPath(), + json_encode($index, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) + ); + } + + /** + * Retourne les articles qui pointent vers /post/, depuis le cache. + * Reconstruit le cache si absent. + */ + public function getBacklinks(string $slug, string $excludeUuid = ''): array + { + $path = $this->backlinksPath(); + if (!file_exists($path)) { + $this->rebuildBacklinksCache(); + } + $index = json_decode((string) file_get_contents($path), true); + if (!is_array($index)) { + return []; + } + $result = $index[$slug] ?? []; + if ($excludeUuid !== '') { + $result = array_values(array_filter($result, static fn ($a) => $a['uuid'] !== $excludeUuid)); + } + return $result; } // ------------------------------------------------------------------ // @@ -887,25 +960,6 @@ class ArticleManager /** * Retourne les articles publiés qui contiennent un lien vers /post/. */ - public function getBacklinks(string $slug, string $excludeUuid = ''): array - { - $pattern = '/post/' . $slug; - $result = []; - foreach ($this->getAll(publishedOnly: true) as $article) { - if ($excludeUuid !== '' && $article['uuid'] === $excludeUuid) { - continue; - } - foreach ($article['external_links'] ?? [] as $link) { - $path = parse_url($link['url'] ?? '', PHP_URL_PATH) ?? ''; - if ($path === $pattern || rtrim($path, '/') === $pattern) { - $result[] = $article; - break; - } - } - } - return $result; - } - private function removeDir(string $dir): void { foreach (scandir($dir) as $entry) {