~ 50% reduction in the time to render a page (#49)
This commit is contained in:
parent
d920b26f52
commit
8d9e894af8
6 changed files with 65 additions and 42 deletions
|
@ -126,25 +126,27 @@ class AntCMS
|
||||||
*/
|
*/
|
||||||
public static function getThemeTemplate(string $layout = 'default', string $theme = null)
|
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';
|
$theme = 'Default';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$basePath = AntTools::repairFilePath(antThemePath . DIRECTORY_SEPARATOR . $theme);
|
||||||
|
|
||||||
if (strpos($layout, '_') !== false) {
|
if (strpos($layout, '_') !== false) {
|
||||||
$layoutPrefix = explode('_', $layout)[0];
|
$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);
|
$defaultTemplates = AntTools::repairFilePath(antThemePath . '/Default/Templates' . '/' . $layoutPrefix);
|
||||||
} else {
|
} else {
|
||||||
$templatePath = AntTools::repairFilePath(antThemePath . '/' . $theme . '/' . 'Templates');
|
$templatePath = $basePath . DIRECTORY_SEPARATOR . 'Templates';
|
||||||
$defaultTemplates = AntTools::repairFilePath(antThemePath . '/Default/Templates');
|
$defaultTemplates = AntTools::repairFilePath(antThemePath . '/Default/Templates');
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$template = @file_get_contents(AntTools::repairFilePath($templatePath . '/' . $layout . '.html.twig'));
|
$template = @file_get_contents($templatePath . DIRECTORY_SEPARATOR . $layout . '.html.twig');
|
||||||
if (empty($template)) {
|
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) {
|
} catch (\Exception) {
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,10 +17,10 @@ class AntCache
|
||||||
/**
|
/**
|
||||||
* Creates a new cache object, sets the correct caching type. ('auto', 'filesystem', 'apcu', or 'none')
|
* 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 = $mode ?? AntConfig::currentConfig('cacheMode') ?? 'auto';
|
||||||
$mode = $config['cacheMode'] ?? 'auto';
|
|
||||||
switch ($mode) {
|
switch ($mode) {
|
||||||
case 'none':
|
case 'none':
|
||||||
$this->cacheType = self::noCache;
|
$this->cacheType = self::noCache;
|
||||||
|
@ -86,11 +86,9 @@ class AntCache
|
||||||
return file_get_contents($cachePath);
|
return file_get_contents($cachePath);
|
||||||
case self::apcuCache:
|
case self::apcuCache:
|
||||||
$apcuKey = $this->cacheKeyApcu . $key;
|
$apcuKey = $this->cacheKeyApcu . $key;
|
||||||
if (apcu_exists($apcuKey)) {
|
$success = false;
|
||||||
return apcu_fetch($apcuKey);
|
$result = apcu_fetch($apcuKey, $success);
|
||||||
} else {
|
return $success ? $result : false;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -129,16 +127,20 @@ class AntCache
|
||||||
*/
|
*/
|
||||||
public function createCacheKey(string $content, string $salt = 'cache')
|
public function createCacheKey(string $content, string $salt = 'cache')
|
||||||
{
|
{
|
||||||
/**
|
return hash(self::getHashAlgo(), $content . $salt);
|
||||||
* 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
|
/**
|
||||||
*/
|
* Generates a unique cache key for a file and a salt value.
|
||||||
if (defined('HAS_XXH128')) {
|
* 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.
|
||||||
return hash('xxh128', $content . $salt);
|
*
|
||||||
} else {
|
* @param string $filePath The file path to create a cache key for.
|
||||||
return hash('md4', $content . $salt);
|
* @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
|
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';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,7 +48,8 @@ class AntConfig
|
||||||
*/
|
*/
|
||||||
public static function currentConfig(?string $key = null)
|
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)) {
|
if (is_null($key)) {
|
||||||
return $config;
|
return $config;
|
||||||
} else {
|
} else {
|
||||||
|
@ -57,7 +58,6 @@ class AntConfig
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param array<mixed> $array
|
* @param array<mixed> $array
|
||||||
* @param array<mixed> $keys
|
* @param array<mixed> $keys
|
||||||
|
@ -67,13 +67,11 @@ class AntConfig
|
||||||
{
|
{
|
||||||
foreach ($keys as $key) {
|
foreach ($keys as $key) {
|
||||||
if (isset($array[$key])) {
|
if (isset($array[$key])) {
|
||||||
$array = $array[$key];
|
return $array[$key];
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $array;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -52,21 +52,18 @@ class AntPages
|
||||||
AntYaml::saveFile(antPagesList, $pageList);
|
AntYaml::saveFile(antPagesList, $pageList);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return array<mixed> */
|
public static function getPages():array
|
||||||
public static function getPages()
|
|
||||||
{
|
{
|
||||||
return AntYaml::parseFile(antPagesList);
|
return AntYaml::parseFile(antPagesList);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $currentPage optional - What page is the active page. Used for highlighting the active page in the navbar
|
* @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();
|
$pages = AntPages::getPages();
|
||||||
$antCache = new AntCache;
|
$antCache = new AntCache;
|
||||||
$antTwig = new AntTwig();
|
|
||||||
|
|
||||||
$theme = AntConfig::currentConfig('activeTheme');
|
$theme = AntConfig::currentConfig('activeTheme');
|
||||||
$cacheKey = $antCache->createCacheKey(json_encode($pages), $theme . $currentPage);
|
$cacheKey = $antCache->createCacheKey(json_encode($pages), $theme . $currentPage);
|
||||||
|
@ -74,7 +71,7 @@ class AntPages
|
||||||
if ($antCache->isCached($cacheKey)) {
|
if ($antCache->isCached($cacheKey)) {
|
||||||
$cachedContent = $antCache->getCache($cacheKey);
|
$cachedContent = $antCache->getCache($cacheKey);
|
||||||
|
|
||||||
if ($cachedContent !== false && !empty($cachedContent)) {
|
if (!empty($cachedContent)) {
|
||||||
return $cachedContent;
|
return $cachedContent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -91,6 +88,7 @@ class AntPages
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$antTwig = new AntTwig();
|
||||||
$navHTML = $antTwig->renderWithTiwg($navTemplate, array('pages' => $pages));
|
$navHTML = $antTwig->renderWithTiwg($navTemplate, array('pages' => $pages));
|
||||||
|
|
||||||
$antCache->setCache($cacheKey, $navHTML);
|
$antCache->setCache($cacheKey, $navHTML);
|
||||||
|
|
|
@ -14,7 +14,7 @@ class AntTwig
|
||||||
$twigCache = (AntConfig::currentConfig('enableCache') !== 'none') ? AntCachePath : false;
|
$twigCache = (AntConfig::currentConfig('enableCache') !== 'none') ? AntCachePath : false;
|
||||||
$this->theme = $theme ?? AntConfig::currentConfig('activeTheme');
|
$this->theme = $theme ?? AntConfig::currentConfig('activeTheme');
|
||||||
|
|
||||||
if (!is_dir(antThemePath . '/' . $this->theme)) {
|
if (!is_dir(antThemePath . DIRECTORY_SEPARATOR . $this->theme)) {
|
||||||
$this->theme = 'Default';
|
$this->theme = 'Default';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,12 +7,25 @@ use Symfony\Component\Yaml\Yaml;
|
||||||
|
|
||||||
class AntYaml
|
class AntYaml
|
||||||
{
|
{
|
||||||
/**
|
public static function parseFile(string $file, bool $fileCache = false): array
|
||||||
* @return array<mixed>
|
|
||||||
*/
|
|
||||||
public static function parseFile(string $file)
|
|
||||||
{
|
{
|
||||||
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
|
* @return array<mixed>|null
|
||||||
*/
|
*/
|
||||||
public static function parseYaml(string $yaml)
|
public static function parseYaml(string $yaml): ?array
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
return Yaml::parse($yaml);
|
return Yaml::parse($yaml);
|
||||||
|
|
Loading…
Reference in a new issue