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

Modularize complex HTTP parameter types

Summary:
Ref T9132. We have several places in the code that sometimes need to parse complex types. For example, we accept all of these in ApplicationSearch and now in ApplicationEditor:

> /?subscribers=cat,dog
> /?subscribers=PHID-USER-1111
> /?subscribers[]=cat&subscribers[]=PHID-USER-2222

..etc. The logic to parse this stuff isn't too complex, but it isn't trivial either.

Right now it lives in some odd places. Notably, `PhabricatorApplicationSearchEngine` has some weird helper methods for this stuff. Rather than give `EditEngine` the same set of weird helper methods, pull all this stuff out into "HTTPParameterTypes".

Future diffs will add "Projects" and "Users" types where all the custom parsing/lookup logic can live. Then eventually the Search stuff can reuse these.

Generally, this just breaks the code up into smaller pieces that have more specific responsibilities.

Test Plan: {F944142}

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T9132

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

+579 -106
+16
src/__phutil_library_map__.php
··· 135 135 'AphrontFormView' => 'view/form/AphrontFormView.php', 136 136 'AphrontGlyphBarView' => 'view/widget/bars/AphrontGlyphBarView.php', 137 137 'AphrontHTMLResponse' => 'aphront/response/AphrontHTMLResponse.php', 138 + 'AphrontHTTPParameterType' => 'aphront/httpparametertype/AphrontHTTPParameterType.php', 138 139 'AphrontHTTPProxyResponse' => 'aphront/response/AphrontHTTPProxyResponse.php', 139 140 'AphrontHTTPSink' => 'aphront/sink/AphrontHTTPSink.php', 140 141 'AphrontHTTPSinkTestCase' => 'aphront/sink/__tests__/AphrontHTTPSinkTestCase.php', ··· 149 150 'AphrontMultiColumnView' => 'view/layout/AphrontMultiColumnView.php', 150 151 'AphrontMySQLDatabaseConnectionTestCase' => 'infrastructure/storage/__tests__/AphrontMySQLDatabaseConnectionTestCase.php', 151 152 'AphrontNullView' => 'view/AphrontNullView.php', 153 + 'AphrontPHIDHTTPParameterType' => 'aphront/httpparametertype/AphrontPHIDHTTPParameterType.php', 154 + 'AphrontPHIDListHTTPParameterType' => 'aphront/httpparametertype/AphrontPHIDListHTTPParameterType.php', 152 155 'AphrontPHPHTTPSink' => 'aphront/sink/AphrontPHPHTTPSink.php', 153 156 'AphrontPageView' => 'view/page/AphrontPageView.php', 154 157 'AphrontPlainTextResponse' => 'aphront/response/AphrontPlainTextResponse.php', ··· 164 167 'AphrontResponseProducerInterface' => 'aphront/interface/AphrontResponseProducerInterface.php', 165 168 'AphrontRoutingMap' => 'aphront/site/AphrontRoutingMap.php', 166 169 'AphrontRoutingResult' => 'aphront/site/AphrontRoutingResult.php', 170 + 'AphrontSelectHTTPParameterType' => 'aphront/httpparametertype/AphrontSelectHTTPParameterType.php', 167 171 'AphrontSideNavFilterView' => 'view/layout/AphrontSideNavFilterView.php', 168 172 'AphrontSite' => 'aphront/site/AphrontSite.php', 169 173 'AphrontStackTraceView' => 'view/widget/AphrontStackTraceView.php', 170 174 'AphrontStandaloneHTMLResponse' => 'aphront/response/AphrontStandaloneHTMLResponse.php', 175 + 'AphrontStringHTTPParameterType' => 'aphront/httpparametertype/AphrontStringHTTPParameterType.php', 176 + 'AphrontStringListHTTPParameterType' => 'aphront/httpparametertype/AphrontStringListHTTPParameterType.php', 171 177 'AphrontTableView' => 'view/control/AphrontTableView.php', 172 178 'AphrontTagView' => 'view/AphrontTagView.php', 173 179 'AphrontTokenizerTemplateView' => 'view/control/AphrontTokenizerTemplateView.php', ··· 1889 1895 'PhabricatorConfigEntryQuery' => 'applications/config/query/PhabricatorConfigEntryQuery.php', 1890 1896 'PhabricatorConfigFileSource' => 'infrastructure/env/PhabricatorConfigFileSource.php', 1891 1897 'PhabricatorConfigGroupController' => 'applications/config/controller/PhabricatorConfigGroupController.php', 1898 + 'PhabricatorConfigHTTPParameterTypesModule' => 'applications/config/module/PhabricatorConfigHTTPParameterTypesModule.php', 1892 1899 'PhabricatorConfigHistoryController' => 'applications/config/controller/PhabricatorConfigHistoryController.php', 1893 1900 'PhabricatorConfigIgnoreController' => 'applications/config/controller/PhabricatorConfigIgnoreController.php', 1894 1901 'PhabricatorConfigIssueListController' => 'applications/config/controller/PhabricatorConfigIssueListController.php', ··· 2250 2257 'PhabricatorGlobalLock' => 'infrastructure/util/PhabricatorGlobalLock.php', 2251 2258 'PhabricatorGlobalUploadTargetView' => 'applications/files/view/PhabricatorGlobalUploadTargetView.php', 2252 2259 'PhabricatorGoogleAuthProvider' => 'applications/auth/provider/PhabricatorGoogleAuthProvider.php', 2260 + 'PhabricatorHTTPParameterTypeTableView' => 'applications/config/view/PhabricatorHTTPParameterTypeTableView.php', 2253 2261 'PhabricatorHandleList' => 'applications/phid/handle/pool/PhabricatorHandleList.php', 2254 2262 'PhabricatorHandleObjectSelectorDataView' => 'applications/phid/handle/view/PhabricatorHandleObjectSelectorDataView.php', 2255 2263 'PhabricatorHandlePool' => 'applications/phid/handle/pool/PhabricatorHandlePool.php', ··· 3866 3874 'AphrontFormView' => 'AphrontView', 3867 3875 'AphrontGlyphBarView' => 'AphrontBarView', 3868 3876 'AphrontHTMLResponse' => 'AphrontResponse', 3877 + 'AphrontHTTPParameterType' => 'Phobject', 3869 3878 'AphrontHTTPProxyResponse' => 'AphrontResponse', 3870 3879 'AphrontHTTPSink' => 'Phobject', 3871 3880 'AphrontHTTPSinkTestCase' => 'PhabricatorTestCase', ··· 3880 3889 'AphrontMultiColumnView' => 'AphrontView', 3881 3890 'AphrontMySQLDatabaseConnectionTestCase' => 'PhabricatorTestCase', 3882 3891 'AphrontNullView' => 'AphrontView', 3892 + 'AphrontPHIDHTTPParameterType' => 'AphrontHTTPParameterType', 3893 + 'AphrontPHIDListHTTPParameterType' => 'AphrontHTTPParameterType', 3883 3894 'AphrontPHPHTTPSink' => 'AphrontHTTPSink', 3884 3895 'AphrontPageView' => 'AphrontView', 3885 3896 'AphrontPlainTextResponse' => 'AphrontResponse', ··· 3897 3908 'AphrontResponse' => 'Phobject', 3898 3909 'AphrontRoutingMap' => 'Phobject', 3899 3910 'AphrontRoutingResult' => 'Phobject', 3911 + 'AphrontSelectHTTPParameterType' => 'AphrontHTTPParameterType', 3900 3912 'AphrontSideNavFilterView' => 'AphrontView', 3901 3913 'AphrontSite' => 'Phobject', 3902 3914 'AphrontStackTraceView' => 'AphrontView', 3903 3915 'AphrontStandaloneHTMLResponse' => 'AphrontHTMLResponse', 3916 + 'AphrontStringHTTPParameterType' => 'AphrontHTTPParameterType', 3917 + 'AphrontStringListHTTPParameterType' => 'AphrontHTTPParameterType', 3904 3918 'AphrontTableView' => 'AphrontView', 3905 3919 'AphrontTagView' => 'AphrontView', 3906 3920 'AphrontTokenizerTemplateView' => 'AphrontView', ··· 5889 5903 'PhabricatorConfigEntryQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 5890 5904 'PhabricatorConfigFileSource' => 'PhabricatorConfigProxySource', 5891 5905 'PhabricatorConfigGroupController' => 'PhabricatorConfigController', 5906 + 'PhabricatorConfigHTTPParameterTypesModule' => 'PhabricatorConfigModule', 5892 5907 'PhabricatorConfigHistoryController' => 'PhabricatorConfigController', 5893 5908 'PhabricatorConfigIgnoreController' => 'PhabricatorConfigController', 5894 5909 'PhabricatorConfigIssueListController' => 'PhabricatorConfigController', ··· 6312 6327 'PhabricatorGlobalLock' => 'PhutilLock', 6313 6328 'PhabricatorGlobalUploadTargetView' => 'AphrontView', 6314 6329 'PhabricatorGoogleAuthProvider' => 'PhabricatorOAuth2AuthProvider', 6330 + 'PhabricatorHTTPParameterTypeTableView' => 'AphrontView', 6315 6331 'PhabricatorHandleList' => array( 6316 6332 'Phobject', 6317 6333 'Iterator',
+309
src/aphront/httpparametertype/AphrontHTTPParameterType.php
··· 1 + <?php 2 + 3 + /** 4 + * Defines how to read a complex value from an HTTP request. 5 + * 6 + * Most HTTP parameters are simple (like strings or integers) but some 7 + * parameters accept more complex values (like lists of users or project names). 8 + * 9 + * This class handles reading simple and complex values from a request, 10 + * performing any required parsing or lookups, and returning a result in a 11 + * standard format. 12 + * 13 + * @task read Reading Values from a Request 14 + * @task info Information About the Type 15 + * @task util Parsing Utilities 16 + * @task impl Implementation 17 + */ 18 + abstract class AphrontHTTPParameterType extends Phobject { 19 + 20 + 21 + private $viewer; 22 + 23 + 24 + /* -( Reading Values from a Request )-------------------------------------- */ 25 + 26 + 27 + /** 28 + * Set the current viewer. 29 + * 30 + * Some parameter types perform complex parsing involving lookups. For 31 + * example, a type might lookup usernames or project names. These types need 32 + * to use the current viewer to execute queries. 33 + * 34 + * @param PhabricatorUser Current viewer. 35 + * @return this 36 + * @task read 37 + */ 38 + final public function setViewer(PhabricatorUser $viewer) { 39 + $this->viewer = $viewer; 40 + return $this; 41 + } 42 + 43 + 44 + /** 45 + * Get the current viewer. 46 + * 47 + * @return PhabricatorUser Current viewer. 48 + * @task read 49 + */ 50 + final public function getViewer() { 51 + if (!$this->viewer) { 52 + throw new PhutilInvalidStateException('setViewer'); 53 + } 54 + return $this->viewer; 55 + } 56 + 57 + 58 + /** 59 + * Test if a value is present in a request. 60 + * 61 + * @param AphrontRequest The incoming request. 62 + * @param string The key to examine. 63 + * @return bool True if a readable value is present in the request. 64 + * @task read 65 + */ 66 + final public function getExists(AphrontRequest $request, $key) { 67 + return $this->getParameterExists($request, $key); 68 + } 69 + 70 + 71 + /** 72 + * Read a value from a request. 73 + * 74 + * If the value is not present, a default value is returned (usually `null`). 75 + * Use @{method:getExists} to test if a value is present. 76 + * 77 + * @param AphrontRequest The incoming request. 78 + * @param string The key to examine. 79 + * @return wild Value, or default if value is not present. 80 + * @task read 81 + */ 82 + final public function getValue(AphrontRequest $request, $key) { 83 + 84 + if (!$this->getExists($request, $key)) { 85 + return $this->getParameterDefault(); 86 + } 87 + 88 + return $this->getParameterValue($request, $key); 89 + } 90 + 91 + 92 + /** 93 + * Get the default value for this parameter type. 94 + * 95 + * @return wild Default value for this type. 96 + * @task read 97 + */ 98 + final public function getDefaultValue() { 99 + return $this->getParameterDefault(); 100 + } 101 + 102 + 103 + /* -( Information About the Type )----------------------------------------- */ 104 + 105 + 106 + /** 107 + * Get a short name for this type, like `string` or `list<phid>`. 108 + * 109 + * @return string Short type name. 110 + * @task info 111 + */ 112 + final public function getTypeName() { 113 + return $this->getParameterTypeName(); 114 + } 115 + 116 + 117 + /** 118 + * Get a list of human-readable descriptions of acceptable formats for this 119 + * type. 120 + * 121 + * For example, a type might return strings like these: 122 + * 123 + * > Any positive integer. 124 + * > A comma-separated list of PHIDs. 125 + * 126 + * This is used to explain to users how to specify a type when generating 127 + * documentation. 128 + * 129 + * @return list<string> Human-readable list of acceptable formats. 130 + * @task info 131 + */ 132 + final public function getFormatDescriptions() { 133 + return $this->getParameterFormatDescriptions(); 134 + } 135 + 136 + 137 + /** 138 + * Get a list of human-readable examples of how to format this type as an 139 + * HTTP GET parameter. 140 + * 141 + * For example, a type might return strings like these: 142 + * 143 + * > v=123 144 + * > v[]=1&v[]=2 145 + * 146 + * This is used to show users how to specify parameters of this type in 147 + * generated documentation. 148 + * 149 + * @return list<string> Human-readable list of format examples. 150 + * @task info 151 + */ 152 + final public function getExamples() { 153 + return $this->getParameterExamples(); 154 + } 155 + 156 + 157 + /* -( Utilities )---------------------------------------------------------- */ 158 + 159 + 160 + /** 161 + * Call another type's existence check. 162 + * 163 + * This method allows a type to reuse the exitence behavior of a different 164 + * type. For example, a "list of users" type may have the same basic 165 + * existence check that a simpler "list of strings" type has, and can just 166 + * call the simpler type to reuse its behavior. 167 + * 168 + * @param AphrontHTTPParameterType The other type. 169 + * @param AphrontRequest Incoming request. 170 + * @param string Key to examine. 171 + * @return bool True if the parameter exists. 172 + * @task util 173 + */ 174 + final protected function getExistsWithType( 175 + AphrontHTTPParameterType $type, 176 + AphrontRequest $request, 177 + $key) { 178 + 179 + $type->setViewer($this->getViewer()); 180 + 181 + return $type->getParameterExists($request, $key); 182 + } 183 + 184 + 185 + /** 186 + * Call another type's value parser. 187 + * 188 + * This method allows a type to reuse the parsing behavior of a different 189 + * type. For example, a "list of users" type may start by running the same 190 + * basic parsing that a simpler "list of strings" type does. 191 + * 192 + * @param AphrontHTTPParameterType The other type. 193 + * @param AphrontRequest Incoming request. 194 + * @param string Key to examine. 195 + * @return wild Parsed value. 196 + * @task util 197 + */ 198 + final protected function getValueWithType( 199 + AphrontHTTPParameterType $type, 200 + AphrontRequest $request, 201 + $key) { 202 + 203 + $type->setViewer($this->getViewer()); 204 + 205 + return $type->getValue($request, $key); 206 + } 207 + 208 + 209 + /** 210 + * Get a list of all available parameter types. 211 + * 212 + * @return list<AphrontHTTPParameterType> List of all available types. 213 + * @task util 214 + */ 215 + final public static function getAllTypes() { 216 + return id(new PhutilClassMapQuery()) 217 + ->setAncestorClass(__CLASS__) 218 + ->setUniqueMethod('getTypeName') 219 + ->setSortMethod('getTypeName') 220 + ->execute(); 221 + } 222 + 223 + 224 + /* -( Implementation )----------------------------------------------------- */ 225 + 226 + 227 + /** 228 + * Test if a parameter exists in a request. 229 + * 230 + * See @{method:getExists}. By default, this method tests if the key is 231 + * present in the request. 232 + * 233 + * To call another type's behavior in order to perform this check, use 234 + * @{method:getExistsWithType}. 235 + * 236 + * @param AphrontRequest The incoming request. 237 + * @param string The key to examine. 238 + * @return bool True if a readable value is present in the request. 239 + * @task impl 240 + */ 241 + protected function getParameterExists(AphrontRequest $request, $key) { 242 + return $request->getExists($key); 243 + } 244 + 245 + 246 + /** 247 + * Parse a value from a request. 248 + * 249 + * See @{method:getValue}. This method will //only// be called if this type 250 + * has already asserted that the value exists with 251 + * @{method:getParameterExists}. 252 + * 253 + * To call another type's behavior in order to parse a value, use 254 + * @{method:getValueWithType}. 255 + * 256 + * @param AphrontRequest The incoming request. 257 + * @param string The key to examine. 258 + * @return wild Parsed value. 259 + * @task impl 260 + */ 261 + abstract protected function getParameterValue(AphrontRequest $request, $key); 262 + 263 + 264 + /** 265 + * Return a simple type name string, like "string" or "list<phid>". 266 + * 267 + * See @{method:getTypeName}. 268 + * 269 + * @return string Short type name. 270 + * @task impl 271 + */ 272 + abstract protected function getParameterTypeName(); 273 + 274 + 275 + /** 276 + * Return a human-readable list of format descriptions. 277 + * 278 + * See @{method:getFormatDescriptions}. 279 + * 280 + * @return list<string> Human-readable list of acceptable formats. 281 + * @task impl 282 + */ 283 + abstract protected function getParameterFormatDescriptions(); 284 + 285 + 286 + /** 287 + * Return a human-readable list of examples. 288 + * 289 + * See @{method:getExamples}. 290 + * 291 + * @return list<string> Human-readable list of format examples. 292 + * @task impl 293 + */ 294 + abstract protected function getParameterExamples(); 295 + 296 + 297 + /** 298 + * Return the default value for this parameter type. 299 + * 300 + * See @{method:getDefaultValue}. If unspecified, the default is `null`. 301 + * 302 + * @return wild Default value. 303 + * @task impl 304 + */ 305 + protected function getParameterDefault() { 306 + return null; 307 + } 308 + 309 + }
+26
src/aphront/httpparametertype/AphrontPHIDHTTPParameterType.php
··· 1 + <?php 2 + 3 + final class AphrontPHIDHTTPParameterType 4 + extends AphrontHTTPParameterType { 5 + 6 + protected function getParameterValue(AphrontRequest $request, $key) { 7 + return $request->getStr($key); 8 + } 9 + 10 + protected function getParameterTypeName() { 11 + return 'phid'; 12 + } 13 + 14 + protected function getParameterFormatDescriptions() { 15 + return array( 16 + pht('A single object PHID.'), 17 + ); 18 + } 19 + 20 + protected function getParameterExamples() { 21 + return array( 22 + 'v=PHID-XXXX-1111', 23 + ); 24 + } 25 + 26 + }
+30
src/aphront/httpparametertype/AphrontPHIDListHTTPParameterType.php
··· 1 + <?php 2 + 3 + final class AphrontPHIDListHTTPParameterType 4 + extends AphrontHTTPParameterType { 5 + 6 + protected function getParameterValue(AphrontRequest $request, $key) { 7 + $type = new AphrontStringListHTTPParameterType(); 8 + return $this->getValueWithType($type, $request, $key); 9 + } 10 + 11 + protected function getParameterTypeName() { 12 + return 'list<phid>'; 13 + } 14 + 15 + protected function getParameterFormatDescriptions() { 16 + return array( 17 + pht('Comma-separated list of PHIDs.'), 18 + pht('List of PHIDs, as array.'), 19 + ); 20 + } 21 + 22 + protected function getParameterExamples() { 23 + return array( 24 + 'v=PHID-XXXX-1111', 25 + 'v=PHID-XXXX-1111,PHID-XXXX-2222', 26 + 'v[]=PHID-XXXX-1111&v[]=PHID-XXXX-2222', 27 + ); 28 + } 29 + 30 + }
+26
src/aphront/httpparametertype/AphrontSelectHTTPParameterType.php
··· 1 + <?php 2 + 3 + final class AphrontSelectHTTPParameterType 4 + extends AphrontHTTPParameterType { 5 + 6 + protected function getParameterValue(AphrontRequest $request, $key) { 7 + return $request->getStr($key); 8 + } 9 + 10 + protected function getParameterTypeName() { 11 + return 'select'; 12 + } 13 + 14 + protected function getParameterFormatDescriptions() { 15 + return array( 16 + pht('A single value from the allowed set.'), 17 + ); 18 + } 19 + 20 + protected function getParameterExamples() { 21 + return array( 22 + 'v=value', 23 + ); 24 + } 25 + 26 + }
+27
src/aphront/httpparametertype/AphrontStringHTTPParameterType.php
··· 1 + <?php 2 + 3 + final class AphrontStringHTTPParameterType 4 + extends AphrontHTTPParameterType { 5 + 6 + protected function getParameterValue(AphrontRequest $request, $key) { 7 + return $request->getStr($key); 8 + } 9 + 10 + protected function getParameterTypeName() { 11 + return 'string'; 12 + } 13 + 14 + protected function getParameterFormatDescriptions() { 15 + return array( 16 + pht('A URL-encoded string.'), 17 + ); 18 + } 19 + 20 + protected function getParameterExamples() { 21 + return array( 22 + 'v=simple', 23 + 'v=properly%20escaped%20text', 24 + ); 25 + } 26 + 27 + }
+38
src/aphront/httpparametertype/AphrontStringListHTTPParameterType.php
··· 1 + <?php 2 + 3 + final class AphrontStringListHTTPParameterType 4 + extends AphrontHTTPParameterType { 5 + 6 + protected function getParameterValue(AphrontRequest $request, $key) { 7 + $list = $request->getArr($key, null); 8 + 9 + if ($list === null) { 10 + $list = $request->getStrList($key); 11 + } 12 + 13 + return $list; 14 + } 15 + 16 + protected function getParameterDefault() { 17 + return array(); 18 + } 19 + 20 + protected function getParameterTypeName() { 21 + return 'list<string>'; 22 + } 23 + 24 + protected function getParameterFormatDescriptions() { 25 + return array( 26 + pht('Comma-separated list of strings.'), 27 + pht('List of strings, as array.'), 28 + ); 29 + } 30 + 31 + protected function getParameterExamples() { 32 + return array( 33 + 'v=cat,dog,pig', 34 + 'v[]=cat&v[]=dog', 35 + ); 36 + } 37 + 38 + }
+27
src/applications/config/module/PhabricatorConfigHTTPParameterTypesModule.php
··· 1 + <?php 2 + 3 + final class PhabricatorConfigHTTPParameterTypesModule 4 + extends PhabricatorConfigModule { 5 + 6 + public function getModuleKey() { 7 + return 'httpparameter'; 8 + } 9 + 10 + public function getModuleName() { 11 + return pht('HTTP Parameter Types'); 12 + } 13 + 14 + public function renderModuleStatus(AphrontRequest $request) { 15 + $viewer = $request->getViewer(); 16 + 17 + $types = AphrontHTTPParameterType::getAllTypes(); 18 + 19 + $table = id(new PhabricatorHTTPParameterTypeTableView()) 20 + ->setHTTPParameterTypes($types); 21 + 22 + return id(new PHUIObjectBoxView()) 23 + ->setHeaderText(pht('HTTP Parameter Types')) 24 + ->setTable($table); 25 + } 26 + 27 + }
+56
src/applications/config/view/PhabricatorHTTPParameterTypeTableView.php
··· 1 + <?php 2 + 3 + final class PhabricatorHTTPParameterTypeTableView 4 + extends AphrontView { 5 + 6 + private $types; 7 + 8 + public function setHTTPParameterTypes(array $types) { 9 + assert_instances_of($types, 'AphrontHTTPParameterType'); 10 + $this->types = $types; 11 + return $this; 12 + } 13 + 14 + public function getHTTPParameterTypes() { 15 + return $this->types; 16 + } 17 + 18 + public function render() { 19 + $types = $this->getHTTPParameterTypes(); 20 + $types = mpull($types, null, 'getTypeName'); 21 + 22 + $br = phutil_tag('br'); 23 + 24 + $rows = array(); 25 + foreach ($types as $name => $type) { 26 + $formats = $type->getFormatDescriptions(); 27 + $formats = phutil_implode_html($br, $formats); 28 + 29 + $examples = $type->getExamples(); 30 + $examples = phutil_implode_html($br, $examples); 31 + 32 + $rows[] = array( 33 + $name, 34 + $formats, 35 + $examples, 36 + ); 37 + } 38 + 39 + $table = id(new AphrontTableView($rows)) 40 + ->setHeaders( 41 + array( 42 + pht('Type'), 43 + pht('Formats'), 44 + pht('Examples'), 45 + )) 46 + ->setColumnClasses( 47 + array( 48 + 'pri top', 49 + 'top', 50 + 'wide top prewrap', 51 + )); 52 + 53 + return $table; 54 + } 55 + 56 + }
+11 -17
src/applications/transactions/editfield/PhabricatorEditField.php
··· 194 194 } 195 195 196 196 protected function getValueExistsInSubmit(AphrontRequest $request, $key) { 197 - return $request->getExists($key); 197 + return $this->getHTTPParameterType()->getExists($request, $key); 198 198 } 199 199 200 200 protected function getValueFromSubmit(AphrontRequest $request, $key) { 201 - return $request->getStr($key); 201 + return $this->getHTTPParameterType()->getValue($request, $key); 202 202 } 203 203 204 204 protected function getDefaultValue() { 205 - return null; 205 + return $this->getHTTPParameterType()->getDefaultValue(); 206 206 } 207 207 208 - protected function getListFromRequest( 209 - AphrontRequest $request, 210 - $key) { 211 - 212 - $list = $request->getArr($key, null); 213 - if ($list === null) { 214 - $list = $request->getStrList($key); 215 - } 208 + final public function getHTTPParameterType() { 209 + $type = $this->newHTTPParameterType(); 216 210 217 - if (!$list) { 218 - return array(); 211 + if ($type) { 212 + $type->setViewer($this->getViewer()); 219 213 } 220 214 221 - return $list; 215 + return $type; 222 216 } 223 217 224 - public function getHTTPParameterType() { 225 - return 'string'; 218 + protected function newHTTPParameterType() { 219 + return new AphrontStringHTTPParameterType(); 226 220 } 227 221 228 222 public function setEditTypeKey($edit_type_key) { ··· 290 284 id(new PhabricatorSimpleEditType()) 291 285 ->setEditType($type_key) 292 286 ->setTransactionType($transaction_type) 293 - ->setValueType($this->getHTTPParameterType()) 287 + ->setValueType($this->getHTTPParameterType()->getTypeName()) 294 288 ->setDescription($this->getDescription()) 295 289 ->setMetadata($this->metadata), 296 290 );
+2 -2
src/applications/transactions/editfield/PhabricatorPolicyEditField.php
··· 51 51 return $control; 52 52 } 53 53 54 - public function getHTTPParameterType() { 55 - return 'phid'; 54 + protected function newHTTPParameterType() { 55 + return new AphrontPHIDHTTPParameterType(); 56 56 } 57 57 58 58 }
+2 -2
src/applications/transactions/editfield/PhabricatorSelectEditField.php
··· 22 22 ->setOptions($this->getOptions()); 23 23 } 24 24 25 - public function getHTTPParameterType() { 26 - return 'select'; 25 + protected function newHTTPParameterType() { 26 + return new AphrontSelectHTTPParameterType(); 27 27 } 28 28 29 29 }
+2 -2
src/applications/transactions/editfield/PhabricatorSpaceEditField.php
··· 9 9 return null; 10 10 } 11 11 12 - public function getHTTPParameterType() { 13 - return 'phid'; 12 + protected function newHTTPParameterType() { 13 + return new AphrontPHIDHTTPParameterType(); 14 14 } 15 15 16 16 }
+3 -12
src/applications/transactions/editfield/PhabricatorTokenizerEditField.php
··· 18 18 return $control; 19 19 } 20 20 21 - public function setOriginalValue(array $value) { 22 - $this->originalValue = $value; 23 - return $this; 24 - } 25 - 26 21 public function setValue($value) { 27 22 $this->originalValue = $value; 28 23 return parent::setValue($value); ··· 33 28 // correctly is easier? 34 29 $this->originalValue = $request->getArr($key.'.original'); 35 30 36 - return $this->getListFromRequest($request, $key); 37 - } 38 - 39 - protected function getDefaultValue() { 40 - return array(); 31 + return parent::getValueFromSubmit($request, $key); 41 32 } 42 33 43 34 protected function getValueForTransaction() { ··· 87 78 return $new; 88 79 } 89 80 90 - public function getHTTPParameterType() { 91 - return 'list<phid>'; 81 + protected function newHTTPParameterType() { 82 + return new AphrontPHIDListHTTPParameterType(); 92 83 } 93 84 94 85 }
+4 -71
src/applications/transactions/view/PhabricatorApplicationEditHTTPParameterHelpView.php
··· 43 43 if ($type === null) { 44 44 unset($fields[$key]); 45 45 } 46 - $types[$type][] = $field; 46 + $types[$type->getTypeName()] = $type; 47 47 } 48 48 49 49 $intro = pht(<<<EOTEXT ··· 95 95 $rows[] = array( 96 96 $field->getLabel(), 97 97 $field->getKey(), 98 - $field->getHTTPParameterType(), 98 + $field->getHTTPParameterType()->getTypeName(), 99 99 $field->getDescription(), 100 100 ); 101 101 } ··· 234 234 EOTEXT 235 235 ); 236 236 237 - // TODO: This should be formalized and modularized. 238 - $type_spec = array( 239 - 'string' => array( 240 - 'format' => pht('URL encoded text.'), 241 - 'examples' => array( 242 - 'v=simple', 243 - 'v=properly%20escaped%20text', 244 - ), 245 - ), 246 - 'select' => array( 247 - 'format' => pht('Value from allowed set.'), 248 - 'examples' => array( 249 - 'v=value', 250 - ), 251 - ), 252 - 'list<phid>' => array( 253 - 'format' => array( 254 - pht('Comma-separated list of PHIDs.'), 255 - pht('List of PHIDs, as array.'), 256 - ), 257 - 'examples' => array( 258 - 'v=PHID-XXXX-1111,PHID-XXXX-2222', 259 - 'v[]=PHID-XXXX-1111&v[]=PHID-XXXX-2222', 260 - ), 261 - ), 262 - 'phid' => array( 263 - 'format' => pht('Single PHID.'), 264 - 'examples' => pht('v=PHID-XXX-1111'), 265 - ), 266 - ); 267 - 268 - $rows = array(); 269 - $br = phutil_tag('br'); 270 - foreach ($types as $type => $fields) { 271 - $spec = idx($type_spec, $type, array()); 272 - 273 - $field_list = mpull($fields, 'getKey'); 274 - $field_list = phutil_implode_html($br, $field_list); 275 - 276 - $format_list = idx($spec, 'format', array()); 277 - $format_list = phutil_implode_html($br, (array)$format_list); 278 - 279 - $example_list = idx($spec, 'examples', array()); 280 - $example_list = phutil_implode_html($br, (array)$example_list); 281 - 282 - $rows[] = array( 283 - $type, 284 - $field_list, 285 - $format_list, 286 - $example_list, 287 - ); 288 - } 289 - 290 - $types_table = id(new AphrontTableView($rows)) 291 - ->setNoDataString(pht('This object has no fields with types.')) 292 - ->setHeaders( 293 - array( 294 - pht('Type'), 295 - pht('Fields'), 296 - pht('Formats'), 297 - pht('Examples'), 298 - )) 299 - ->setColumnClasses( 300 - array( 301 - 'pri top', 302 - 'top', 303 - 'top', 304 - 'wide top prewrap', 305 - )); 237 + $types_table = id(new PhabricatorHTTPParameterTypeTableView()) 238 + ->setHTTPParameterTypes($types); 306 239 307 240 return array( 308 241 $this->renderInstructions($intro),