Files
BookStack/app/Theming/ThemeViews.php
2026-02-01 11:53:46 +00:00

105 lines
3.3 KiB
PHP

<?php
namespace BookStack\Theming;
use BookStack\Exceptions\ThemeException;
use Illuminate\View\FileViewFinder;
class ThemeViews
{
/**
* @var array<string, array<string, int>>
*/
protected array $beforeViews = [];
/**
* @var array<string, array<string, int>>
*/
protected array $afterViews = [];
/**
* Register any extra paths for where we may expect views to be located
* with the provided FileViewFinder, to make custom views available for use.
* @param ThemeModule[] $modules
*/
public function registerViewPathsForTheme(FileViewFinder $finder, array $modules): void
{
foreach ($modules as $module) {
$moduleViewsPath = $module->path('views');
if (file_exists($moduleViewsPath) && is_dir($moduleViewsPath)) {
$finder->prependLocation($moduleViewsPath);
}
}
$finder->prependLocation(theme_path());
}
/**
* Provide the response for a blade template view include.
*/
public function handleViewInclude(string $viewPath, array $data = []): string
{
if (!$this->hasRegisteredViews()) {
return view()->make($viewPath, $data)->render();
}
$viewsContent = [
...$this->renderViewSets($this->beforeViews[$viewPath] ?? [], $data),
view()->make($viewPath, $data)->render(),
...$this->renderViewSets($this->afterViews[$viewPath] ?? [], $data),
];
return implode("\n", $viewsContent);
}
/**
* Register a custom view to be rendered before the given target view is included in the template system.
*/
public function renderBefore(string $targetView, string $localView, int $priority = 50): void
{
$this->registerAdjacentView($this->beforeViews, $targetView, $localView, $priority);
}
/**
* Register a custom view to be rendered after the given target view is included in the template system.
*/
public function renderAfter(string $targetView, string $localView, int $priority = 50): void
{
$this->registerAdjacentView($this->afterViews, $targetView, $localView, $priority);
}
public function hasRegisteredViews(): bool
{
return !empty($this->beforeViews) && !empty($this->afterViews);
}
protected function registerAdjacentView(array &$location, string $targetView, string $localView, int $priority = 50): void
{
$viewPath = theme_path($localView . '.blade.php');
if (!file_exists($viewPath)) {
throw new ThemeException("Expected registered view file at \"{$viewPath}\" does not exist");
}
if (!isset($location[$targetView])) {
$location[$targetView] = [];
}
$location[$targetView][$viewPath] = $priority;
}
/**
* @param array<string, int> $viewSet
* @return string[]
*/
protected function renderViewSets(array $viewSet, array $data): array
{
$paths = array_keys($viewSet);
usort($paths, function (string $a, string $b) use ($viewSet) {
return $viewSet[$a] <=> $viewSet[$b];
});
return array_map(function (string $viewPath) use ($data) {
return view()->file($viewPath, $data)->render();
}, $paths);
}
}