3 namespace BookStack\References\ModelResolvers;
5 use BookStack\Uploads\Image;
6 use BookStack\Uploads\ImageStorage;
8 class ImageModelResolver implements CrossLinkModelResolver
10 protected ?string $pattern = null;
12 public function resolve(string $link): ?Image
14 $pattern = $this->getUrlPattern();
16 $match = preg_match($pattern, $link, $matches);
23 // Strip thumbnail element from path if existing
24 $originalPathSplit = array_filter(explode('/', $path), function (string $part) {
25 $resizedDir = (str_starts_with($part, 'thumbs-') || str_starts_with($part, 'scaled-'));
26 $missingExtension = !str_contains($part, '.');
28 return !($resizedDir && $missingExtension);
31 // Build a database-format image path and search for the image entry
32 $fullPath = '/uploads/images/' . ltrim(implode('/', $originalPathSplit), '/');
34 return Image::query()->where('path', '=', $fullPath)->first();
38 * Get the regex pattern to identify image URLs.
39 * Caches the pattern since it requires looking up to settings/config.
41 protected function getUrlPattern(): string
44 return $this->pattern;
47 $urls = [url('/uploads/images')];
48 $baseImageUrl = ImageStorage::getPublicUrl('/uploads/images');
49 if ($baseImageUrl !== $urls[0]) {
50 $urls[] = $baseImageUrl;
53 $imageUrlRegex = implode('|', array_map(fn ($url) => preg_quote($url, '/'), $urls));
54 $this->pattern = '/^(' . $imageUrlRegex . ')\/(.+)/';
56 return $this->pattern;