~ 50% reduction in the time to render a page (#49)

This commit is contained in:
Belle Aerni 2023-06-19 16:18:49 -07:00 committed by GitHub
parent d920b26f52
commit 8d9e894af8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 65 additions and 42 deletions

View file

@ -126,25 +126,27 @@ class AntCMS
*/
public static function getThemeTemplate(string $layout = 'default', string $theme = null)
{
$theme = $theme ?? AntConfig::currentConfig('activeTheme');
$theme ??= AntConfig::currentConfig('activeTheme');
if (!is_dir(antThemePath . '/' . $theme)) {
if (!is_dir(antThemePath . DIRECTORY_SEPARATOR . $theme)) {
$theme = 'Default';
}
$basePath = AntTools::repairFilePath(antThemePath . DIRECTORY_SEPARATOR . $theme);
if (strpos($layout, '_') !== false) {
$layoutPrefix = explode('_', $layout)[0];
$templatePath = AntTools::repairFilePath(antThemePath . '/' . $theme . '/' . 'Templates' . '/' . $layoutPrefix);
$templatePath = $basePath . DIRECTORY_SEPARATOR . 'Templates' . DIRECTORY_SEPARATOR . $layoutPrefix;
$defaultTemplates = AntTools::repairFilePath(antThemePath . '/Default/Templates' . '/' . $layoutPrefix);
} else {
$templatePath = AntTools::repairFilePath(antThemePath . '/' . $theme . '/' . 'Templates');
$templatePath = $basePath . DIRECTORY_SEPARATOR . 'Templates';
$defaultTemplates = AntTools::repairFilePath(antThemePath . '/Default/Templates');
}
try {
$template = @file_get_contents(AntTools::repairFilePath($templatePath . '/' . $layout . '.html.twig'));
$template = @file_get_contents($templatePath . DIRECTORY_SEPARATOR . $layout . '.html.twig');
if (empty($template)) {
$template = file_get_contents(AntTools::repairFilePath($defaultTemplates . '/' . $layout . '.html.twig'));
$template = file_get_contents($defaultTemplates . DIRECTORY_SEPARATOR . $layout . '.html.twig');
}
} catch (\Exception) {
}

View file

@ -17,10 +17,10 @@ class AntCache
/**
* Creates a new cache object, sets the correct caching type. ('auto', 'filesystem', 'apcu', or 'none')
*/
public function __construct()
public function __construct(null|string $mode = null)
{
$config = AntConfig::currentConfig();
$mode = $config['cacheMode'] ?? 'auto';
$mode = $mode ?? AntConfig::currentConfig('cacheMode') ?? 'auto';
switch ($mode) {
case 'none':
$this->cacheType = self::noCache;
@ -86,11 +86,9 @@ class AntCache
return file_get_contents($cachePath);
case self::apcuCache:
$apcuKey = $this->cacheKeyApcu . $key;
if (apcu_exists($apcuKey)) {
return apcu_fetch($apcuKey);
} else {
return false;
}
$success = false;
$result = apcu_fetch($apcuKey, $success);
return $success ? $result : false;
default:
return false;
}
@ -129,16 +127,20 @@ class AntCache
*/
public function createCacheKey(string $content, string $salt = 'cache')
{
/**
* If the server is modern enough to have xxh128, use that. It is really fast and still produces long hashes
* If not, use MD4 since it's still quite fast.
* Source: https://php.watch/articles/php-hash-benchmark
*/
if (defined('HAS_XXH128')) {
return hash('xxh128', $content . $salt);
} else {
return hash('md4', $content . $salt);
}
return hash(self::getHashAlgo(), $content . $salt);
}
/**
* Generates a unique cache key for a file and a salt value.
* The salt is used to ensure that each cache key is unique to each component, even if multiple components are using the same source content but caching different results.
*
* @param string $filePath The file path to create a cache key for.
* @param string $salt An optional salt value to use in the cache key generation. Default is 'cache'.
* @return string The generated cache key.
*/
public function createCacheKeyFile(string $filePath, string $salt = 'cache')
{
return hash_file(self::getHashAlgo(), $filePath) . $salt;
}
public static function clearCache(): void
@ -162,4 +164,14 @@ class AntCache
}
}
}
public static function getHashAlgo(): string
{
/**
* If the server is modern enough to have xxh128, use that. It is really fast and still produces long hashes
* If not, use MD4 since it's still quite fast.
* Source: https://php.watch/articles/php-hash-benchmark
*/
return defined('HAS_XXH128') ? 'xxh128' : 'md4';
}
}

