@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
fork

Configure Feed

Select the types of activity you want to include in your feed.

Support HTTP parameter prefilling in EditEngine forms for CustomFields

Summary:
Ref T9132. This allows you to prefill custom fields with `?custom.x.y=value`, for most types of custom fields.

Dates (which are substantially more complicated) aren't supported. I'll just do those once the dust settles. Other types should work, I think.

Test Plan:
- Verified custom fields appear on "HTTP Parameters" help UI.
- Used `?x=y` to prefill custom fields on edit form.
- Performed various normal edits.

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T9132

Differential Revision: https://secure.phabricator.com/D14634

+188 -31
+4
src/__phutil_library_map__.php
··· 103 103 'AphrontAjaxResponse' => 'aphront/response/AphrontAjaxResponse.php', 104 104 'AphrontApplicationConfiguration' => 'aphront/configuration/AphrontApplicationConfiguration.php', 105 105 'AphrontBarView' => 'view/widget/bars/AphrontBarView.php', 106 + 'AphrontBoolHTTPParameterType' => 'aphront/httpparametertype/AphrontBoolHTTPParameterType.php', 106 107 'AphrontCSRFException' => 'aphront/exception/AphrontCSRFException.php', 107 108 'AphrontCalendarEventView' => 'applications/calendar/view/AphrontCalendarEventView.php', 108 109 'AphrontController' => 'aphront/AphrontController.php', ··· 139 140 'AphrontHTTPProxyResponse' => 'aphront/response/AphrontHTTPProxyResponse.php', 140 141 'AphrontHTTPSink' => 'aphront/sink/AphrontHTTPSink.php', 141 142 'AphrontHTTPSinkTestCase' => 'aphront/sink/__tests__/AphrontHTTPSinkTestCase.php', 143 + 'AphrontIntHTTPParameterType' => 'aphront/httpparametertype/AphrontIntHTTPParameterType.php', 142 144 'AphrontIsolatedDatabaseConnectionTestCase' => 'infrastructure/storage/__tests__/AphrontIsolatedDatabaseConnectionTestCase.php', 143 145 'AphrontIsolatedHTTPSink' => 'aphront/sink/AphrontIsolatedHTTPSink.php', 144 146 'AphrontJSONResponse' => 'aphront/response/AphrontJSONResponse.php', ··· 3907 3909 'AphrontAjaxResponse' => 'AphrontResponse', 3908 3910 'AphrontApplicationConfiguration' => 'Phobject', 3909 3911 'AphrontBarView' => 'AphrontView', 3912 + 'AphrontBoolHTTPParameterType' => 'AphrontHTTPParameterType', 3910 3913 'AphrontCSRFException' => 'AphrontException', 3911 3914 'AphrontCalendarEventView' => 'AphrontView', 3912 3915 'AphrontController' => 'Phobject', ··· 3946 3949 'AphrontHTTPProxyResponse' => 'AphrontResponse', 3947 3950 'AphrontHTTPSink' => 'Phobject', 3948 3951 'AphrontHTTPSinkTestCase' => 'PhabricatorTestCase', 3952 + 'AphrontIntHTTPParameterType' => 'AphrontHTTPParameterType', 3949 3953 'AphrontIsolatedDatabaseConnectionTestCase' => 'PhabricatorTestCase', 3950 3954 'AphrontIsolatedHTTPSink' => 'AphrontHTTPSink', 3951 3955 'AphrontJSONResponse' => 'AphrontResponse',
+29
src/aphront/httpparametertype/AphrontBoolHTTPParameterType.php
··· 1 + <?php 2 + 3 + final class AphrontBoolHTTPParameterType 4 + extends AphrontHTTPParameterType { 5 + 6 + protected function getParameterValue(AphrontRequest $request, $key) { 7 + return $request->getBool($key); 8 + } 9 + 10 + protected function getParameterTypeName() { 11 + return 'bool'; 12 + } 13 + 14 + protected function getParameterFormatDescriptions() { 15 + return array( 16 + pht('A boolean value (true or false).'), 17 + ); 18 + } 19 + 20 + protected function getParameterExamples() { 21 + return array( 22 + 'v=true', 23 + 'v=false', 24 + 'v=1', 25 + 'v=0', 26 + ); 27 + } 28 + 29 + }
+26
src/aphront/httpparametertype/AphrontIntHTTPParameterType.php
··· 1 + <?php 2 + 3 + final class AphrontIntHTTPParameterType 4 + extends AphrontHTTPParameterType { 5 + 6 + protected function getParameterValue(AphrontRequest $request, $key) { 7 + return $request->getInt($key); 8 + } 9 + 10 + protected function getParameterTypeName() { 11 + return 'int'; 12 + } 13 + 14 + protected function getParameterFormatDescriptions() { 15 + return array( 16 + pht('An integer.'), 17 + ); 18 + } 19 + 20 + protected function getParameterExamples() { 21 + return array( 22 + 'v=123', 23 + ); 24 + } 25 + 26 + }
-4
src/applications/transactions/editengine/PhabricatorEditEngine.php
··· 685 685 686 686 $field->readValueFromRequest($request); 687 687 } 688 - } else { 689 - foreach ($fields as $field) { 690 - $field->readValueFromObject($object); 691 - } 692 688 } 693 689 } 694 690
+31 -12
src/applications/transactions/editfield/PhabricatorEditField.php
··· 299 299 } 300 300 301 301 public function readValueFromRequest(AphrontRequest $request) { 302 - $check = array_merge(array($this->getKey()), $this->getAliases()); 302 + $check = $this->getAllReadValueFromRequestKeys(); 303 303 foreach ($check as $key) { 304 304 if (!$this->getValueExistsInRequest($request, $key)) { 305 305 continue; 306 306 } 307 307 308 308 $this->value = $this->getValueFromRequest($request, $key); 309 - return; 309 + break; 310 310 } 311 - 312 - $this->readValueFromObject($this->getObject()); 313 - 314 311 return $this; 315 312 } 316 313 317 - public function readValueFromObject($object) { 318 - $this->value = $this->getValueFromObject($object); 319 - return $this; 314 + public function getAllReadValueFromRequestKeys() { 315 + $keys = array(); 316 + 317 + $keys[] = $this->getKey(); 318 + foreach ($this->getAliases() as $alias) { 319 + $keys[] = $alias; 320 + } 321 + 322 + return $keys; 320 323 } 321 324 322 325 public function readDefaultValueFromConfiguration($value) { ··· 337 340 } 338 341 339 342 protected function getValueExistsInRequest(AphrontRequest $request, $key) { 340 - return $this->getValueExistsInSubmit($request, $key); 343 + return $this->getHTTPParameterValueExists($request, $key); 341 344 } 342 345 343 346 protected function getValueFromRequest(AphrontRequest $request, $key) { 344 - return $this->getValueFromSubmit($request, $key); 347 + return $this->getHTTPParameterValue($request, $key); 345 348 } 346 349 347 350 ··· 385 388 } 386 389 387 390 protected function getValueExistsInSubmit(AphrontRequest $request, $key) { 391 + return $this->getHTTPParameterValueExists($request, $key); 392 + } 393 + 394 + protected function getValueFromSubmit(AphrontRequest $request, $key) { 395 + return $this->getHTTPParameterValue($request, $key); 396 + } 397 + 398 + protected function getHTTPParameterValueExists( 399 + AphrontRequest $request, 400 + $key) { 388 401 $type = $this->getHTTPParameterType(); 389 402 390 403 if ($type) { ··· 394 407 return false; 395 408 } 396 409 397 - protected function getValueFromSubmit(AphrontRequest $request, $key) { 398 - return $this->getHTTPParameterType()->getValue($request, $key); 410 + protected function getHTTPParameterValue($request, $key) { 411 + $type = $this->getHTTPParameterType(); 412 + 413 + if ($type) { 414 + return $type->getValue($request, $key); 415 + } 416 + 417 + return null; 399 418 } 400 419 401 420 protected function getDefaultValue() {
+2 -2
src/applications/transactions/view/PhabricatorApplicationEditHTTPParameterHelpView.php
··· 95 95 foreach ($fields as $field) { 96 96 $rows[] = array( 97 97 $field->getLabel(), 98 - $field->getKey(), 98 + head($field->getAllReadValueFromRequestKeys()), 99 99 $field->getHTTPParameterType()->getTypeName(), 100 100 $field->getDescription(), 101 101 ); ··· 150 150 151 151 $rows = array(); 152 152 foreach ($fields as $field) { 153 - $aliases = $field->getAliases(); 153 + $aliases = array_slice($field->getAllReadValueFromRequestKeys(), 1); 154 154 if (!$aliases) { 155 155 continue; 156 156 }
+4 -1
src/infrastructure/customfield/editor/PhabricatorCustomFieldEditEngineExtension.php
··· 34 34 PhabricatorCustomField::ROLE_EDIT); 35 35 36 36 $field_list->setViewer($viewer); 37 - $field_list->readFieldsFromStorage($object); 37 + 38 + if (!$engine->getIsCreate()) { 39 + $field_list->readFieldsFromStorage($object); 40 + } 38 41 39 42 $results = array(); 40 43 foreach ($field_list->getFields() as $field) {
+37 -10
src/infrastructure/customfield/editor/PhabricatorCustomFieldEditField.php
··· 4 4 extends PhabricatorEditField { 5 5 6 6 private $customField; 7 + private $httpParameterType; 7 8 8 9 public function setCustomField(PhabricatorCustomField $custom_field) { 9 10 $this->customField = $custom_field; ··· 14 15 return $this->customField; 15 16 } 16 17 18 + public function setCustomFieldHTTPParameterType( 19 + AphrontHTTPParameterType $type) { 20 + $this->httpParameterType = $type; 21 + return $this; 22 + } 23 + 24 + public function getCustomFieldHTTPParameterType() { 25 + return $this->httpParameterType; 26 + } 27 + 17 28 protected function buildControl() { 18 29 $field = $this->getCustomField(); 19 30 $clone = clone $field; 20 31 21 - if ($this->getIsSubmittedForm()) { 22 - $value = $this->getValue(); 23 - $clone->setValueFromApplicationTransactions($value); 24 - } 32 + $value = $this->getValue(); 33 + $clone->setValueFromApplicationTransactions($value); 25 34 26 35 return $clone->renderEditControl(array()); 27 36 } ··· 42 51 return $clone->getNewValueForApplicationTransactions(); 43 52 } 44 53 45 - protected function getValueExistsInRequest(AphrontRequest $request, $key) { 46 - // For now, never read these out of the request. 47 - return false; 48 - } 49 - 50 54 protected function getValueExistsInSubmit(AphrontRequest $request, $key) { 51 55 return true; 52 56 } ··· 66 70 } 67 71 68 72 protected function newHTTPParameterType() { 69 - // TODO: For now, don't support custom fields for HTTP prefill. 73 + $type = $this->getCustomFieldHTTPParameterType(); 74 + 75 + if ($type) { 76 + return clone $type; 77 + } 78 + 70 79 return null; 80 + } 81 + 82 + public function getAllReadValueFromRequestKeys() { 83 + $keys = array(); 84 + 85 + // NOTE: This piece of complexity is so we can expose a reasonable key in 86 + // the UI ("custom.x") instead of a crufty internal key ("std:app:x"). 87 + // Perhaps we can simplify this some day. 88 + 89 + // In the parent, this is just getKey(), but that returns a cumbersome 90 + // key in EditFields. Use the simpler edit type key instead. 91 + $keys[] = $this->getEditTypeKey(); 92 + 93 + foreach ($this->getAliases() as $alias) { 94 + $keys[] = $alias; 95 + } 96 + 97 + return $keys; 71 98 } 72 99 73 100 }
+15 -1
src/infrastructure/customfield/field/PhabricatorCustomField.php
··· 1091 1091 } 1092 1092 1093 1093 protected function newEditField() { 1094 - return id(new PhabricatorCustomFieldEditField()) 1094 + $field = id(new PhabricatorCustomFieldEditField()) 1095 1095 ->setCustomField($this); 1096 + 1097 + $http_type = $this->getHTTPParameterType(); 1098 + if ($http_type) { 1099 + $field->setCustomFieldHTTPParameterType($http_type); 1100 + } 1101 + 1102 + return $field; 1096 1103 } 1097 1104 1098 1105 protected function newStandardEditField() { ··· 1107 1114 ->setDescription($this->getFieldDescription()) 1108 1115 ->setTransactionType($this->getApplicationTransactionType()) 1109 1116 ->setValue($this->getNewValueForApplicationTransactions()); 1117 + } 1118 + 1119 + protected function getHTTPParameterType() { 1120 + if ($this->proxy) { 1121 + return $this->proxy->getHTTPParameterType(); 1122 + } 1123 + return null; 1110 1124 } 1111 1125 1112 1126 /**
+4
src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldBool.php
··· 129 129 ); 130 130 } 131 131 132 + protected function getHTTPParameterType() { 133 + return new AphrontBoolHTTPParameterType(); 134 + } 135 + 132 136 }
+4
src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldInt.php
··· 112 112 } 113 113 } 114 114 115 + protected function getHTTPParameterType() { 116 + return new AphrontIntHTTPParameterType(); 117 + } 118 + 115 119 116 120 }
+4
src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldLink.php
··· 80 80 ); 81 81 } 82 82 83 + protected function getHTTPParameterType() { 84 + return new AphrontStringHTTPParameterType(); 85 + } 86 + 83 87 }
+12 -1
src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldPHIDs.php
··· 34 34 } 35 35 36 36 public function setValueFromStorage($value) { 37 + // NOTE: We're accepting either a JSON string (a real storage value) or 38 + // an array (from HTTP parameter prefilling). This is a little hacky, but 39 + // should hold until this can get cleaned up more thoroughly. 40 + // TODO: Clean this up. 41 + 37 42 $result = array(); 38 - if ($value) { 43 + if (!is_array($value)) { 39 44 $value = json_decode($value, true); 40 45 if (is_array($value)) { 41 46 $result = array_values($value); 42 47 } 43 48 } 49 + 44 50 $this->setFieldValue($value); 51 + 45 52 return $this; 46 53 } 47 54 ··· 211 218 } 212 219 213 220 return $value; 221 + } 222 + 223 + protected function getHTTPParameterType() { 224 + return new AphrontPHIDListHTTPParameterType(); 214 225 } 215 226 216 227 }
+4
src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldRemarkup.php
··· 95 95 ); 96 96 } 97 97 98 + protected function getHTTPParameterType() { 99 + return new AphrontStringHTTPParameterType(); 100 + } 101 + 98 102 99 103 }
+4
src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldSelect.php
··· 136 136 ->setValueMap($this->getOptions()); 137 137 } 138 138 139 + protected function getHTTPParameterType() { 140 + return new AphrontSelectHTTPParameterType(); 141 + } 142 + 139 143 }
+4
src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldText.php
··· 63 63 ); 64 64 } 65 65 66 + protected function getHTTPParameterType() { 67 + return new AphrontStringHTTPParameterType(); 68 + } 69 + 66 70 }
+4
src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldUsers.php
··· 11 11 return new PhabricatorPeopleDatasource(); 12 12 } 13 13 14 + protected function getHTTPParameterType() { 15 + return new AphrontUserListHTTPParameterType(); 16 + } 17 + 14 18 }