@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 PhabricatorStandardCustomFieldDate
4 extends PhabricatorStandardCustomField {
5
6 public function getFieldType() {
7 return 'date';
8 }
9
10 public function buildFieldIndexes() {
11 $indexes = array();
12
13 $value = $this->getFieldValue();
14 if (phutil_nonempty_scalar($value)) {
15 $indexes[] = $this->newNumericIndex((int)$value);
16 }
17
18 return $indexes;
19 }
20
21 public function buildOrderIndex() {
22 return $this->newNumericIndex(0);
23 }
24
25 public function getValueForStorage() {
26 $value = $this->getFieldValue();
27 if (phutil_nonempty_scalar($value)) {
28 return (int)$value;
29 } else {
30 return null;
31 }
32 }
33
34 public function setValueFromStorage($value) {
35 if (phutil_nonempty_scalar($value)) {
36 $value = (int)$value;
37 } else {
38 $value = null;
39 }
40 return $this->setFieldValue($value);
41 }
42
43 public function renderEditControl(array $handles) {
44 return $this->newDateControl();
45 }
46
47 public function readValueFromRequest(AphrontRequest $request) {
48 $control = $this->newDateControl();
49 $control->setViewer($request->getUser());
50 $value = $control->readValueFromRequest($request);
51
52 $this->setFieldValue($value);
53 }
54
55 protected function renderValue() {
56 $value = $this->getFieldValue();
57 if (!$value) {
58 return null;
59 }
60
61 return phabricator_datetime($value, $this->getViewer());
62 }
63
64 private function newDateControl() {
65 $control = id(new AphrontFormDateControl())
66 ->setLabel($this->getFieldName())
67 ->setName($this->getFieldKey())
68 ->setViewer($this->getViewer())
69 ->setCaption($this->getCaption())
70 ->setAllowNull(!$this->getRequired());
71
72 // If the value is already numeric, treat it as an epoch timestamp and set
73 // it directly. Otherwise, it's likely a field default, which we let users
74 // specify as a string. Parse the string into an epoch.
75
76 $value = $this->getFieldValue();
77 if ($value !== null && gettype($value) !== 'integer' &&
78 !ctype_digit($value)) {
79 $value = PhabricatorTime::parseLocalTime($value, $this->getViewer());
80 }
81
82 // If we don't have anything valid, make sure we pass `null`, since the
83 // control special-cases that.
84 $control->setValue(nonempty($value, null));
85
86 return $control;
87 }
88
89 public function readApplicationSearchValueFromRequest(
90 PhabricatorApplicationSearchEngine $engine,
91 AphrontRequest $request) {
92
93 $key = $this->getFieldKey();
94
95 return array(
96 'min' => $request->getStr($key.'.min'),
97 'max' => $request->getStr($key.'.max'),
98 );
99 }
100
101 public function applyApplicationSearchConstraintToQuery(
102 PhabricatorApplicationSearchEngine $engine,
103 PhabricatorCursorPagedPolicyAwareQuery $query,
104 $value) {
105
106 $viewer = $this->getViewer();
107
108 if (!is_array($value)) {
109 $value = array();
110 }
111
112 $min_str = idx($value, 'min', '');
113 if (phutil_nonempty_string($min_str)) {
114 $min = PhabricatorTime::parseLocalTime($min_str, $viewer);
115 } else {
116 $min = null;
117 }
118
119 $max_str = idx($value, 'max', '');
120 if (phutil_nonempty_string($max_str)) {
121 $max = PhabricatorTime::parseLocalTime($max_str, $viewer);
122 } else {
123 $max = null;
124 }
125
126 if (($min !== null) || ($max !== null)) {
127 $query->withApplicationSearchRangeConstraint(
128 $this->newNumericIndex(null),
129 $min,
130 $max);
131 }
132 }
133
134 public function appendToApplicationSearchForm(
135 PhabricatorApplicationSearchEngine $engine,
136 AphrontFormView $form,
137 $value) {
138
139 if (!is_array($value)) {
140 $value = array();
141 }
142
143 $form
144 ->appendChild(
145 id(new AphrontFormTextControl())
146 ->setLabel(pht('%s After', $this->getFieldName()))
147 ->setName($this->getFieldKey().'.min')
148 ->setValue(idx($value, 'min', '')))
149 ->appendChild(
150 id(new AphrontFormTextControl())
151 ->setLabel(pht('%s Before', $this->getFieldName()))
152 ->setName($this->getFieldKey().'.max')
153 ->setValue(idx($value, 'max', '')));
154 }
155
156 public function getApplicationTransactionTitle(
157 PhabricatorApplicationTransaction $xaction) {
158 $author_phid = $xaction->getAuthorPHID();
159 $old = $xaction->getOldValue();
160 $new = $xaction->getNewValue();
161
162 $viewer = $this->getViewer();
163
164 $old_date = null;
165 if ($old) {
166 $old_date = phabricator_datetime($old, $viewer);
167 }
168
169 $new_date = null;
170 if ($new) {
171 $new_date = phabricator_datetime($new, $viewer);
172 }
173
174 if (!$old) {
175 return pht(
176 '%s set %s to %s.',
177 $xaction->renderHandleLink($author_phid),
178 $this->getFieldName(),
179 $new_date);
180 } else if (!$new && $old) {
181 return pht(
182 '%s removed %s which was set to %s.',
183 $xaction->renderHandleLink($author_phid),
184 $this->getFieldName(),
185 $old_date);
186 } else if (!$new) {
187 return pht(
188 '%s removed %s.',
189 $xaction->renderHandleLink($author_phid),
190 $this->getFieldName());
191 } else {
192 return pht(
193 '%s changed %s from %s to %s.',
194 $xaction->renderHandleLink($author_phid),
195 $this->getFieldName(),
196 $old_date,
197 $new_date);
198 }
199 }
200
201 public function getApplicationTransactionTitleForFeed(
202 PhabricatorApplicationTransaction $xaction) {
203
204 $viewer = $this->getViewer();
205
206 $author_phid = $xaction->getAuthorPHID();
207 $object_phid = $xaction->getObjectPHID();
208
209 $old = $xaction->getOldValue();
210 $new = $xaction->getNewValue();
211
212 if (!$old) {
213 return pht(
214 '%s set %s to %s on %s.',
215 $xaction->renderHandleLink($author_phid),
216 $this->getFieldName(),
217 phabricator_datetime($new, $viewer),
218 $xaction->renderHandleLink($object_phid));
219 } else if (!$new) {
220 return pht(
221 '%s removed %s on %s.',
222 $xaction->renderHandleLink($author_phid),
223 $this->getFieldName(),
224 $xaction->renderHandleLink($object_phid));
225 } else {
226 return pht(
227 '%s changed %s from %s to %s on %s.',
228 $xaction->renderHandleLink($author_phid),
229 $this->getFieldName(),
230 phabricator_datetime($old, $viewer),
231 phabricator_datetime($new, $viewer),
232 $xaction->renderHandleLink($object_phid));
233 }
234 }
235
236 protected function newConduitSearchParameterType() {
237 // TODO: Build a new "pair<epoch|null, epoch|null>" type or similar.
238 return null;
239 }
240
241 protected function newConduitEditParameterType() {
242 return id(new ConduitEpochParameterType())
243 ->setAllowNull(!$this->getRequired());
244 }
245
246 protected function newExportFieldType() {
247 return new PhabricatorEpochExportField();
248 }
249
250}