@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.)
hq.recaptime.dev/wiki/Phorge
phorge
phabricator
1<?php
2
3final class PhrictionHovercardEngineExtension
4 extends PhabricatorHovercardEngineExtension {
5
6 const EXTENSIONKEY = 'phriction';
7
8 public function isExtensionEnabled() {
9 return PhabricatorApplication::isClassInstalled(
10 PhabricatorPhrictionApplication::class);
11 }
12
13 public function getExtensionName() {
14 return pht('Wiki Documents');
15 }
16
17 public function canRenderObjectHovercard($object) {
18 return ($object instanceof PhrictionDocument);
19 }
20
21 public function willRenderHovercards(array $objects) {
22 return array(
23 'projects' => $this->getProjectHandlesOfDocuments($objects),
24 'ancestors' => $this->getAncestorHandlesOfDocuments($objects),
25 );
26 }
27
28 public function renderHovercard(
29 PHUIHovercardView $hovercard,
30 PhabricatorObjectHandle $handle,
31 $object,
32 $data) {
33
34 $viewer = $this->getViewer();
35 $phid = $object->getPHID();
36
37 $detail_content = array(
38 id(new PHUIIconView())->setIcon('fa-book'),
39 );
40
41 $ancestor_handles = $data['ancestors'][$phid];
42 if ($ancestor_handles) {
43 foreach ($ancestor_handles as $ancestor_handle) {
44 $detail_content[] = phutil_tag(
45 'a',
46 array(
47 'href' => $ancestor_handle->getUri(),
48 ),
49 $ancestor_handle->getName());
50
51 $detail_content[] = id(new PHUIIconView())
52 ->setIcon('fa-angle-right')
53 ->addClass('phui-crumb-divider');
54 }
55 array_pop($detail_content);
56 } else {
57 $detail_content[] = pht('Wiki Document');
58 }
59
60 $project_handles = $data['projects'][$phid];
61 if ($project_handles) {
62 $list = id(new PHUIHandleTagListView())
63 ->setHandles($project_handles)
64 ->setSlim(true)
65 ->setShowHovercards(false);
66
67 $detail_content[] = $list;
68 }
69
70 $hovercard->setDetail(
71 phutil_tag(
72 'div',
73 array(
74 'class' => 'phui-hovercard-object-type',
75 ),
76 $detail_content));
77
78 $content = $object->getContent();
79
80 if ($content) {
81 $hovercard->addField(
82 pht('Last Author'),
83 $viewer->renderHandle($content->getAuthorPHID()));
84
85 $hovercard->addField(
86 pht('Last Edited'),
87 phabricator_dual_datetime($content->getDateCreated(), $viewer));
88 }
89 }
90
91 private function getProjectHandlesOfDocuments($documents) {
92 $viewer = $this->getViewer();
93 $project_edge_type = PhabricatorProjectObjectHasProjectEdgeType::EDGECONST;
94 $project_phids = array();
95 $project_map = array();
96
97 $project_edges = id(new PhabricatorEdgeQuery())
98 ->withSourcePHIDs(mpull($documents, 'getPHID'))
99 ->withEdgeTypes(array($project_edge_type))
100 ->execute();
101
102 foreach ($project_edges as $document_phid => $edge_types) {
103 $document_project_phids = array_keys($edge_types[$project_edge_type]);
104
105 $project_map[$document_phid] = array_reverse($document_project_phids);
106 foreach ($document_project_phids as $project_phid) {
107 if (!in_array($project_phid, $project_phids, true)) {
108 $project_phids[] = $project_phid;
109 }
110 }
111 }
112
113 if ($project_phids) {
114 $project_handles = $viewer->loadHandles($project_phids);
115 $project_handles = iterator_to_array($project_handles);
116 $project_handles = mpull($project_handles, null, 'getPHID');
117
118 foreach ($project_map as $key => $document_project_phids) {
119 $project_map[$key] = array_select_keys(
120 $project_handles,
121 $document_project_phids);
122 }
123 }
124
125 return $project_map;
126 }
127
128 private function getAncestorHandlesOfDocuments($documents) {
129 $viewer = $this->getViewer();
130 $ancestor_slugs = array();
131 $ancestor_map = array();
132
133 foreach ($documents as $document) {
134 $document_phid = $document->getPHID();
135 $document_ancestor_slugs = PhabricatorSlug::getAncestry(
136 $document->getSlug());
137
138 $ancestor_map[$document_phid] = $document_ancestor_slugs;
139 foreach ($document_ancestor_slugs as $slug) {
140 if (!in_array($slug, $ancestor_slugs, true)) {
141 $ancestor_slugs[] = $slug;
142 }
143 }
144 }
145
146 if ($ancestor_slugs) {
147 $ancestors = id(new PhrictionDocumentQuery())
148 ->setViewer($viewer)
149 ->withSlugs($ancestor_slugs)
150 ->execute();
151 $ancestor_phids = mpull($ancestors, 'getPHID', 'getSlug');
152 $ancestor_handles = $viewer->loadHandles($ancestor_phids);
153 $ancestor_handles = iterator_to_array($ancestor_handles);
154 $ancestor_handles = mpull($ancestor_handles, null, 'getPHID');
155
156 foreach ($ancestor_map as $key => $document_ancestor_slugs) {
157 $document_ancestor_phids = array_select_keys(
158 $ancestor_phids,
159 $document_ancestor_slugs);
160 $ancestor_map[$key] = array_select_keys(
161 $ancestor_handles,
162 $document_ancestor_phids);
163 }
164 }
165
166 return $ancestor_map;
167 }
168
169}