folderweb/app/content.php
Ruben 32449d2edd Refactor template and content handling logic
Add constants for file extensions

Extract helper functions for common operations

Improve PDF file detection

Simplify directory scanning operations

Standardize template resolution

Optimize content rendering pipeline
2025-11-01 22:54:42 +01:00

211 lines
7.2 KiB
PHP

<?php
// Find all content files in a directory (supporting language variants)
function findAllContentFiles(string $dir, string $lang, string $defaultLang): array {
global $availableLangs;
if (!is_dir($dir)) return [];
$files = scandir($dir) ?: [];
$contentFiles = [];
foreach ($files as $file) {
if ($file === '.' || $file === '..' || $file === 'index.php') continue;
$ext = pathinfo($file, PATHINFO_EXTENSION);
if (!in_array($ext, CONTENT_EXTENSIONS)) continue;
$filePath = "$dir/$file";
if (!is_file($filePath)) continue;
// Parse filename to check for language variant
$parts = explode('.', $file);
// Check if this is a language-specific file
if (count($parts) >= 3) {
// Pattern: name.lang.ext
$fileLang = $parts[count($parts) - 2];
if (in_array($fileLang, $availableLangs)) {
// Only include if it matches current language
if ($fileLang === $lang) {
$contentFiles[] = [
'path' => $filePath,
'name' => $file,
'sort_key' => $parts[0]
];
}
continue;
}
}
// Default files (no language suffix) - include if no language-specific version exists
$baseName = $parts[0];
$hasLangVersion = false;
if ($lang !== $defaultLang) {
// Check if language-specific version exists
foreach (CONTENT_EXTENSIONS as $checkExt) {
if (file_exists("$dir/$baseName.$lang.$checkExt")) {
$hasLangVersion = true;
break;
}
}
}
if (!$hasLangVersion) {
$contentFiles[] = [
'path' => $filePath,
'name' => $file,
'sort_key' => $baseName
];
}
}
// Sort by filename (alphanumerical)
usort($contentFiles, fn($a, $b) => strnatcmp($a['sort_key'], $b['sort_key']));
return array_column($contentFiles, 'path');
}
function resolveTranslatedPath(string $requestPath, string $contentDir, string $lang, string $defaultLang): string {
// If default language, no translation needed
if ($lang === $defaultLang) {
return $requestPath;
}
$parts = explode('/', trim($requestPath, '/'));
$resolvedParts = [];
$currentPath = $contentDir;
foreach ($parts as $segment) {
if (empty($segment)) continue;
// Check all subdirectories for slug matches
$found = false;
if (is_dir($currentPath)) {
$subdirs = getSubdirectories($currentPath);
foreach ($subdirs as $dir) {
$metadata = loadMetadata("$currentPath/$dir", $lang, $defaultLang);
if ($metadata && isset($metadata['slug']) && $metadata['slug'] === $segment) {
$resolvedParts[] = $dir;
$currentPath .= "/$dir";
$found = true;
break;
}
}
}
// If no slug match, use segment as-is
if (!$found) {
$resolvedParts[] = $segment;
$currentPath .= "/$segment";
}
}
return implode('/', $resolvedParts);
}
function parseRequestPath(string $requestPath, string $contentDir, bool $hasTrailingSlash, string $lang, string $defaultLang): array {
// Resolve translated slugs to actual directory names
$resolvedPath = resolveTranslatedPath($requestPath, $contentDir, $lang, $defaultLang);
$contentPath = rtrim($contentDir, '/') . '/' . ltrim($resolvedPath, '/');
if (is_file($contentPath)) {
return ['type' => 'file', 'path' => realpath($contentPath)];
}
if (is_dir($contentPath)) {
// Check if directory has subdirectories
$hasSubdirs = !empty(getSubdirectories($contentPath));
// If directory has subdirectories, it's an article-type folder (list view)
if ($hasSubdirs) {
return ['type' => 'directory', 'path' => realpath($contentPath)];
}
// No subdirectories - it's a page-type folder
// Find all content files in this directory
$contentFiles = findAllContentFiles($contentPath, $lang, $defaultLang);
if (!empty($contentFiles)) {
return ['type' => 'page', 'path' => realpath($contentPath), 'files' => $contentFiles, 'needsSlash' => !$hasTrailingSlash];
}
// No content files found
return ['type' => 'directory', 'path' => realpath($contentPath)];
}
return ['type' => 'not_found', 'path' => $contentPath];
}
function loadMetadata(string $dirPath, string $lang, string $defaultLang): ?array {
$metadataFile = "$dirPath/metadata.ini";
if (!file_exists($metadataFile)) return null;
$metadata = parse_ini_file($metadataFile, true);
if (!$metadata) return null;
// Extract base metadata (non-section values)
$baseMetadata = array_filter($metadata, fn($key) => !is_array($metadata[$key]), ARRAY_FILTER_USE_KEY);
// If current language is not default, merge language-specific overrides
if ($lang !== $defaultLang && isset($metadata[$lang]) && is_array($metadata[$lang])) {
$baseMetadata = array_merge($baseMetadata, $metadata[$lang]);
}
return $baseMetadata ?: null;
}
function loadTranslations(string $lang): array {
$translationFile = dirname(__DIR__) . "/custom/languages/$lang.ini";
if (file_exists($translationFile)) {
return parse_ini_file($translationFile) ?: [];
}
return [];
}
function buildNavigation(string $contentDir, string $currentLang, string $defaultLang): array {
$navItems = [];
$items = getSubdirectories($contentDir);
foreach ($items as $item) {
$itemPath = "$contentDir/$item";
$metadata = loadMetadata($itemPath, $currentLang, $defaultLang);
// Check if this item should be in menu
if (!$metadata || empty($metadata['menu'])) {
continue;
}
// Check if content exists for current language
if ($currentLang !== $defaultLang) {
$contentFiles = findAllContentFiles($itemPath, $currentLang, $defaultLang);
// If no content files, check if metadata has title for this language
$hasContent = !empty($contentFiles) || ($metadata && isset($metadata['title']));
if (!$hasContent) continue;
}
// Extract title and build URL
$title = $metadata['title'] ?? extractTitle($itemPath, $currentLang, $defaultLang) ?? ucfirst($item);
$langPrefix = getLangPrefix($currentLang, $defaultLang);
// Use translated slug if available
$urlSlug = ($currentLang !== $defaultLang && $metadata && isset($metadata['slug']))
? $metadata['slug']
: $item;
$navItems[] = [
'title' => $title,
'url' => $langPrefix . '/' . urlencode($urlSlug) . '/',
'order' => (int)($metadata['menu_order'] ?? 999)
];
}
// Sort by menu_order
usort($navItems, fn($a, $b) => $a['order'] <=> $b['order']);
return $navItems;
}