vendor/contao/core-bundle/src/Twig/Loader/TemplateLocator.php line 76

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. /*
  4.  * This file is part of Contao.
  5.  *
  6.  * (c) Leo Feyer
  7.  *
  8.  * @license LGPL-3.0-or-later
  9.  */
  10. namespace Contao\CoreBundle\Twig\Loader;
  11. use Contao\CoreBundle\Exception\InvalidThemePathException;
  12. use Contao\CoreBundle\HttpKernel\Bundle\ContaoModuleBundle;
  13. use Doctrine\DBAL\Connection;
  14. use Doctrine\DBAL\Exception\DriverException;
  15. use Symfony\Component\Filesystem\Path;
  16. use Symfony\Component\Finder\Finder;
  17. /**
  18.  * @experimental
  19.  */
  20. class TemplateLocator
  21. {
  22.     private string $projectDir;
  23.     private ThemeNamespace $themeNamespace;
  24.     private Connection $connection;
  25.     /**
  26.      * @var array<string,string>
  27.      */
  28.     private array $bundles;
  29.     /**
  30.      * @var array<string, array<string, string>>
  31.      */
  32.     private array $bundlesMetadata;
  33.     public function __construct(string $projectDir, array $bundles, array $bundlesMetadataThemeNamespace $themeNamespaceConnection $connection)
  34.     {
  35.         $this->projectDir $projectDir;
  36.         $this->bundles $bundles;
  37.         $this->bundlesMetadata $bundlesMetadata;
  38.         $this->themeNamespace $themeNamespace;
  39.         $this->connection $connection;
  40.     }
  41.     /**
  42.      * @return array<string, string>
  43.      */
  44.     public function findThemeDirectories(): array
  45.     {
  46.         $directories = [];
  47.         // This code might run early during cache warmup where the 'tl_theme'
  48.         // table couldn't exist, yet.
  49.         try {
  50.             // Note: We cannot use models or other parts of the Contao
  51.             // framework here because this function will be called when the
  52.             // container is built (see #3567)
  53.             $themePaths $this->connection->fetchFirstColumn('SELECT templates FROM tl_theme');
  54.         } catch (DriverException $e) {
  55.             return [];
  56.         }
  57.         foreach ($themePaths as $themePath) {
  58.             if (!is_dir($absolutePath Path::join($this->projectDir$themePath))) {
  59.                 continue;
  60.             }
  61.             try {
  62.                 $slug $this->themeNamespace->generateSlug(Path::makeRelative($themePath'templates'));
  63.             } catch (InvalidThemePathException $e) {
  64.                 trigger_deprecation('contao/core-bundle''4.12''Using a theme path with invalid characters has been deprecated and will throw an exception in Contao 5.0.');
  65.                 continue;
  66.             }
  67.             $directories[$slug] = $absolutePath;
  68.         }
  69.         return $directories;
  70.     }
  71.     /**
  72.      * @return array<string, array<string>>
  73.      */
  74.     public function findResourcesPaths(): array
  75.     {
  76.         $paths = [];
  77.         $add = function (string $groupstring $basePath) use (&$paths): void {
  78.             $paths[$group] = array_merge($paths[$group] ?? [], $this->expandSubdirectories($basePath));
  79.         };
  80.         if (is_dir($path Path::join($this->projectDir'contao/templates'))) {
  81.             $add('App'$path);
  82.         }
  83.         if (is_dir($path Path::join($this->projectDir'src/Resources/contao/templates'))) {
  84.             $add('App'$path);
  85.         }
  86.         if (is_dir($path Path::join($this->projectDir'app/Resources/contao/templates'))) {
  87.             $add('App'$path);
  88.         }
  89.         foreach (array_reverse($this->bundles) as $name => $class) {
  90.             if (ContaoModuleBundle::class === $class && is_dir($path Path::join($this->bundlesMetadata[$name]['path'], 'templates'))) {
  91.                 $add($name$path);
  92.             } elseif (is_dir($path Path::join($this->bundlesMetadata[$name]['path'], 'Resources/contao/templates'))) {
  93.                 $add($name$path);
  94.             } elseif (is_dir($path Path::join($this->bundlesMetadata[$name]['path'], 'contao/templates'))) {
  95.                 $add($name$path);
  96.             }
  97.         }
  98.         return $paths;
  99.     }
  100.     /**
  101.      * @return array<string, string>
  102.      */
  103.     public function findTemplates(string $path): array
  104.     {
  105.         if (!is_dir($path)) {
  106.             return [];
  107.         }
  108.         $finder = (new Finder())
  109.             ->files()
  110.             ->in($path)
  111.             ->depth('< 1')
  112.             ->name('/(\.html\.twig|\.html5)$/')
  113.             ->sortByName()
  114.         ;
  115.         $templates = [];
  116.         foreach ($finder as $file) {
  117.             $templates[$file->getFilename()] = Path::canonicalize($file->getPathname());
  118.         }
  119.         return $templates;
  120.     }
  121.     private function expandSubdirectories(string $path): array
  122.     {
  123.         $finder = (new Finder())
  124.             ->directories()
  125.             ->in($path)
  126.             ->sortByName()
  127.         ;
  128.         $paths = [$path];
  129.         foreach ($finder as $item) {
  130.             $paths[] = Path::canonicalize($item->getPathname());
  131.         }
  132.         return $paths;
  133.     }
  134. }