]> BookStack Code Mirror - bookstack/blob - app/Activity/Tools/CommentTree.php
Lexical: Media form improvements
[bookstack] / app / Activity / Tools / CommentTree.php
1 <?php
2
3 namespace BookStack\Activity\Tools;
4
5 use BookStack\Activity\Models\Comment;
6 use BookStack\Entities\Models\Page;
7
8 class CommentTree
9 {
10     /**
11      * The built nested tree structure array.
12      * @var CommentTreeNode[]
13      */
14     protected array $tree;
15     protected array $comments;
16
17     public function __construct(
18         protected Page $page
19     ) {
20         $this->comments = $this->loadComments();
21         $this->tree = $this->createTree($this->comments);
22     }
23
24     public function enabled(): bool
25     {
26         return !setting('app-disable-comments');
27     }
28
29     public function empty(): bool
30     {
31         return count($this->getActive()) === 0;
32     }
33
34     public function count(): int
35     {
36         return count($this->comments);
37     }
38
39     public function getActive(): array
40     {
41         return array_filter($this->tree, fn (CommentTreeNode $node) => !$node->comment->archived);
42     }
43
44     public function activeThreadCount(): int
45     {
46         return count($this->getActive());
47     }
48
49     public function getArchived(): array
50     {
51         return array_filter($this->tree, fn (CommentTreeNode $node) => $node->comment->archived);
52     }
53
54     public function archivedThreadCount(): int
55     {
56         return count($this->getArchived());
57     }
58
59     public function getCommentNodeForId(int $commentId): ?CommentTreeNode
60     {
61         foreach ($this->tree as $node) {
62             if ($node->comment->id === $commentId) {
63                 return $node;
64             }
65         }
66
67         return null;
68     }
69
70     public function canUpdateAny(): bool
71     {
72         foreach ($this->comments as $comment) {
73             if (userCan('comment-update', $comment)) {
74                 return true;
75             }
76         }
77
78         return false;
79     }
80
81     /**
82      * @param Comment[] $comments
83      * @return CommentTreeNode[]
84      */
85     protected function createTree(array $comments): array
86     {
87         $byId = [];
88         foreach ($comments as $comment) {
89             $byId[$comment->local_id] = $comment;
90         }
91
92         $childMap = [];
93         foreach ($comments as $comment) {
94             $parent = $comment->parent_id;
95             if (is_null($parent) || !isset($byId[$parent])) {
96                 $parent = 0;
97             }
98
99             if (!isset($childMap[$parent])) {
100                 $childMap[$parent] = [];
101             }
102             $childMap[$parent][] = $comment->local_id;
103         }
104
105         $tree = [];
106         foreach ($childMap[0] ?? [] as $childId) {
107             $tree[] = $this->createTreeNodeForId($childId, 0, $byId, $childMap);
108         }
109
110         return $tree;
111     }
112
113     protected function createTreeNodeForId(int $id, int $depth, array &$byId, array &$childMap): CommentTreeNode
114     {
115         $childIds = $childMap[$id] ?? [];
116         $children = [];
117
118         foreach ($childIds as $childId) {
119             $children[] = $this->createTreeNodeForId($childId, $depth + 1, $byId, $childMap);
120         }
121
122         return new CommentTreeNode($byId[$id], $depth, $children);
123     }
124
125     protected function loadComments(): array
126     {
127         if (!$this->enabled()) {
128             return [];
129         }
130
131         return $this->page->comments()
132             ->with('createdBy')
133             ->get()
134             ->all();
135     }
136 }