templateService->getActiveTemplateIdentifier('user'); } catch (TemplateNotFoundException $e) { $activeTemplate = null; } // 프론트엔드 전역 변수로 사용할 설정 조회 try { $frontendSettings = $this->settingsService->getFrontendSettings(); } catch (\Exception $e) { $frontendSettings = []; } // 활성화된 플러그인 설정 조회 try { $pluginSettings = $this->pluginSettingsService->getAllActiveSettings(); } catch (\Exception $e) { $pluginSettings = []; } // 활성화된 모듈 설정 조회 (frontend_schema 기반 필터링 적용) try { $moduleSettings = $this->moduleSettingsService->getAllActiveSettings(); } catch (\Exception $e) { $moduleSettings = []; } // 활성화된 모듈의 프론트엔드 에셋 정보 수집 $moduleAssets = $this->collectModuleAssets(); // 활성화된 플러그인의 프론트엔드 에셋 정보 수집 $pluginAssets = $this->collectPluginAssets(); // 활성 확장(모듈/플러그인) 메타 — 레이아웃 편집기 SSoT // 기존 modules/plugins 키는 hasSettings() 필터로 활성 전수가 아님 $activeModulesMeta = $this->collectActiveModulesMeta(); $activePluginsMeta = $this->collectActivePluginsMeta(); // 프론트엔드에 노출할 앱 config 값 조회 try { $appConfig = $this->settingsService->getAppConfigForFrontend(); } catch (\Exception $e) { $appConfig = []; } // 템플릿의 외부 리소스 정보 수집 $templateExternals = $this->collectTemplateExternals($activeTemplate); // 확장 기능 캐시 버전 (브라우저 캐시 무효화용) $extensionCacheVersion = ClearsTemplateCaches::getExtensionCacheVersion(); $view->with('activeUserTemplate', $activeTemplate); $view->with('extensionCacheVersion', $extensionCacheVersion); $view->with('frontendSettings', $frontendSettings); $view->with('pluginSettings', $pluginSettings); $view->with('moduleSettings', $moduleSettings); $view->with('moduleAssets', $moduleAssets); $view->with('pluginAssets', $pluginAssets); $view->with('activeModulesMeta', $activeModulesMeta); $view->with('activePluginsMeta', $activePluginsMeta); $view->with('appConfig', $appConfig); $view->with('templateExternals', $templateExternals); } /** * 활성화된 모듈의 프론트엔드 에셋 정보를 수집합니다. * * @return array */ private function collectModuleAssets(): array { $assets = []; try { // ModuleManager에서 활성화된 모듈 목록 조회 $activeModules = $this->moduleManager->getActiveModules(); // 캐시 버전 조회 (브라우저 캐시 무효화용) $cacheVersion = ClearsTemplateCaches::getExtensionCacheVersion(); foreach ($activeModules as $identifier => $module) { // 모듈에 에셋이 있는지 확인 if (! $module->hasAssets()) { continue; } $builtPaths = $module->getBuiltAssetPaths(); $loadingConfig = $module->getAssetLoadingConfig(); $assetConfig = $module->getAssets(); // global 전략인 경우에만 수집 (layout, lazy는 레이아웃에서 처리) if ($loadingConfig['strategy'] !== 'global') { continue; } $moduleAsset = [ 'priority' => $loadingConfig['priority'], ]; // JS 빌드 경로 (캐시 버전 파라미터 추가) if (! empty($builtPaths['js'])) { $moduleAsset['js'] = "/api/modules/assets/{$identifier}/".$builtPaths['js']."?v={$cacheVersion}"; } // CSS 빌드 경로 (캐시 버전 파라미터 추가) if (! empty($builtPaths['css'])) { $moduleAsset['css'] = "/api/modules/assets/{$identifier}/".$builtPaths['css']."?v={$cacheVersion}"; } // 외부 스크립트 (조건부 로드용) if (! empty($assetConfig['external'])) { $moduleAsset['external'] = $assetConfig['external']; } $assets[$identifier] = $moduleAsset; } // 우선순위 기준 정렬 (낮을수록 먼저) uasort($assets, fn ($a, $b) => $a['priority'] <=> $b['priority']); } catch (\Exception $e) { // 에러 발생 시 빈 배열 반환 (에셋 로드 실패해도 앱 진행) Log::warning('Failed to collect module assets: '.$e->getMessage()); } return $assets; } /** * 활성화된 플러그인의 프론트엔드 에셋 정보를 수집합니다. * * @return array */ private function collectPluginAssets(): array { $assets = []; try { // PluginManager에서 활성화된 플러그인 목록 조회 $activePlugins = $this->pluginManager->getActivePlugins(); // 캐시 버전 조회 (브라우저 캐시 무효화용) $cacheVersion = ClearsTemplateCaches::getExtensionCacheVersion(); foreach ($activePlugins as $identifier => $plugin) { // 플러그인에 에셋이 있는지 확인 if (! $plugin->hasAssets()) { continue; } $builtPaths = $plugin->getBuiltAssetPaths(); $loadingConfig = $plugin->getAssetLoadingConfig(); $assetConfig = $plugin->getAssets(); // global 전략인 경우에만 수집 (layout, lazy는 레이아웃에서 처리) if ($loadingConfig['strategy'] !== 'global') { continue; } $pluginAsset = [ 'priority' => $loadingConfig['priority'], ]; // JS 빌드 경로 (캐시 버전 파라미터 추가) if (! empty($builtPaths['js'])) { $pluginAsset['js'] = "/api/plugins/assets/{$identifier}/".$builtPaths['js']."?v={$cacheVersion}"; } // CSS 빌드 경로 (캐시 버전 파라미터 추가) if (! empty($builtPaths['css'])) { $pluginAsset['css'] = "/api/plugins/assets/{$identifier}/".$builtPaths['css']."?v={$cacheVersion}"; } // 외부 스크립트 (조건부 로드용) if (! empty($assetConfig['external'])) { $pluginAsset['external'] = $assetConfig['external']; } $assets[$identifier] = $pluginAsset; } // 우선순위 기준 정렬 (낮을수록 먼저) uasort($assets, fn ($a, $b) => $a['priority'] <=> $b['priority']); } catch (\Exception $e) { // 에러 발생 시 빈 배열 반환 (에셋 로드 실패해도 앱 진행) Log::warning('Failed to collect plugin assets: '.$e->getMessage()); } return $assets; } }