]> BookStack Code Mirror - bookstack/blob - app/Exports/ZipExports/ZipExportReferences.php
ZIP Exports: Added core logic for books/chapters
[bookstack] / app / Exports / ZipExports / ZipExportReferences.php
1 <?php
2
3 namespace BookStack\Exports\ZipExports;
4
5 use BookStack\App\Model;
6 use BookStack\Exports\ZipExports\Models\ZipExportAttachment;
7 use BookStack\Exports\ZipExports\Models\ZipExportBook;
8 use BookStack\Exports\ZipExports\Models\ZipExportChapter;
9 use BookStack\Exports\ZipExports\Models\ZipExportImage;
10 use BookStack\Exports\ZipExports\Models\ZipExportModel;
11 use BookStack\Exports\ZipExports\Models\ZipExportPage;
12 use BookStack\Uploads\Attachment;
13 use BookStack\Uploads\Image;
14
15 class ZipExportReferences
16 {
17     /** @var ZipExportPage[] */
18     protected array $pages = [];
19     /** @var ZipExportChapter[] */
20     protected array $chapters = [];
21     /** @var ZipExportBook[] */
22     protected array $books = [];
23
24     /** @var ZipExportAttachment[] */
25     protected array $attachments = [];
26
27     /** @var ZipExportImage[] */
28     protected array $images = [];
29
30     public function __construct(
31         protected ZipReferenceParser $parser,
32     ) {
33     }
34
35     public function addPage(ZipExportPage $page): void
36     {
37         if ($page->id) {
38             $this->pages[$page->id] = $page;
39         }
40
41         foreach ($page->attachments as $attachment) {
42             if ($attachment->id) {
43                 $this->attachments[$attachment->id] = $attachment;
44             }
45         }
46     }
47
48     public function addChapter(ZipExportChapter $chapter): void
49     {
50         if ($chapter->id) {
51             $this->chapters[$chapter->id] = $chapter;
52         }
53
54         foreach ($chapter->pages as $page) {
55             $this->addPage($page);
56         }
57     }
58
59     public function addBook(ZipExportBook $book): void
60     {
61         if ($book->id) {
62             $this->chapters[$book->id] = $book;
63         }
64
65         foreach ($book->pages as $page) {
66             $this->addPage($page);
67         }
68
69         foreach ($book->chapters as $chapter) {
70             $this->addChapter($chapter);
71         }
72     }
73
74     public function buildReferences(ZipExportFiles $files): void
75     {
76         $createHandler = function (ZipExportModel $zipModel) use ($files) {
77             return function (Model $model) use ($files, $zipModel) {
78                 return $this->handleModelReference($model, $zipModel, $files);
79             };
80         };
81
82         // Parse page content first
83         foreach ($this->pages as $page) {
84             $handler = $createHandler($page);
85             $page->html = $this->parser->parse($page->html ?? '', $handler);
86             if ($page->markdown) {
87                 $page->markdown = $this->parser->parse($page->markdown, $handler);
88             }
89         }
90
91         // Parse chapter description HTML
92         foreach ($this->chapters as $chapter) {
93             if ($chapter->description_html) {
94                 $handler = $createHandler($chapter);
95                 $chapter->description_html = $this->parser->parse($chapter->description_html, $handler);
96             }
97         }
98
99         // Parse book description HTML
100         foreach ($this->books as $book) {
101             if ($book->description_html) {
102                 $handler = $createHandler($book);
103                 $book->description_html = $this->parser->parse($book->description_html, $handler);
104             }
105         }
106     }
107
108     protected function handleModelReference(Model $model, ZipExportModel $exportModel, ZipExportFiles $files): ?string
109     {
110         // TODO - References to other entities
111
112         // Handle attachment references
113         // No permission check needed here since they would only already exist in this
114         // reference context if already allowed via their entity access.
115         if ($model instanceof Attachment) {
116             if (isset($this->attachments[$model->id])) {
117                 return "[[bsexport:attachment:{$model->id}]]";
118             }
119             return null;
120         }
121
122         // Handle image references
123         if ($model instanceof Image) {
124             // Only handle gallery and drawio images
125             if ($model->type !== 'gallery' && $model->type !== 'drawio') {
126                 return null;
127             }
128
129             // We don't expect images to be part of book/chapter content
130             if (!($exportModel instanceof ZipExportPage)) {
131                 return null;
132             }
133
134             $page = $model->getPage();
135             if ($page && userCan('view', $page)) {
136                 if (!isset($this->images[$model->id])) {
137                     $exportImage = ZipExportImage::fromModel($model, $files);
138                     $this->images[$model->id] = $exportImage;
139                     $exportModel->images[] = $exportImage;
140                 }
141                 return "[[bsexport:image:{$model->id}]]";
142             }
143             return null;
144         }
145
146         return null;
147     }
148 }