]> BookStack Code Mirror - bookstack/blob - app/Exports/ZipReferenceParser.php
ZIP Exports: Added working image handling/inclusion
[bookstack] / app / Exports / ZipReferenceParser.php
1 <?php
2
3 namespace BookStack\Exports;
4
5 use BookStack\App\Model;
6 use BookStack\Entities\Queries\EntityQueries;
7 use BookStack\References\ModelResolvers\AttachmentModelResolver;
8 use BookStack\References\ModelResolvers\BookLinkModelResolver;
9 use BookStack\References\ModelResolvers\ChapterLinkModelResolver;
10 use BookStack\References\ModelResolvers\CrossLinkModelResolver;
11 use BookStack\References\ModelResolvers\ImageModelResolver;
12 use BookStack\References\ModelResolvers\PageLinkModelResolver;
13 use BookStack\References\ModelResolvers\PagePermalinkModelResolver;
14
15 class ZipReferenceParser
16 {
17     /**
18      * @var CrossLinkModelResolver[]
19      */
20     protected array $modelResolvers;
21
22     public function __construct(EntityQueries $queries)
23     {
24         $this->modelResolvers = [
25             new PagePermalinkModelResolver($queries->pages),
26             new PageLinkModelResolver($queries->pages),
27             new ChapterLinkModelResolver($queries->chapters),
28             new BookLinkModelResolver($queries->books),
29             new ImageModelResolver(),
30             new AttachmentModelResolver(),
31         ];
32     }
33
34     /**
35      * Parse and replace references in the given content.
36      * @param callable(Model):(string|null) $handler
37      */
38     public function parse(string $content, callable $handler): string
39     {
40         $escapedBase = preg_quote(url('/'), '/');
41         $linkRegex = "/({$escapedBase}.*?)[\\t\\n\\f>\"'=?#]/";
42         $matches = [];
43         preg_match_all($linkRegex, $content, $matches);
44
45         if (count($matches) < 2) {
46             return $content;
47         }
48
49         foreach ($matches[1] as $link) {
50             $model = $this->linkToModel($link);
51             if ($model) {
52                 $result = $handler($model);
53                 if ($result !== null) {
54                     $content = str_replace($link, $result, $content);
55                 }
56             }
57         }
58
59         return $content;
60     }
61
62
63     /**
64      * Attempt to resolve the given link to a model using the instance model resolvers.
65      */
66     protected function linkToModel(string $link): ?Model
67     {
68         foreach ($this->modelResolvers as $resolver) {
69             $model = $resolver->resolve($link);
70             if (!is_null($model)) {
71                 return $model;
72             }
73         }
74
75         return null;
76     }
77 }