| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348 |
- <?php
- namespace Webkul\Theme;
- use Illuminate\Support\Facades\Config;
- use Illuminate\Support\Facades\Vite;
- use Illuminate\Support\Str;
- use Webkul\Theme\Exceptions\ViterNotFound;
- class Themes
- {
- /**
- * Contains current activated theme code.
- *
- * @var string
- */
- protected $activeTheme = null;
- /**
- * Contains all themes.
- *
- * @var array
- */
- protected $themes = [];
- /**
- * Contains laravel default view paths.
- *
- * @var array
- */
- protected $laravelViewsPath;
- /**
- * Create a new themes instance.
- *
- * @return void
- */
- public function __construct()
- {
- $this->laravelViewsPath = Config::get('view.paths');
- $this->loadThemes();
- }
- /**
- * Return list of all registered themes.
- *
- * @return array
- */
- public function all()
- {
- return $this->themes;
- }
- /**
- * Return list of registered themes.
- *
- * @return array
- */
- public function getChannelThemes()
- {
- $themes = config('themes.shop', []);
- $channelThemes = [];
- foreach ($themes as $code => $data) {
- $channelThemes[] = new Theme(
- $code,
- $data['name'] ?? '',
- $data['assets_path'] ?? '',
- $data['views_path'] ?? '',
- isset($data['vite']) ? $data['vite'] : [],
- );
- if (! empty($data['parent'])) {
- $parentThemes[$code] = $data['parent'];
- }
- }
- return $channelThemes;
- }
- /**
- * Check if specified exists.
- *
- * @return bool
- */
- public function exists(string $themeName)
- {
- foreach ($this->themes as $theme) {
- if ($theme->code == $themeName) {
- return true;
- }
- }
- return false;
- }
- /**
- * Prepare all themes.
- *
- * @return void
- */
- public function loadThemes()
- {
- $parentThemes = [];
- /**
- * Octane safety: Handle request context more safely.
- */
- $isAdmin = false;
- try {
- $currentRequest = request();
- if ($currentRequest && $currentRequest->url()) {
- $isAdmin = Str::contains($currentRequest->url(), config('app.admin_url').'/');
- }
- } catch (\Exception $e) {
- /**
- * Fallback if request context is not available.
- */
- $isAdmin = false;
- }
- if ($isAdmin) {
- $themes = config('themes.admin', []);
- } else {
- $themes = config('themes.shop', []);
- }
- foreach ($themes as $code => $data) {
- $this->themes[] = new Theme(
- $code,
- $data['name'] ?? '',
- $data['assets_path'] ?? '',
- $data['views_path'] ?? '',
- $data['views_namespace'] ?? null,
- $data['vite'] ?? [],
- );
- if (! empty($data['parent'])) {
- $parentThemes[$code] = $data['parent'];
- }
- }
- foreach ($parentThemes as $childCode => $parentCode) {
- $child = $this->find($childCode);
- if ($this->exists($parentCode)) {
- $parent = $this->find($parentCode);
- } else {
- $parent = new Theme($parentCode);
- }
- $child->setParent($parent);
- }
- }
- /**
- * Enable theme.
- *
- * @return \Webkul\Theme\Theme
- */
- public function set(string $themeName)
- {
- if ($this->exists($themeName)) {
- $theme = $this->find($themeName);
- } else {
- $theme = new Theme($themeName);
- }
- $this->activeTheme = $theme;
- $paths = $theme->getViewPaths();
- foreach ($this->laravelViewsPath as $path) {
- if (! in_array($path, $paths)) {
- $paths[] = $path;
- }
- }
- Config::set('view.paths', $paths);
- $themeViewFinder = app('view.finder');
- $themeViewFinder->setPaths($paths);
- return $theme;
- }
- /**
- * Get current theme.
- *
- * @return \Webkul\Theme\Theme
- */
- public function current()
- {
- return $this->activeTheme ?? null;
- }
- /**
- * Get current theme's name.
- *
- * @return string
- */
- public function getName()
- {
- return $this->current()?->name ?? '';
- }
- /**
- * Find a theme by it's name.
- *
- * @return \Webkul\Theme\Theme
- */
- public function find(string $themeName)
- {
- foreach ($this->themes as $theme) {
- if ($theme->code == $themeName) {
- return $theme;
- }
- }
- throw new Exceptions\ThemeNotFound($themeName);
- }
- /**
- * Original view paths defined in `config.view.php`.
- *
- * @return array
- */
- public function getLaravelViewPaths()
- {
- return $this->laravelViewsPath;
- }
- /**
- * Return the asset URL of the current theme if a theme is found; otherwise, check from the namespace.
- *
- * @return string
- */
- public function url(string $filename, ?string $namespace = null)
- {
- $url = trim($filename, '/');
- /**
- * If the namespace is null, it means the theming system is activated. We use the request URI to
- * detect the theme and provide Vite assets based on the current theme.
- */
- if (empty($namespace)) {
- $currentTheme = $this->current();
- /**
- * Octane safety: Initialize theme if not set.
- */
- if (! $currentTheme) {
- $this->ensureThemeInitialized();
- $currentTheme = $this->current();
- }
- return $currentTheme->url($url);
- }
- /**
- * If a namespace is provided, it means the developer knows what they are doing and must create the
- * registry in the provided configuration. We will analyze based on that.
- */
- $viters = config('bagisto-vite.viters');
- if (empty($viters[$namespace])) {
- throw new ViterNotFound($namespace);
- }
- $viteUrl = trim($viters[$namespace]['package_assets_directory'], '/').'/'.$url;
- return Vite::useHotFile($viters[$namespace]['hot_file'])
- ->useBuildDirectory($viters[$namespace]['build_directory'])
- ->asset($viteUrl);
- }
- /**
- * Set bagisto vite in current theme.
- *
- * @param mixed $entryPoints
- * @return mixed
- */
- public function setBagistoVite($entryPoints, ?string $namespace = null)
- {
- /**
- * If the namespace is null, it means the theming system is activated. We use the request URI to
- * detect the theme and provide Vite assets based on the current theme.
- */
- if (empty($namespace)) {
- $currentTheme = $this->current();
- /**
- * Octane safety: Initialize theme if not set.
- */
- if (! $currentTheme) {
- $this->ensureThemeInitialized();
- $currentTheme = $this->current();
- }
- return $currentTheme->setBagistoVite($entryPoints);
- }
- /**
- * If a namespace is provided, it means the developer knows what they are doing and must create the
- * registry in the provided configuration. We will analyze based on that.
- */
- $viters = config('bagisto-vite.viters');
- if (empty($viters[$namespace])) {
- throw new ViterNotFound($namespace);
- }
- return Vite::useHotFile($viters[$namespace]['hot_file'])
- ->useBuildDirectory($viters[$namespace]['build_directory'])
- ->withEntryPoints($entryPoints);
- }
- /**
- * Ensure theme is properly initialized (Octane Safety).
- *
- * @return void
- */
- protected function ensureThemeInitialized()
- {
- if (! $this->activeTheme) {
- /**
- * Reload themes based on current request context.
- */
- $this->loadThemes();
- /**
- * Set default theme if no theme is set.
- */
- if (! $this->activeTheme && ! empty($this->themes)) {
- $defaultTheme = $this->themes[0];
- $this->set($defaultTheme->code);
- }
- }
- }
- }
|