Correct Aphlict websocket URI construction after PHP8 compatibility changes
[phabricator.git] / src / infrastructure / customfield / standard / PhabricatorStandardCustomField.php
blob4c0bce861b124082e0a9cc4fdce325fe50e18fb0
1 <?php
3 abstract class PhabricatorStandardCustomField
4 extends PhabricatorCustomField {
6 private $rawKey;
7 private $fieldKey;
8 private $fieldName;
9 private $fieldValue;
10 private $fieldDescription;
11 private $fieldConfig;
12 private $applicationField;
13 private $strings = array();
14 private $caption;
15 private $fieldError;
16 private $required;
17 private $default;
18 private $isCopyable;
19 private $hasStorageValue;
20 private $isBuiltin;
21 private $isEnabled = true;
23 abstract public function getFieldType();
25 public static function buildStandardFields(
26 PhabricatorCustomField $template,
27 array $config,
28 $builtin = false) {
30 $types = id(new PhutilClassMapQuery())
31 ->setAncestorClass(__CLASS__)
32 ->setUniqueMethod('getFieldType')
33 ->execute();
35 $fields = array();
36 foreach ($config as $key => $value) {
37 $type = idx($value, 'type', 'text');
38 if (empty($types[$type])) {
39 // TODO: We should have better typechecking somewhere, and then make
40 // this more serious.
41 continue;
44 $namespace = $template->getStandardCustomFieldNamespace();
45 $full_key = "std:{$namespace}:{$key}";
47 $template = clone $template;
48 $standard = id(clone $types[$type])
49 ->setRawStandardFieldKey($key)
50 ->setFieldKey($full_key)
51 ->setFieldConfig($value)
52 ->setApplicationField($template);
54 if ($builtin) {
55 $standard->setIsBuiltin(true);
58 $field = $template->setProxy($standard);
59 $fields[] = $field;
62 return $fields;
65 public function setApplicationField(
66 PhabricatorStandardCustomFieldInterface $application_field) {
67 $this->applicationField = $application_field;
68 return $this;
71 public function getApplicationField() {
72 return $this->applicationField;
75 public function setFieldName($name) {
76 $this->fieldName = $name;
77 return $this;
80 public function getFieldValue() {
81 return $this->fieldValue;
84 public function setFieldValue($value) {
85 $this->fieldValue = $value;
86 return $this;
89 public function setCaption($caption) {
90 $this->caption = $caption;
91 return $this;
94 public function getCaption() {
95 return $this->caption;
98 public function setFieldDescription($description) {
99 $this->fieldDescription = $description;
100 return $this;
103 public function setIsBuiltin($is_builtin) {
104 $this->isBuiltin = $is_builtin;
105 return $this;
108 public function getIsBuiltin() {
109 return $this->isBuiltin;
112 public function setFieldConfig(array $config) {
113 foreach ($config as $key => $value) {
114 switch ($key) {
115 case 'name':
116 $this->setFieldName($value);
117 break;
118 case 'description':
119 $this->setFieldDescription($value);
120 break;
121 case 'strings':
122 $this->setStrings($value);
123 break;
124 case 'caption':
125 $this->setCaption($value);
126 break;
127 case 'required':
128 if ($value) {
129 $this->setRequired($value);
130 $this->setFieldError(true);
132 break;
133 case 'default':
134 $this->setFieldValue($value);
135 break;
136 case 'copy':
137 $this->setIsCopyable($value);
138 break;
139 case 'type':
140 // We set this earlier on.
141 break;
144 $this->fieldConfig = $config;
145 return $this;
148 public function getFieldConfigValue($key, $default = null) {
149 return idx($this->fieldConfig, $key, $default);
152 public function setFieldError($field_error) {
153 $this->fieldError = $field_error;
154 return $this;
157 public function getFieldError() {
158 return $this->fieldError;
161 public function setRequired($required) {
162 $this->required = $required;
163 return $this;
166 public function getRequired() {
167 return $this->required;
170 public function setRawStandardFieldKey($raw_key) {
171 $this->rawKey = $raw_key;
172 return $this;
175 public function getRawStandardFieldKey() {
176 return $this->rawKey;
179 public function setIsEnabled($is_enabled) {
180 $this->isEnabled = $is_enabled;
181 return $this;
184 public function getIsEnabled() {
185 return $this->isEnabled;
188 public function isFieldEnabled() {
189 return $this->getIsEnabled();
193 /* -( PhabricatorCustomField )--------------------------------------------- */
196 public function setFieldKey($field_key) {
197 $this->fieldKey = $field_key;
198 return $this;
201 public function getFieldKey() {
202 return $this->fieldKey;
205 public function getFieldName() {
206 return coalesce($this->fieldName, parent::getFieldName());
209 public function getFieldDescription() {
210 return coalesce($this->fieldDescription, parent::getFieldDescription());
213 public function setStrings(array $strings) {
214 $this->strings = $strings;
215 return;
218 public function getString($key, $default = null) {
219 return idx($this->strings, $key, $default);
222 public function setIsCopyable($is_copyable) {
223 $this->isCopyable = $is_copyable;
224 return $this;
227 public function getIsCopyable() {
228 return $this->isCopyable;
231 public function shouldUseStorage() {
232 try {
233 $object = $this->newStorageObject();
234 return true;
235 } catch (PhabricatorCustomFieldImplementationIncompleteException $ex) {
236 return false;
240 public function getValueForStorage() {
241 return $this->getFieldValue();
244 public function setValueFromStorage($value) {
245 return $this->setFieldValue($value);
248 public function didSetValueFromStorage() {
249 $this->hasStorageValue = true;
250 return $this;
253 public function getOldValueForApplicationTransactions() {
254 if ($this->hasStorageValue) {
255 return $this->getValueForStorage();
256 } else {
257 return null;
261 public function shouldAppearInApplicationTransactions() {
262 return true;
265 public function shouldAppearInEditView() {
266 return $this->getFieldConfigValue('edit', true);
269 public function readValueFromRequest(AphrontRequest $request) {
270 $value = $request->getStr($this->getFieldKey());
271 if (!strlen($value)) {
272 $value = null;
274 $this->setFieldValue($value);
277 public function getInstructionsForEdit() {
278 return $this->getFieldConfigValue('instructions');
281 public function getPlaceholder() {
282 return $this->getFieldConfigValue('placeholder', null);
285 public function renderEditControl(array $handles) {
286 return id(new AphrontFormTextControl())
287 ->setName($this->getFieldKey())
288 ->setCaption($this->getCaption())
289 ->setValue($this->getFieldValue())
290 ->setError($this->getFieldError())
291 ->setLabel($this->getFieldName())
292 ->setPlaceholder($this->getPlaceholder());
295 public function newStorageObject() {
296 return $this->getApplicationField()->newStorageObject();
299 public function shouldAppearInPropertyView() {
300 return $this->getFieldConfigValue('view', true);
303 public function renderPropertyViewValue(array $handles) {
304 if (!strlen($this->getFieldValue())) {
305 return null;
307 return $this->getFieldValue();
310 public function shouldAppearInApplicationSearch() {
311 return $this->getFieldConfigValue('search', false);
314 protected function newStringIndexStorage() {
315 return $this->getApplicationField()->newStringIndexStorage();
318 protected function newNumericIndexStorage() {
319 return $this->getApplicationField()->newNumericIndexStorage();
322 public function buildFieldIndexes() {
323 return array();
326 public function buildOrderIndex() {
327 return null;
330 public function readApplicationSearchValueFromRequest(
331 PhabricatorApplicationSearchEngine $engine,
332 AphrontRequest $request) {
333 return;
336 public function applyApplicationSearchConstraintToQuery(
337 PhabricatorApplicationSearchEngine $engine,
338 PhabricatorCursorPagedPolicyAwareQuery $query,
339 $value) {
340 return;
343 public function appendToApplicationSearchForm(
344 PhabricatorApplicationSearchEngine $engine,
345 AphrontFormView $form,
346 $value) {
347 return;
350 public function validateApplicationTransactions(
351 PhabricatorApplicationTransactionEditor $editor,
352 $type,
353 array $xactions) {
355 $this->setFieldError(null);
357 $errors = parent::validateApplicationTransactions(
358 $editor,
359 $type,
360 $xactions);
362 if ($this->getRequired()) {
363 $value = $this->getOldValueForApplicationTransactions();
365 $transaction = null;
366 foreach ($xactions as $xaction) {
367 $value = $xaction->getNewValue();
368 if (!$this->isValueEmpty($value)) {
369 $transaction = $xaction;
370 break;
373 if ($this->isValueEmpty($value)) {
374 $error = new PhabricatorApplicationTransactionValidationError(
375 $type,
376 pht('Required'),
377 pht('%s is required.', $this->getFieldName()),
378 $transaction);
379 $error->setIsMissingFieldError(true);
380 $errors[] = $error;
381 $this->setFieldError(pht('Required'));
385 return $errors;
388 protected function isValueEmpty($value) {
389 if (is_array($value)) {
390 return empty($value);
392 return !strlen($value);
395 public function getApplicationTransactionTitle(
396 PhabricatorApplicationTransaction $xaction) {
397 $author_phid = $xaction->getAuthorPHID();
398 $old = $xaction->getOldValue();
399 $new = $xaction->getNewValue();
401 if (!$old) {
402 return pht(
403 '%s set %s to %s.',
404 $xaction->renderHandleLink($author_phid),
405 $this->getFieldName(),
406 $new);
407 } else if (!$new) {
408 return pht(
409 '%s removed %s.',
410 $xaction->renderHandleLink($author_phid),
411 $this->getFieldName());
412 } else {
413 return pht(
414 '%s changed %s from %s to %s.',
415 $xaction->renderHandleLink($author_phid),
416 $this->getFieldName(),
417 $old,
418 $new);
422 public function getApplicationTransactionTitleForFeed(
423 PhabricatorApplicationTransaction $xaction) {
425 $author_phid = $xaction->getAuthorPHID();
426 $object_phid = $xaction->getObjectPHID();
428 $old = $xaction->getOldValue();
429 $new = $xaction->getNewValue();
431 if (!$old) {
432 return pht(
433 '%s set %s to %s on %s.',
434 $xaction->renderHandleLink($author_phid),
435 $this->getFieldName(),
436 $new,
437 $xaction->renderHandleLink($object_phid));
438 } else if (!$new) {
439 return pht(
440 '%s removed %s on %s.',
441 $xaction->renderHandleLink($author_phid),
442 $this->getFieldName(),
443 $xaction->renderHandleLink($object_phid));
444 } else {
445 return pht(
446 '%s changed %s from %s to %s on %s.',
447 $xaction->renderHandleLink($author_phid),
448 $this->getFieldName(),
449 $old,
450 $new,
451 $xaction->renderHandleLink($object_phid));
455 public function getHeraldFieldValue() {
456 return $this->getFieldValue();
459 public function getFieldControlID($key = null) {
460 $key = coalesce($key, $this->getRawStandardFieldKey());
461 return 'std:control:'.$key;
464 public function shouldAppearInGlobalSearch() {
465 return $this->getFieldConfigValue('fulltext', false);
468 public function updateAbstractDocument(
469 PhabricatorSearchAbstractDocument $document) {
471 $field_key = $this->getFieldConfigValue('fulltext');
473 // If the caller or configuration didn't specify a valid field key,
474 // generate one automatically from the field index.
475 if (!is_string($field_key) || (strlen($field_key) != 4)) {
476 $field_key = '!'.substr($this->getFieldIndex(), 0, 3);
479 $field_value = $this->getFieldValue();
480 if (strlen($field_value)) {
481 $document->addField($field_key, $field_value);
485 protected function newStandardEditField() {
486 $short = $this->getModernFieldKey();
488 return parent::newStandardEditField()
489 ->setEditTypeKey($short)
490 ->setIsCopyable($this->getIsCopyable());
493 public function shouldAppearInConduitTransactions() {
494 return true;
497 public function shouldAppearInConduitDictionary() {
498 return true;
501 public function getModernFieldKey() {
502 if ($this->getIsBuiltin()) {
503 return $this->getRawStandardFieldKey();
504 } else {
505 return 'custom.'.$this->getRawStandardFieldKey();
509 public function getConduitDictionaryValue() {
510 return $this->getFieldValue();
513 public function newExportData() {
514 return $this->getFieldValue();