3 namespace BookStack\Exports\ZipExports;
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;
15 class ZipExportReferences
17 /** @var ZipExportPage[] */
18 protected array $pages = [];
19 /** @var ZipExportChapter[] */
20 protected array $chapters = [];
21 /** @var ZipExportBook[] */
22 protected array $books = [];
24 /** @var ZipExportAttachment[] */
25 protected array $attachments = [];
27 /** @var ZipExportImage[] */
28 protected array $images = [];
30 public function __construct(
31 protected ZipReferenceParser $parser,
35 public function addPage(ZipExportPage $page): void
38 $this->pages[$page->id] = $page;
41 foreach ($page->attachments as $attachment) {
42 if ($attachment->id) {
43 $this->attachments[$attachment->id] = $attachment;
48 public function addChapter(ZipExportChapter $chapter): void
51 $this->chapters[$chapter->id] = $chapter;
54 foreach ($chapter->pages as $page) {
55 $this->addPage($page);
59 public function addBook(ZipExportBook $book): void
62 $this->chapters[$book->id] = $book;
65 foreach ($book->pages as $page) {
66 $this->addPage($page);
69 foreach ($book->chapters as $chapter) {
70 $this->addChapter($chapter);
74 public function buildReferences(ZipExportFiles $files): void
76 $createHandler = function (ZipExportModel $zipModel) use ($files) {
77 return function (Model $model) use ($files, $zipModel) {
78 return $this->handleModelReference($model, $zipModel, $files);
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);
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);
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);
108 protected function handleModelReference(Model $model, ZipExportModel $exportModel, ZipExportFiles $files): ?string
110 // TODO - References to other entities
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}]]";
122 // Handle image references
123 if ($model instanceof Image) {
124 // Only handle gallery and drawio images
125 if ($model->type !== 'gallery' && $model->type !== 'drawio') {
129 // We don't expect images to be part of book/chapter content
130 if (!($exportModel instanceof ZipExportPage)) {
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;
141 return "[[bsexport:image:{$model->id}]]";