diff --git a/application/Espo/Core/Utils/ClientManager.php b/application/Espo/Core/Utils/ClientManager.php index b05cd17b64..6d998ffe11 100644 --- a/application/Espo/Core/Utils/ClientManager.php +++ b/application/Espo/Core/Utils/ClientManager.php @@ -44,11 +44,12 @@ class ClientManager { protected string $mainHtmlFilePath = 'html/main.html'; protected string $runScript = "app.start();"; + private string $favicon = 'client/img/favicon.ico'; + private string $favicon196 = 'client/img/favicon196x196.png'; private string $basePath = ''; - private string $nonce; - private const APP_DESCRIPTION = "EspoCRM - Open Source CRM application."; + private const APP_DESCRIPTION = "EspoCRM – Open Source CRM application."; public function __construct( private Config $config, @@ -72,15 +73,6 @@ class ClientManager return $this->basePath; } - protected function getCacheTimestamp(): int - { - if (!$this->config->get('useCache')) { - return time(); - } - - return $this->config->get('cacheTimestamp', 0); - } - /** * @todo Move to a separate class. */ @@ -156,78 +148,42 @@ class ClientManager */ public function render(?string $runScript = null, ?string $htmlFilePath = null, array $vars = []): string { - if (is_null($runScript)) { - $runScript = $this->runScript; - } - - if (is_null($htmlFilePath)) { - $htmlFilePath = $this->mainHtmlFilePath; - } + $runScript ??= $this->runScript; + $htmlFilePath ??= $this->mainHtmlFilePath; $cacheTimestamp = $this->getCacheTimestamp(); $jsFileList = $this->getJsFileList(); + $appTimestamp = $this->getAppTimestamp(); - if ($this->config->get('isDeveloperMode')) { - $useCache = $this->config->get('useCacheInDeveloperMode'); + if ($this->isDeveloperMode()) { + $useCache = $this->useCacheInDeveloperMode(); $loaderCacheTimestamp = null; } else { - $useCache = $this->config->get('useCache'); - $loaderCacheTimestamp = $cacheTimestamp; + $useCache = $this->useCache(); + $loaderCacheTimestamp = $appTimestamp; } $cssFileList = $this->metadata->get(['app', 'client', 'cssList'], []); $linkList = $this->metadata->get(['app', 'client', 'linkList'], []); + $favicon196Path = $this->metadata->get(['app', 'client', 'favicon196']) ?? $this->favicon196; + $faviconPath = $this->metadata->get(['app', 'client', 'favicon']) ?? $this->favicon; $jsLibs = $this->metadata->get(['app', 'jsLibs'], []); - $scriptsHtml = ''; + $scriptsHtml = implode('', + array_map(fn ($file) => $this->getScriptItemHtml($file, $appTimestamp), $jsFileList) + ); - foreach ($jsFileList as $jsFile) { - $src = $this->basePath . $jsFile . '?r=' . $cacheTimestamp; + $additionalStyleSheetsHtml = implode('', + array_map(fn ($file) => $this->getCssItemHtml($file, $appTimestamp), $cssFileList) + ); - $scriptsHtml .= "\n " . - ""; - } - - $additionalStyleSheetsHtml = ''; - - foreach ($cssFileList as $cssFile) { - $src = $this->basePath . $cssFile . '?r=' . $cacheTimestamp; - - $additionalStyleSheetsHtml .= "\n "; - } - - $linksHtml = ''; - - foreach ($linkList as $item) { - $href = $this->basePath . $item['href']; - - if (empty($item['noTimestamp'])) { - $href .= '?r=' . $cacheTimestamp; - } - - $as = $item['as'] ?? ''; - $rel = $item['rel'] ?? ''; - $type = $item['type'] ?? ''; - $additionalPlaceholder = ''; - - if (!empty($item['crossorigin'])) { - $additionalPlaceholder .= ' crossorigin'; - } - - $linksHtml .= "\n " . - ""; - } - - $favicon196Path = $this->metadata->get(['app', 'client', 'favicon196']) ?? - 'client/img/favicon196x196.png'; - - $faviconPath = $this->metadata->get(['app', 'client', 'favicon']) ?? 'client/img/favicon.ico'; + $linksHtml = implode('', + array_map(fn ($item) => $this->getLinkItemHtml($item, $appTimestamp), $linkList) + ); $internalModuleList = array_map( - function (string $moduleName): string { - return Util::fromCamelCase($moduleName, '-'); - }, + fn ($moduleName) => Util::fromCamelCase($moduleName, '-'), $this->module->getInternalList() ); @@ -262,7 +218,7 @@ class ClientManager $html = $this->fileManager->getContents($htmlFilePath); foreach ($vars as $key => $value) { - $html = str_replace('{{'.$key.'}}', $value, $html); + $html = str_replace('{{' . $key . '}}', $value, $html); } foreach ($data as $key => $value) { @@ -270,7 +226,7 @@ class ClientManager continue; } - $html = str_replace('{{'.$key.'}}', $value, $html); + $html = str_replace('{{' . $key . '}}', $value, $html); } return $html; @@ -281,7 +237,7 @@ class ClientManager */ private function getJsFileList(): array { - if ($this->config->get('isDeveloperMode')) { + if ($this->isDeveloperMode()) { return array_merge( $this->getDeveloperModeBundleLibFileList(), $this->metadata->get(['app', 'client', 'developerModeScriptList']) ?? [], @@ -298,4 +254,88 @@ class ClientManager { return $this->devModeJsFileListProvider->get(); } + + private function isDeveloperMode(): bool + { + return $this->config->get('isDeveloperMode'); + } + + private function useCache(): bool + { + return $this->config->get('useCache'); + } + + private function useCacheInDeveloperMode(): bool + { + return $this->config->get('useCacheInDeveloperMode'); + } + + private function getCacheTimestamp(): int + { + if (!$this->useCache()) { + return time(); + } + + return $this->config->get('cacheTimestamp', 0); + } + + private function getAppTimestamp(): int + { + if (!$this->useCache()) { + return time(); + } + + return $this->config->get('appTimestamp', 0); + } + + private function getScriptItemHtml(string $file, int $appTimestamp): string + { + $src = $this->basePath . $file . '?r=' . $appTimestamp; + + return $this->getTabHtml() . + ""; + } + + private function getCssItemHtml(string $file, int $appTimestamp): string + { + $src = $this->basePath . $file . '?r=' . $appTimestamp; + + return $this->getTabHtml() . ""; + } + + /** + * @param array{ + * href: string, + * noTimestamp?: bool, + * as?: string, + * rel?: string, + * type?: string, + * crossorigin?: bool, + * } $item + */ + private function getLinkItemHtml(array $item, int $appTimestamp): string + { + $href = $this->basePath . $item['href']; + + if (empty($item['noTimestamp'])) { + $href .= '?r=' . $appTimestamp; + } + + $as = $item['as'] ?? ''; + $rel = $item['rel'] ?? ''; + $type = $item['type'] ?? ''; + $part = ''; + + if ($item['crossorigin'] ?? false) { + $part .= ' crossorigin'; + } + + return $this->getTabHtml() . + ""; + } + + private function getTabHtml(): string + { + return "\n "; + } }