3 abstract class PhabricatorStandardCustomField
4 extends PhabricatorCustomField
{
10 private $fieldDescription;
12 private $applicationField;
13 private $strings = array();
19 private $hasStorageValue;
21 private $isEnabled = true;
23 abstract public function getFieldType();
25 public static function buildStandardFields(
26 PhabricatorCustomField
$template,
30 $types = id(new PhutilClassMapQuery())
31 ->setAncestorClass(__CLASS__
)
32 ->setUniqueMethod('getFieldType')
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
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);
55 $standard->setIsBuiltin(true);
58 $field = $template->setProxy($standard);
65 public function setApplicationField(
66 PhabricatorStandardCustomFieldInterface
$application_field) {
67 $this->applicationField
= $application_field;
71 public function getApplicationField() {
72 return $this->applicationField
;
75 public function setFieldName($name) {
76 $this->fieldName
= $name;
80 public function getFieldValue() {
81 return $this->fieldValue
;
84 public function setFieldValue($value) {
85 $this->fieldValue
= $value;
89 public function setCaption($caption) {
90 $this->caption
= $caption;
94 public function getCaption() {
95 return $this->caption
;
98 public function setFieldDescription($description) {
99 $this->fieldDescription
= $description;
103 public function setIsBuiltin($is_builtin) {
104 $this->isBuiltin
= $is_builtin;
108 public function getIsBuiltin() {
109 return $this->isBuiltin
;
112 public function setFieldConfig(array $config) {
113 foreach ($config as $key => $value) {
116 $this->setFieldName($value);
119 $this->setFieldDescription($value);
122 $this->setStrings($value);
125 $this->setCaption($value);
129 $this->setRequired($value);
130 $this->setFieldError(true);
134 $this->setFieldValue($value);
137 $this->setIsCopyable($value);
140 // We set this earlier on.
144 $this->fieldConfig
= $config;
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;
157 public function getFieldError() {
158 return $this->fieldError
;
161 public function setRequired($required) {
162 $this->required
= $required;
166 public function getRequired() {
167 return $this->required
;
170 public function setRawStandardFieldKey($raw_key) {
171 $this->rawKey
= $raw_key;
175 public function getRawStandardFieldKey() {
176 return $this->rawKey
;
179 public function setIsEnabled($is_enabled) {
180 $this->isEnabled
= $is_enabled;
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;
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;
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;
227 public function getIsCopyable() {
228 return $this->isCopyable
;
231 public function shouldUseStorage() {
233 $object = $this->newStorageObject();
235 } catch (PhabricatorCustomFieldImplementationIncompleteException
$ex) {
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;
253 public function getOldValueForApplicationTransactions() {
254 if ($this->hasStorageValue
) {
255 return $this->getValueForStorage();
261 public function shouldAppearInApplicationTransactions() {
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)) {
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())) {
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() {
326 public function buildOrderIndex() {
330 public function readApplicationSearchValueFromRequest(
331 PhabricatorApplicationSearchEngine
$engine,
332 AphrontRequest
$request) {
336 public function applyApplicationSearchConstraintToQuery(
337 PhabricatorApplicationSearchEngine
$engine,
338 PhabricatorCursorPagedPolicyAwareQuery
$query,
343 public function appendToApplicationSearchForm(
344 PhabricatorApplicationSearchEngine
$engine,
345 AphrontFormView
$form,
350 public function validateApplicationTransactions(
351 PhabricatorApplicationTransactionEditor
$editor,
355 $this->setFieldError(null);
357 $errors = parent
::validateApplicationTransactions(
362 if ($this->getRequired()) {
363 $value = $this->getOldValueForApplicationTransactions();
366 foreach ($xactions as $xaction) {
367 $value = $xaction->getNewValue();
368 if (!$this->isValueEmpty($value)) {
369 $transaction = $xaction;
373 if ($this->isValueEmpty($value)) {
374 $error = new PhabricatorApplicationTransactionValidationError(
377 pht('%s is required.', $this->getFieldName()),
379 $error->setIsMissingFieldError(true);
381 $this->setFieldError(pht('Required'));
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();
404 $xaction->renderHandleLink($author_phid),
405 $this->getFieldName(),
410 $xaction->renderHandleLink($author_phid),
411 $this->getFieldName());
414 '%s changed %s from %s to %s.',
415 $xaction->renderHandleLink($author_phid),
416 $this->getFieldName(),
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();
433 '%s set %s to %s on %s.',
434 $xaction->renderHandleLink($author_phid),
435 $this->getFieldName(),
437 $xaction->renderHandleLink($object_phid));
440 '%s removed %s on %s.',
441 $xaction->renderHandleLink($author_phid),
442 $this->getFieldName(),
443 $xaction->renderHandleLink($object_phid));
446 '%s changed %s from %s to %s on %s.',
447 $xaction->renderHandleLink($author_phid),
448 $this->getFieldName(),
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() {
497 public function shouldAppearInConduitDictionary() {
501 public function getModernFieldKey() {
502 if ($this->getIsBuiltin()) {
503 return $this->getRawStandardFieldKey();
505 return 'custom.'.$this->getRawStandardFieldKey();
509 public function getConduitDictionaryValue() {
510 return $this->getFieldValue();
513 public function newExportData() {
514 return $this->getFieldValue();