> */ private array $candidateCache = []; public function __construct( private readonly Stylist $stylist, private readonly ViewFactory $views, private readonly Loader $loader, ) {} public function make(string $view, array $data = [], array $mergeData = []): View { return $this->views->first( $this->candidates($view), array_replace([ 'themeSettings' => $this->stylist->settings(), 'themeVariant' => $this->stylist->variant(), ], $data), $mergeData, ); } public function makeForTheme(string $theme, string $view, array $data = [], array $mergeData = []): View { return $this->views->first($this->candidatesForTheme($theme, $view), $data, $mergeData); } /** @return array */ public function candidates(string $view): array { return $this->candidatesForTheme($this->stylist->current()->key(), $view); } /** @return array */ public function candidatesForTheme(string $theme, string $view): array { $view = ltrim($view, '.'); $cacheKey = $theme.'|'.$view; if (isset($this->candidateCache[$cacheKey])) { return $this->candidateCache[$cacheKey]; } $keys = $this->inheritanceChain($theme); $fallback = (string) config('stylist.default_theme', 'common'); if ($fallback !== '' && ! in_array($fallback, $keys, true)) { try { $keys = array_merge($keys, $this->inheritanceChain($fallback)); } catch (ThemeNotFoundException) { // A missing configured fallback is diagnosed by stylist:doctor. } } if (! in_array('common', $keys, true)) { try { $keys = array_merge($keys, $this->inheritanceChain('common')); } catch (ThemeNotFoundException) { // The module fallback below remains available. } } $candidates = []; foreach (array_values(array_unique($keys)) as $key) { $this->registerNamespace($key); $candidates[] = "stylist-theme-{$key}::{$view}"; $candidates[] = "stylist-module-theme-{$key}::{$view}"; } $candidates[] = "stylist::{$view}"; $candidates[] = $view; return $this->candidateCache[$cacheKey] = array_values(array_unique($candidates)); } public function flush(): void { $this->candidateCache = []; } /** @return array */ private function inheritanceChain(string $theme): array { $keys = []; $seen = []; $key = $theme; while ($key !== '') { if (isset($seen[$key])) { throw new RuntimeException('Theme inheritance cycle detected at ['.$key.'].'); } $seen[$key] = true; $loaded = $this->loader->find($key); $keys[] = $loaded->key(); $key = $loaded->parent() ?? ''; } return $keys; } private function registerNamespace(string $theme): void { try { $loaded = $this->loader->find($theme); } catch (ThemeNotFoundException) { return; } $viewsPath = $loaded->path().DIRECTORY_SEPARATOR.'views'; if (! is_dir($viewsPath)) { return; } $this->views->addNamespace("stylist-theme-{$theme}", $viewsPath); $this->views->addNamespace("stylist-module-theme-{$theme}", $viewsPath); } }