ThemeInjectionService.php 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. <?php
  2. /**
  3. * SPDX-FileCopyrightText: 2022 Nextcloud GmbH and Nextcloud contributors
  4. * SPDX-License-Identifier: AGPL-3.0-or-later
  5. */
  6. namespace OCA\Theming\Service;
  7. use OCA\Theming\ITheme;
  8. use OCA\Theming\Themes\DefaultTheme;
  9. use OCA\Theming\Util;
  10. use OCP\IConfig;
  11. use OCP\IURLGenerator;
  12. use OCP\IUserSession;
  13. class ThemeInjectionService {
  14. private IURLGenerator $urlGenerator;
  15. private ThemesService $themesService;
  16. private DefaultTheme $defaultTheme;
  17. private Util $util;
  18. private IConfig $config;
  19. private ?string $userId;
  20. public function __construct(IURLGenerator $urlGenerator,
  21. ThemesService $themesService,
  22. DefaultTheme $defaultTheme,
  23. Util $util,
  24. IConfig $config,
  25. IUserSession $userSession) {
  26. $this->urlGenerator = $urlGenerator;
  27. $this->themesService = $themesService;
  28. $this->defaultTheme = $defaultTheme;
  29. $this->util = $util;
  30. $this->config = $config;
  31. if ($userSession->getUser() !== null) {
  32. $this->userId = $userSession->getUser()->getUID();
  33. } else {
  34. $this->userId = null;
  35. }
  36. }
  37. public function injectHeaders(): void {
  38. $themes = $this->themesService->getThemes();
  39. $defaultTheme = $themes[$this->defaultTheme->getId()];
  40. $mediaThemes = array_filter($themes, function ($theme) {
  41. // Check if the theme provides a media query
  42. return (bool)$theme->getMediaQuery();
  43. });
  44. // Default theme fallback
  45. $this->addThemeHeaders($defaultTheme);
  46. // Themes applied by media queries
  47. foreach($mediaThemes as $theme) {
  48. $this->addThemeHeaders($theme, true, $theme->getMediaQuery());
  49. }
  50. // Themes
  51. foreach($this->themesService->getThemes() as $theme) {
  52. // Ignore default theme as already processed first
  53. if ($theme->getId() === $this->defaultTheme->getId()) {
  54. continue;
  55. }
  56. $this->addThemeHeaders($theme, false);
  57. }
  58. // Meta headers
  59. $this->addThemeMetaHeaders($themes);
  60. }
  61. /**
  62. * Inject theme header into rendered page
  63. *
  64. * @param ITheme $theme the theme
  65. * @param bool $plain request the :root syntax
  66. * @param string $media media query to use in the <link> element
  67. */
  68. private function addThemeHeaders(ITheme $theme, bool $plain = true, ?string $media = null): void {
  69. $linkToCSS = $this->urlGenerator->linkToRoute('theming.Theming.getThemeStylesheet', [
  70. 'themeId' => $theme->getId(),
  71. 'plain' => $plain,
  72. 'v' => $this->util->getCacheBuster(),
  73. ]);
  74. \OCP\Util::addHeader('link', [
  75. 'rel' => 'stylesheet',
  76. 'media' => $media,
  77. 'href' => $linkToCSS,
  78. 'class' => 'theme'
  79. ]);
  80. }
  81. /**
  82. * Inject meta headers into rendered page
  83. *
  84. * @param ITheme[] $themes the theme
  85. */
  86. private function addThemeMetaHeaders(array $themes): void {
  87. $metaHeaders = [];
  88. // Meta headers
  89. foreach($this->themesService->getThemes() as $theme) {
  90. if (!empty($theme->getMeta())) {
  91. foreach($theme->getMeta() as $meta) {
  92. if (!isset($meta['name']) || !isset($meta['content'])) {
  93. continue;
  94. }
  95. if (!isset($metaHeaders[$meta['name']])) {
  96. $metaHeaders[$meta['name']] = [];
  97. }
  98. $metaHeaders[$meta['name']][] = $meta['content'];
  99. }
  100. }
  101. }
  102. foreach($metaHeaders as $name => $content) {
  103. \OCP\Util::addHeader('meta', [
  104. 'name' => $name,
  105. 'content' => join(' ', array_unique($content)),
  106. ]);
  107. }
  108. }
  109. }