]> BookStack Code Mirror - bookstack/blob - app/Theming/ThemeService.php
Themes: Added route to serve public theme files
[bookstack] / app / Theming / ThemeService.php
1 <?php
2
3 namespace BookStack\Theming;
4
5 use BookStack\Access\SocialDriverManager;
6 use BookStack\Exceptions\ThemeException;
7 use Illuminate\Console\Application;
8 use Illuminate\Console\Application as Artisan;
9 use Symfony\Component\Console\Command\Command;
10
11 class ThemeService
12 {
13     /**
14      * @var array<string, callable[]>
15      */
16     protected array $listeners = [];
17
18     /**
19      * Get the currently configured theme.
20      * Returns an empty string if not configured.
21      */
22     public function getTheme(): string
23     {
24         return config('view.theme') ?? '';
25     }
26
27     /**
28      * Listen to a given custom theme event,
29      * setting up the action to be ran when the event occurs.
30      */
31     public function listen(string $event, callable $action): void
32     {
33         if (!isset($this->listeners[$event])) {
34             $this->listeners[$event] = [];
35         }
36
37         $this->listeners[$event][] = $action;
38     }
39
40     /**
41      * Dispatch the given event name.
42      * Runs any registered listeners for that event name,
43      * passing all additional variables to the listener action.
44      *
45      * If a callback returns a non-null value, this method will
46      * stop and return that value itself.
47      */
48     public function dispatch(string $event, ...$args): mixed
49     {
50         foreach ($this->listeners[$event] ?? [] as $action) {
51             $result = call_user_func_array($action, $args);
52             if (!is_null($result)) {
53                 return $result;
54             }
55         }
56
57         return null;
58     }
59
60     /**
61      * Check if there are listeners registered for the given event name.
62      */
63     public function hasListeners(string $event): bool
64     {
65         return count($this->listeners[$event] ?? []) > 0;
66     }
67
68     /**
69      * Register a new custom artisan command to be available.
70      */
71     public function registerCommand(Command $command): void
72     {
73         Artisan::starting(function (Application $application) use ($command) {
74             $application->addCommands([$command]);
75         });
76     }
77
78     /**
79      * Read any actions from the set theme path if the 'functions.php' file exists.
80      */
81     public function readThemeActions(): void
82     {
83         $themeActionsFile = theme_path('functions.php');
84         if ($themeActionsFile && file_exists($themeActionsFile)) {
85             try {
86                 require $themeActionsFile;
87             } catch (\Error $exception) {
88                 throw new ThemeException("Failed loading theme functions file at \"{$themeActionsFile}\" with error: {$exception->getMessage()}");
89             }
90         }
91     }
92
93     /**
94      * @see SocialDriverManager::addSocialDriver
95      */
96     public function addSocialDriver(string $driverName, array $config, string $socialiteHandler, callable $configureForRedirect = null): void
97     {
98         $driverManager = app()->make(SocialDriverManager::class);
99         $driverManager->addSocialDriver($driverName, $config, $socialiteHandler, $configureForRedirect);
100     }
101 }