perf : getAll() sans contenu, search_index + featured, excerpts via plain (v1.6.14)
- loadArticle($dir, false) dans loadAll() — meta.json seulement, pas d'index.md - loadAll() enrichit les articles avec plain depuis search_index (1 lecture JSON) - rebuildSearchIndex() lit index.md directement + ajoute featured au schéma - getSearchIndex() rebuilde automatiquement si featured absent - post_list, author_articles, author_profile : excerpts via plain, plus de Parsedown - Ferme #24 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+48
-22
@@ -44,7 +44,7 @@ class ArticleManager
|
||||
continue;
|
||||
}
|
||||
|
||||
$article = $this->loadArticle($dir);
|
||||
$article = $this->loadArticle($dir, false);
|
||||
if (!$article) {
|
||||
continue;
|
||||
}
|
||||
@@ -53,6 +53,19 @@ class ArticleManager
|
||||
|
||||
usort($articles, static fn ($a, $b) => strcmp($b['published_at'] ?? '', $a['published_at'] ?? ''));
|
||||
|
||||
// Enrichir avec le plain text pré-calculé (pour les excerpts sans charger index.md)
|
||||
$siPath = $this->dataDir . '/search_index.json';
|
||||
if (file_exists($siPath)) {
|
||||
$si = json_decode((string)file_get_contents($siPath), true);
|
||||
if (is_array($si)) {
|
||||
$plainByUuid = array_column($si, 'plain', 'uuid');
|
||||
foreach ($articles as &$a) {
|
||||
$a['plain'] = $plainByUuid[$a['uuid']] ?? '';
|
||||
}
|
||||
unset($a);
|
||||
}
|
||||
}
|
||||
|
||||
return $articles;
|
||||
}
|
||||
|
||||
@@ -944,19 +957,25 @@ class ArticleManager
|
||||
{
|
||||
$index = [];
|
||||
foreach ($this->getAll() as $article) {
|
||||
$uuid = $article['uuid'] ?? '';
|
||||
$contentPath = $this->dataDir . '/' . $uuid . '/index.md';
|
||||
$content = $uuid !== '' && file_exists($contentPath)
|
||||
? (string)file_get_contents($contentPath)
|
||||
: '';
|
||||
$index[] = [
|
||||
'uuid' => $article['uuid'],
|
||||
'uuid' => $uuid,
|
||||
'slug' => $article['slug'] ?? '',
|
||||
'title' => $article['title'] ?? '',
|
||||
'category' => $article['category'] ?? '',
|
||||
'author' => $article['author'] ?? '',
|
||||
'cover' => $article['cover'] ?? '',
|
||||
'featured' => (bool)($article['featured'] ?? false),
|
||||
'published' => $article['published'],
|
||||
'published_at' => $article['published_at'] ?? '',
|
||||
'created_at' => $article['created_at'] ?? '',
|
||||
'updated_at' => $article['updated_at'] ?? '',
|
||||
'tags' => $article['tags'] ?? [],
|
||||
'plain' => $this->stripForIndex($article['content'] ?? ''),
|
||||
'plain' => $this->stripForIndex($content),
|
||||
];
|
||||
}
|
||||
file_put_contents(
|
||||
@@ -1027,8 +1046,8 @@ class ArticleManager
|
||||
if (!is_array($data) || empty($data)) {
|
||||
return null;
|
||||
}
|
||||
// Rebuild automatique si le format est obsolète (champs cover/created_at absents)
|
||||
if (!array_key_exists('cover', $data[0])) {
|
||||
// Rebuild automatique si le format est obsolète (champs manquants)
|
||||
if (!array_key_exists('cover', $data[0]) || !array_key_exists('featured', $data[0])) {
|
||||
$this->rebuildSearchIndex();
|
||||
return $this->searchIndexCache;
|
||||
}
|
||||
@@ -1200,21 +1219,22 @@ class ArticleManager
|
||||
};
|
||||
}
|
||||
|
||||
private function loadArticle(string $dir): ?array
|
||||
private function loadArticle(string $dir, bool $withContent = true): ?array
|
||||
{
|
||||
$metaPath = $dir . '/meta.json';
|
||||
$metaPath = $dir . '/meta.json';
|
||||
if (!file_exists($metaPath)) {
|
||||
return null;
|
||||
}
|
||||
$uuid = basename($dir);
|
||||
$cachePath = $this->articleCachePath($uuid);
|
||||
|
||||
// Utiliser le cache si plus récent que meta.json ET index.md
|
||||
$contentMtime = file_exists($dir . '/index.md') ? filemtime($dir . '/index.md') : 0;
|
||||
if (file_exists($cachePath) && filemtime($cachePath) >= filemtime($metaPath) && filemtime($cachePath) >= $contentMtime) {
|
||||
$cached = json_decode((string) file_get_contents($cachePath), true);
|
||||
if (is_array($cached) && !empty($cached['uuid'])) {
|
||||
return $cached;
|
||||
if ($withContent) {
|
||||
$uuid = basename($dir);
|
||||
$cachePath = $this->articleCachePath($uuid);
|
||||
$contentMtime = file_exists($dir . '/index.md') ? filemtime($dir . '/index.md') : 0;
|
||||
if (file_exists($cachePath) && filemtime($cachePath) >= filemtime($metaPath) && filemtime($cachePath) >= $contentMtime) {
|
||||
$cached = json_decode((string) file_get_contents($cachePath), true);
|
||||
if (is_array($cached) && !empty($cached['uuid'])) {
|
||||
return $cached;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1227,8 +1247,11 @@ class ArticleManager
|
||||
return null;
|
||||
}
|
||||
|
||||
$contentPath = $dir . '/index.md';
|
||||
$meta['content'] = file_exists($contentPath) ? (string)file_get_contents($contentPath) : '';
|
||||
if ($withContent) {
|
||||
$contentPath = $dir . '/index.md';
|
||||
$meta['content'] = file_exists($contentPath) ? (string)file_get_contents($contentPath) : '';
|
||||
}
|
||||
|
||||
$meta['published'] = (bool)($meta['published'] ?? false);
|
||||
$meta['featured'] = (bool)($meta['featured'] ?? false);
|
||||
$meta['files_meta'] = $meta['files_meta'] ?? [];
|
||||
@@ -1242,12 +1265,15 @@ class ArticleManager
|
||||
}
|
||||
}
|
||||
|
||||
// Écrire le cache
|
||||
$cacheDir = dirname($cachePath);
|
||||
if (!is_dir($cacheDir)) {
|
||||
mkdir($cacheDir, 0755, true);
|
||||
if ($withContent) {
|
||||
$uuid = $meta['uuid'];
|
||||
$cachePath = $this->articleCachePath($uuid);
|
||||
$cacheDir = dirname($cachePath);
|
||||
if (!is_dir($cacheDir)) {
|
||||
mkdir($cacheDir, 0755, true);
|
||||
}
|
||||
file_put_contents($cachePath, json_encode($meta, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
|
||||
}
|
||||
file_put_contents($cachePath, json_encode($meta, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
|
||||
|
||||
return $meta;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user