diff --git a/src/Filesystem/TwigTemplateLocator.php b/src/Filesystem/TwigTemplateLocator.php index 5ee53b1..1db4ca0 100644 --- a/src/Filesystem/TwigTemplateLocator.php +++ b/src/Filesystem/TwigTemplateLocator.php @@ -93,7 +93,7 @@ public function getTemplateContext(string $templateName, array $options = []): T /* @var PageModel $objPage */ global $objPage; - if ('' != $objPage->templateGroup) { + if ($objPage && '' != $objPage->templateGroup) { if (Validator::isInsecurePath($objPage->templateGroup)) { throw new \RuntimeException('Invalid path '.$objPage->templateGroup); } @@ -424,6 +424,7 @@ protected function generateContaoTwigTemplatePaths(bool $extension = false): arr $this->stopwatch->start($stopwatchname); $contaoResourcePaths = $this->templateLocator->findResourcesPaths(); + $contaoThemePaths = $this->templateLocator->findThemeDirectories(); $bundles = $this->kernel->getBundles(); $resourcePaths = []; @@ -454,6 +455,7 @@ protected function generateContaoTwigTemplatePaths(bool $extension = false): arr $twigFiles = []; foreach ($resourcePaths as $bundle => $paths) { foreach ($paths as $path) { + $path = Path::canonicalize($path); $templates = $this->templateLocator->findTemplates($path); if (empty($templates)) { continue; @@ -478,7 +480,17 @@ protected function generateContaoTwigTemplatePaths(bool $extension = false): arr continue; } - $twigPath = ($namespace ? "@$namespace/" : '').$name; + if (empty($namespace) && str_contains($name, '/')) { + $parts = explode('/', $name); + if (isset($contaoThemePaths[$parts[0]]) + && (Path::getLongestCommonBasePath($contaoThemePaths[$parts[0]], $templatePath)) === $contaoThemePaths[$parts[0]]) { + $namespace = $parts[0]; + $name = Path::makeRelative($templatePath, $contaoThemePaths[$parts[0]]); + } + $twigPath = ($namespace ? "$namespace/" : '').$name; + } else { + $twigPath = ($namespace ? "@$namespace/" : '').$name; + } if (!$extension) { if (str_ends_with($name, '.html.twig')) { diff --git a/tests/Filesystem/TwigTemplateLocatorTest.php b/tests/Filesystem/TwigTemplateLocatorTest.php index 64372e4..9411f35 100644 --- a/tests/Filesystem/TwigTemplateLocatorTest.php +++ b/tests/Filesystem/TwigTemplateLocatorTest.php @@ -256,6 +256,64 @@ public function testGetTemplatePath() $this->assertSame('@ipsum/ce_text.html.twig', $instance->getTemplatePath('ce_text', ['disableCache' => true])); } + public function testGetTemplatePathNews() + { + $instance = $this->createTestInstance($this->prepareTemplateLoader([])); + $this->assertSame('@Contao_App/content_element/text.html.twig', $instance->getTemplatePath('text', ['disableCache' => true])); + $this->assertSame('@Contao_App/content_element/text.html.twig', $instance->getTemplatePath('content_element/text', ['disableCache' => true])); + $this->assertSame('@Contao_App/form_text.html.twig', $instance->getTemplatePath('form_text', ['disableCache' => true])); + $this->assertSame('ce_text.html.twig', $instance->getTemplatePath('ce_text', ['disableCache' => true])); + + $parameters = $this->prepareTemplateLoader([]); + $scopeMather = $this->createMock(ScopeMatcher::class); + $scopeMather->method('isFrontendRequest')->willReturn(true); + $parameters['scope_matcher'] = $scopeMather; + $instance = $this->createTestInstance($parameters); + $this->assertSame('ce_text.html.twig', $instance->getTemplatePath('ce_text', ['disableCache' => true])); + $GLOBALS['objPage'] = (object) ['templateGroup' => 'customtheme']; + $this->assertSame('customtheme/ce_text.html.twig', $instance->getTemplatePath('ce_text', ['disableCache' => true])); + } + + private function prepareTemplateLoader(array $parameters): array + { + $projectDir = __DIR__.'/../Fixtures/TwigTemplateLocator'; + $kernel = $this->createMock(Kernel::class); + $bundles = []; + $bundleMetaData = []; + foreach (['a', 'b'] as $bundle) { + $currentBundle = $this->createMock(BundleInterface::class); + $bundlePath = $projectDir.'/vendor/example/'.$bundle; + $currentBundle->method('getPath')->willReturn($bundlePath); + $currentBundle->method('getName')->willReturn($bundle); + $kernelBundles[$bundle] = $currentBundle; + $bundles[$bundle] = BundleInterface::class; + $bundleMetaData[$bundle] = ['path' => $bundlePath]; + } + + $kernel->method('getBundles')->willReturn($kernelBundles); + $kernel->method('getProjectDir')->willReturn($projectDir); + + $connection = $this->createMock(Connection::class); + $connection->method('fetchFirstColumn')->willReturn([ + 'templates/customtheme', + 'templates/anothertheme', + ]); + + $templateLocator = new TemplateLocator( + $projectDir, + $bundles, + $bundleMetaData, + new ThemeNamespace(), + $connection + ); + + $parameters['kernel'] = $kernel; + $parameters['locator'] = $templateLocator; + + return $parameters; + } + + protected function buildKernelAndResourceFinderForBundlesAndPath(array $bundles, string $subpath) { $kernel = $this->createMock(Kernel::class); diff --git a/tests/Fixtures/TwigTemplateLocator/contao/templates/twig/.twig-root b/tests/Fixtures/TwigTemplateLocator/contao/templates/twig/.twig-root new file mode 100644 index 0000000..e69de29 diff --git a/tests/Fixtures/TwigTemplateLocator/contao/templates/twig/content_element/text.html.twig b/tests/Fixtures/TwigTemplateLocator/contao/templates/twig/content_element/text.html.twig new file mode 100644 index 0000000..e69de29 diff --git a/tests/Fixtures/TwigTemplateLocator/contao/templates/widget/form_captcha.html5 b/tests/Fixtures/TwigTemplateLocator/contao/templates/widget/form_captcha.html5 new file mode 100644 index 0000000..e69de29 diff --git a/tests/Fixtures/TwigTemplateLocator/contao/templates/widget/form_text.html.twig b/tests/Fixtures/TwigTemplateLocator/contao/templates/widget/form_text.html.twig new file mode 100644 index 0000000..e69de29 diff --git a/tests/Fixtures/TwigTemplateLocator/templates/anothertheme/ce_text.html.twig b/tests/Fixtures/TwigTemplateLocator/templates/anothertheme/ce_text.html.twig new file mode 100644 index 0000000..e69de29 diff --git a/tests/Fixtures/TwigTemplateLocator/templates/ce_text.html.twig b/tests/Fixtures/TwigTemplateLocator/templates/ce_text.html.twig new file mode 100644 index 0000000..e69de29 diff --git a/tests/Fixtures/TwigTemplateLocator/templates/customtheme/ce_text.html.twig b/tests/Fixtures/TwigTemplateLocator/templates/customtheme/ce_text.html.twig new file mode 100644 index 0000000..e69de29