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 ";
+ }
}