View file

@ -48,7 +48,8 @@ class AntConfig
*/
public static function currentConfig(?string $key = null)
{
$config = AntYaml::parseFile(antConfigFile);
// FS cache enabled to save ~10% of the time to deliver the file page.
$config = AntYaml::parseFile(antConfigFile, true);
if (is_null($key)) {
return $config;
} else {
@ -57,7 +58,6 @@ class AntConfig
}
}
/**
* @param array<mixed> $array
* @param array<mixed> $keys
@ -67,13 +67,11 @@ class AntConfig
{
foreach ($keys as $key) {
if (isset($array[$key])) {
$array = $array[$key];
return $array[$key];
} else {
return null;
}
}
return $array;
}
/**

View file

@ -52,21 +52,18 @@ class AntPages
AntYaml::saveFile(antPagesList, $pageList);
}
/** @return array<mixed> */
public static function getPages()
public static function getPages():array
{
return AntYaml::parseFile(antPagesList);
}
/**
* @param string $currentPage optional - What page is the active page. Used for highlighting the active page in the navbar
* @return string
*/
public static function generateNavigation(string $navTemplate = '', string $currentPage = '')
public static function generateNavigation(string $navTemplate = '', string $currentPage = ''): string
{
$pages = AntPages::getPages();
$antCache = new AntCache;
$antTwig = new AntTwig();
$theme = AntConfig::currentConfig('activeTheme');
$cacheKey = $antCache->createCacheKey(json_encode($pages), $theme . $currentPage);
@ -74,7 +71,7 @@ class AntPages
if ($antCache->isCached($cacheKey)) {
$cachedContent = $antCache->getCache($cacheKey);
if ($cachedContent !== false && !empty($cachedContent)) {
if (!empty($cachedContent)) {
return $cachedContent;
}
}
@ -91,6 +88,7 @@ class AntPages
}
}
$antTwig = new AntTwig();
$navHTML = $antTwig->renderWithTiwg($navTemplate, array('pages' => $pages));
$antCache->setCache($cacheKey, $navHTML);

View file

@ -14,7 +14,7 @@ class AntTwig
$twigCache = (AntConfig::currentConfig('enableCache') !== 'none') ? AntCachePath : false;
$this->theme = $theme ?? AntConfig::currentConfig('activeTheme');
if (!is_dir(antThemePath . '/' . $this->theme)) {
if (!is_dir(antThemePath . DIRECTORY_SEPARATOR . $this->theme)) {
$this->theme = 'Default';
}

View file

@ -7,12 +7,25 @@ use Symfony\Component\Yaml\Yaml;
class AntYaml
{
/**
* @return array<mixed>
*/
public static function parseFile(string $file)
public static function parseFile(string $file, bool $fileCache = false): array
{
return Yaml::parseFile($file);
if ($fileCache) {
$antCache = new AntCache('filesystem');
} else {
$antCache = new AntCache();
}
$cacheKey = $antCache->createCacheKeyFile($file);
if ($antCache->isCached($cacheKey)) {
$parsed = json_decode($antCache->getCache($cacheKey), true);
}
if (empty($parsed)) {
$parsed = Yaml::parseFile($file);
$antCache->setCache($cacheKey, json_encode($parsed));
}
return $parsed;
}
/**
@ -27,7 +40,7 @@ class AntYaml
/**
* @return array<mixed>|null
*/
public static function parseYaml(string $yaml)
public static function parseYaml(string $yaml): ?array
{
try {
return Yaml::parse($yaml);