@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 PhabricatorSearchDocumentQuery
4 extends PhabricatorPolicyAwareQuery {
5
6 private $savedQuery;
7 private $objectCapabilities;
8 private $unfilteredOffset;
9 private $fulltextResultSet;
10
11 public function withSavedQuery(PhabricatorSavedQuery $query) {
12 $this->savedQuery = $query;
13 return $this;
14 }
15
16 public function requireObjectCapabilities(array $capabilities) {
17 $this->objectCapabilities = $capabilities;
18 return $this;
19 }
20
21 protected function getRequiredObjectCapabilities() {
22 if ($this->objectCapabilities) {
23 return $this->objectCapabilities;
24 }
25
26 return $this->getRequiredCapabilities();
27 }
28
29 /**
30 * @return PhabricatorFulltextResultSet
31 */
32 public function getFulltextResultSet() {
33 if (!$this->fulltextResultSet) {
34 throw new PhutilInvalidStateException('execute');
35 }
36
37 return $this->fulltextResultSet;
38 }
39
40 protected function willExecute() {
41 $this->unfilteredOffset = 0;
42 $this->fulltextResultSet = null;
43 }
44
45 /**
46 * Load a raw page of results.
47 *
48 * @return list PHIDs of the search result objects as array keys.
49 */
50 protected function loadPage() {
51 // NOTE: The offset and limit information in the inherited properties of
52 // this object represent a policy-filtered offset and limit, but the
53 // underlying query engine needs an unfiltered offset and limit. We keep
54 // track of an unfiltered result offset internally.
55
56 $query = id(clone($this->savedQuery))
57 ->setParameter('offset', $this->unfilteredOffset)
58 ->setParameter('limit', $this->getRawResultLimit());
59
60 $result_set = PhabricatorSearchService::newResultSet($query);
61 $phids = $result_set->getPHIDs();
62
63 $this->fulltextResultSet = $result_set;
64 $this->unfilteredOffset += count($phids);
65
66 $handles = id(new PhabricatorHandleQuery())
67 ->setViewer($this->getViewer())
68 ->requireObjectCapabilities($this->getRequiredObjectCapabilities())
69 ->withPHIDs($phids)
70 ->execute();
71
72 // Retain engine order.
73 $handles = array_select_keys($handles, $phids);
74
75 return $handles;
76 }
77
78 protected function willFilterPage(array $handles) {
79 // NOTE: This is used by the object selector dialog to exclude the object
80 // you're looking at, so that, e.g., a task can't be set as a dependency
81 // of itself in the UI.
82
83 // TODO: Remove this after object selection moves to ApplicationSearch.
84
85 $exclude = array();
86 if ($this->savedQuery) {
87 $exclude_phids = $this->savedQuery->getParameter('excludePHIDs', array());
88 $exclude = array_fuse($exclude_phids);
89 }
90
91 foreach ($handles as $key => $handle) {
92 if (!$handle->isComplete()) {
93 unset($handles[$key]);
94 continue;
95 }
96 if ($handle->getPolicyFiltered()) {
97 unset($handles[$key]);
98 continue;
99 }
100 if (isset($exclude[$handle->getPHID()])) {
101 unset($handles[$key]);
102 continue;
103 }
104 }
105
106 return $handles;
107 }
108
109 public function getQueryApplicationClass() {
110 return PhabricatorSearchApplication::class;
111 }
112
113 protected function nextPage(array $page) {
114 // We already updated the internal offset in `loadPage()` after loading
115 // results, so we do not need to make any additional state updates here.
116 }
117
118}