mirror of
https://we.phorge.it/source/phorge.git
synced 2025-01-19 03:01:11 +01:00
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
This commit is contained in:
parent
9de4bc6f3a
commit
20e4c3fbd4
15 changed files with 579 additions and 106 deletions
|
@ -135,6 +135,7 @@ phutil_register_library_map(array(
|
||||||
'AphrontFormView' => 'view/form/AphrontFormView.php',
|
'AphrontFormView' => 'view/form/AphrontFormView.php',
|
||||||
'AphrontGlyphBarView' => 'view/widget/bars/AphrontGlyphBarView.php',
|
'AphrontGlyphBarView' => 'view/widget/bars/AphrontGlyphBarView.php',
|
||||||
'AphrontHTMLResponse' => 'aphront/response/AphrontHTMLResponse.php',
|
'AphrontHTMLResponse' => 'aphront/response/AphrontHTMLResponse.php',
|
||||||
|
'AphrontHTTPParameterType' => 'aphront/httpparametertype/AphrontHTTPParameterType.php',
|
||||||
'AphrontHTTPProxyResponse' => 'aphront/response/AphrontHTTPProxyResponse.php',
|
'AphrontHTTPProxyResponse' => 'aphront/response/AphrontHTTPProxyResponse.php',
|
||||||
'AphrontHTTPSink' => 'aphront/sink/AphrontHTTPSink.php',
|
'AphrontHTTPSink' => 'aphront/sink/AphrontHTTPSink.php',
|
||||||
'AphrontHTTPSinkTestCase' => 'aphront/sink/__tests__/AphrontHTTPSinkTestCase.php',
|
'AphrontHTTPSinkTestCase' => 'aphront/sink/__tests__/AphrontHTTPSinkTestCase.php',
|
||||||
|
@ -149,6 +150,8 @@ phutil_register_library_map(array(
|
||||||
'AphrontMultiColumnView' => 'view/layout/AphrontMultiColumnView.php',
|
'AphrontMultiColumnView' => 'view/layout/AphrontMultiColumnView.php',
|
||||||
'AphrontMySQLDatabaseConnectionTestCase' => 'infrastructure/storage/__tests__/AphrontMySQLDatabaseConnectionTestCase.php',
|
'AphrontMySQLDatabaseConnectionTestCase' => 'infrastructure/storage/__tests__/AphrontMySQLDatabaseConnectionTestCase.php',
|
||||||
'AphrontNullView' => 'view/AphrontNullView.php',
|
'AphrontNullView' => 'view/AphrontNullView.php',
|
||||||
|
'AphrontPHIDHTTPParameterType' => 'aphront/httpparametertype/AphrontPHIDHTTPParameterType.php',
|
||||||
|
'AphrontPHIDListHTTPParameterType' => 'aphront/httpparametertype/AphrontPHIDListHTTPParameterType.php',
|
||||||
'AphrontPHPHTTPSink' => 'aphront/sink/AphrontPHPHTTPSink.php',
|
'AphrontPHPHTTPSink' => 'aphront/sink/AphrontPHPHTTPSink.php',
|
||||||
'AphrontPageView' => 'view/page/AphrontPageView.php',
|
'AphrontPageView' => 'view/page/AphrontPageView.php',
|
||||||
'AphrontPlainTextResponse' => 'aphront/response/AphrontPlainTextResponse.php',
|
'AphrontPlainTextResponse' => 'aphront/response/AphrontPlainTextResponse.php',
|
||||||
|
@ -164,10 +167,13 @@ phutil_register_library_map(array(
|
||||||
'AphrontResponseProducerInterface' => 'aphront/interface/AphrontResponseProducerInterface.php',
|
'AphrontResponseProducerInterface' => 'aphront/interface/AphrontResponseProducerInterface.php',
|
||||||
'AphrontRoutingMap' => 'aphront/site/AphrontRoutingMap.php',
|
'AphrontRoutingMap' => 'aphront/site/AphrontRoutingMap.php',
|
||||||
'AphrontRoutingResult' => 'aphront/site/AphrontRoutingResult.php',
|
'AphrontRoutingResult' => 'aphront/site/AphrontRoutingResult.php',
|
||||||
|
'AphrontSelectHTTPParameterType' => 'aphront/httpparametertype/AphrontSelectHTTPParameterType.php',
|
||||||
'AphrontSideNavFilterView' => 'view/layout/AphrontSideNavFilterView.php',
|
'AphrontSideNavFilterView' => 'view/layout/AphrontSideNavFilterView.php',
|
||||||
'AphrontSite' => 'aphront/site/AphrontSite.php',
|
'AphrontSite' => 'aphront/site/AphrontSite.php',
|
||||||
'AphrontStackTraceView' => 'view/widget/AphrontStackTraceView.php',
|
'AphrontStackTraceView' => 'view/widget/AphrontStackTraceView.php',
|
||||||
'AphrontStandaloneHTMLResponse' => 'aphront/response/AphrontStandaloneHTMLResponse.php',
|
'AphrontStandaloneHTMLResponse' => 'aphront/response/AphrontStandaloneHTMLResponse.php',
|
||||||
|
'AphrontStringHTTPParameterType' => 'aphront/httpparametertype/AphrontStringHTTPParameterType.php',
|
||||||
|
'AphrontStringListHTTPParameterType' => 'aphront/httpparametertype/AphrontStringListHTTPParameterType.php',
|
||||||
'AphrontTableView' => 'view/control/AphrontTableView.php',
|
'AphrontTableView' => 'view/control/AphrontTableView.php',
|
||||||
'AphrontTagView' => 'view/AphrontTagView.php',
|
'AphrontTagView' => 'view/AphrontTagView.php',
|
||||||
'AphrontTokenizerTemplateView' => 'view/control/AphrontTokenizerTemplateView.php',
|
'AphrontTokenizerTemplateView' => 'view/control/AphrontTokenizerTemplateView.php',
|
||||||
|
@ -1889,6 +1895,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorConfigEntryQuery' => 'applications/config/query/PhabricatorConfigEntryQuery.php',
|
'PhabricatorConfigEntryQuery' => 'applications/config/query/PhabricatorConfigEntryQuery.php',
|
||||||
'PhabricatorConfigFileSource' => 'infrastructure/env/PhabricatorConfigFileSource.php',
|
'PhabricatorConfigFileSource' => 'infrastructure/env/PhabricatorConfigFileSource.php',
|
||||||
'PhabricatorConfigGroupController' => 'applications/config/controller/PhabricatorConfigGroupController.php',
|
'PhabricatorConfigGroupController' => 'applications/config/controller/PhabricatorConfigGroupController.php',
|
||||||
|
'PhabricatorConfigHTTPParameterTypesModule' => 'applications/config/module/PhabricatorConfigHTTPParameterTypesModule.php',
|
||||||
'PhabricatorConfigHistoryController' => 'applications/config/controller/PhabricatorConfigHistoryController.php',
|
'PhabricatorConfigHistoryController' => 'applications/config/controller/PhabricatorConfigHistoryController.php',
|
||||||
'PhabricatorConfigIgnoreController' => 'applications/config/controller/PhabricatorConfigIgnoreController.php',
|
'PhabricatorConfigIgnoreController' => 'applications/config/controller/PhabricatorConfigIgnoreController.php',
|
||||||
'PhabricatorConfigIssueListController' => 'applications/config/controller/PhabricatorConfigIssueListController.php',
|
'PhabricatorConfigIssueListController' => 'applications/config/controller/PhabricatorConfigIssueListController.php',
|
||||||
|
@ -2250,6 +2257,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorGlobalLock' => 'infrastructure/util/PhabricatorGlobalLock.php',
|
'PhabricatorGlobalLock' => 'infrastructure/util/PhabricatorGlobalLock.php',
|
||||||
'PhabricatorGlobalUploadTargetView' => 'applications/files/view/PhabricatorGlobalUploadTargetView.php',
|
'PhabricatorGlobalUploadTargetView' => 'applications/files/view/PhabricatorGlobalUploadTargetView.php',
|
||||||
'PhabricatorGoogleAuthProvider' => 'applications/auth/provider/PhabricatorGoogleAuthProvider.php',
|
'PhabricatorGoogleAuthProvider' => 'applications/auth/provider/PhabricatorGoogleAuthProvider.php',
|
||||||
|
'PhabricatorHTTPParameterTypeTableView' => 'applications/config/view/PhabricatorHTTPParameterTypeTableView.php',
|
||||||
'PhabricatorHandleList' => 'applications/phid/handle/pool/PhabricatorHandleList.php',
|
'PhabricatorHandleList' => 'applications/phid/handle/pool/PhabricatorHandleList.php',
|
||||||
'PhabricatorHandleObjectSelectorDataView' => 'applications/phid/handle/view/PhabricatorHandleObjectSelectorDataView.php',
|
'PhabricatorHandleObjectSelectorDataView' => 'applications/phid/handle/view/PhabricatorHandleObjectSelectorDataView.php',
|
||||||
'PhabricatorHandlePool' => 'applications/phid/handle/pool/PhabricatorHandlePool.php',
|
'PhabricatorHandlePool' => 'applications/phid/handle/pool/PhabricatorHandlePool.php',
|
||||||
|
@ -3866,6 +3874,7 @@ phutil_register_library_map(array(
|
||||||
'AphrontFormView' => 'AphrontView',
|
'AphrontFormView' => 'AphrontView',
|
||||||
'AphrontGlyphBarView' => 'AphrontBarView',
|
'AphrontGlyphBarView' => 'AphrontBarView',
|
||||||
'AphrontHTMLResponse' => 'AphrontResponse',
|
'AphrontHTMLResponse' => 'AphrontResponse',
|
||||||
|
'AphrontHTTPParameterType' => 'Phobject',
|
||||||
'AphrontHTTPProxyResponse' => 'AphrontResponse',
|
'AphrontHTTPProxyResponse' => 'AphrontResponse',
|
||||||
'AphrontHTTPSink' => 'Phobject',
|
'AphrontHTTPSink' => 'Phobject',
|
||||||
'AphrontHTTPSinkTestCase' => 'PhabricatorTestCase',
|
'AphrontHTTPSinkTestCase' => 'PhabricatorTestCase',
|
||||||
|
@ -3880,6 +3889,8 @@ phutil_register_library_map(array(
|
||||||
'AphrontMultiColumnView' => 'AphrontView',
|
'AphrontMultiColumnView' => 'AphrontView',
|
||||||
'AphrontMySQLDatabaseConnectionTestCase' => 'PhabricatorTestCase',
|
'AphrontMySQLDatabaseConnectionTestCase' => 'PhabricatorTestCase',
|
||||||
'AphrontNullView' => 'AphrontView',
|
'AphrontNullView' => 'AphrontView',
|
||||||
|
'AphrontPHIDHTTPParameterType' => 'AphrontHTTPParameterType',
|
||||||
|
'AphrontPHIDListHTTPParameterType' => 'AphrontHTTPParameterType',
|
||||||
'AphrontPHPHTTPSink' => 'AphrontHTTPSink',
|
'AphrontPHPHTTPSink' => 'AphrontHTTPSink',
|
||||||
'AphrontPageView' => 'AphrontView',
|
'AphrontPageView' => 'AphrontView',
|
||||||
'AphrontPlainTextResponse' => 'AphrontResponse',
|
'AphrontPlainTextResponse' => 'AphrontResponse',
|
||||||
|
@ -3897,10 +3908,13 @@ phutil_register_library_map(array(
|
||||||
'AphrontResponse' => 'Phobject',
|
'AphrontResponse' => 'Phobject',
|
||||||
'AphrontRoutingMap' => 'Phobject',
|
'AphrontRoutingMap' => 'Phobject',
|
||||||
'AphrontRoutingResult' => 'Phobject',
|
'AphrontRoutingResult' => 'Phobject',
|
||||||
|
'AphrontSelectHTTPParameterType' => 'AphrontHTTPParameterType',
|
||||||
'AphrontSideNavFilterView' => 'AphrontView',
|
'AphrontSideNavFilterView' => 'AphrontView',
|
||||||
'AphrontSite' => 'Phobject',
|
'AphrontSite' => 'Phobject',
|
||||||
'AphrontStackTraceView' => 'AphrontView',
|
'AphrontStackTraceView' => 'AphrontView',
|
||||||
'AphrontStandaloneHTMLResponse' => 'AphrontHTMLResponse',
|
'AphrontStandaloneHTMLResponse' => 'AphrontHTMLResponse',
|
||||||
|
'AphrontStringHTTPParameterType' => 'AphrontHTTPParameterType',
|
||||||
|
'AphrontStringListHTTPParameterType' => 'AphrontHTTPParameterType',
|
||||||
'AphrontTableView' => 'AphrontView',
|
'AphrontTableView' => 'AphrontView',
|
||||||
'AphrontTagView' => 'AphrontView',
|
'AphrontTagView' => 'AphrontView',
|
||||||
'AphrontTokenizerTemplateView' => 'AphrontView',
|
'AphrontTokenizerTemplateView' => 'AphrontView',
|
||||||
|
@ -5889,6 +5903,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorConfigEntryQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
'PhabricatorConfigEntryQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
||||||
'PhabricatorConfigFileSource' => 'PhabricatorConfigProxySource',
|
'PhabricatorConfigFileSource' => 'PhabricatorConfigProxySource',
|
||||||
'PhabricatorConfigGroupController' => 'PhabricatorConfigController',
|
'PhabricatorConfigGroupController' => 'PhabricatorConfigController',
|
||||||
|
'PhabricatorConfigHTTPParameterTypesModule' => 'PhabricatorConfigModule',
|
||||||
'PhabricatorConfigHistoryController' => 'PhabricatorConfigController',
|
'PhabricatorConfigHistoryController' => 'PhabricatorConfigController',
|
||||||
'PhabricatorConfigIgnoreController' => 'PhabricatorConfigController',
|
'PhabricatorConfigIgnoreController' => 'PhabricatorConfigController',
|
||||||
'PhabricatorConfigIssueListController' => 'PhabricatorConfigController',
|
'PhabricatorConfigIssueListController' => 'PhabricatorConfigController',
|
||||||
|
@ -6312,6 +6327,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorGlobalLock' => 'PhutilLock',
|
'PhabricatorGlobalLock' => 'PhutilLock',
|
||||||
'PhabricatorGlobalUploadTargetView' => 'AphrontView',
|
'PhabricatorGlobalUploadTargetView' => 'AphrontView',
|
||||||
'PhabricatorGoogleAuthProvider' => 'PhabricatorOAuth2AuthProvider',
|
'PhabricatorGoogleAuthProvider' => 'PhabricatorOAuth2AuthProvider',
|
||||||
|
'PhabricatorHTTPParameterTypeTableView' => 'AphrontView',
|
||||||
'PhabricatorHandleList' => array(
|
'PhabricatorHandleList' => array(
|
||||||
'Phobject',
|
'Phobject',
|
||||||
'Iterator',
|
'Iterator',
|
||||||
|
|
309
src/aphront/httpparametertype/AphrontHTTPParameterType.php
Normal file
309
src/aphront/httpparametertype/AphrontHTTPParameterType.php
Normal file
|
@ -0,0 +1,309 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines how to read a complex value from an HTTP request.
|
||||||
|
*
|
||||||
|
* Most HTTP parameters are simple (like strings or integers) but some
|
||||||
|
* parameters accept more complex values (like lists of users or project names).
|
||||||
|
*
|
||||||
|
* This class handles reading simple and complex values from a request,
|
||||||
|
* performing any required parsing or lookups, and returning a result in a
|
||||||
|
* standard format.
|
||||||
|
*
|
||||||
|
* @task read Reading Values from a Request
|
||||||
|
* @task info Information About the Type
|
||||||
|
* @task util Parsing Utilities
|
||||||
|
* @task impl Implementation
|
||||||
|
*/
|
||||||
|
abstract class AphrontHTTPParameterType extends Phobject {
|
||||||
|
|
||||||
|
|
||||||
|
private $viewer;
|
||||||
|
|
||||||
|
|
||||||
|
/* -( Reading Values from a Request )-------------------------------------- */
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the current viewer.
|
||||||
|
*
|
||||||
|
* Some parameter types perform complex parsing involving lookups. For
|
||||||
|
* example, a type might lookup usernames or project names. These types need
|
||||||
|
* to use the current viewer to execute queries.
|
||||||
|
*
|
||||||
|
* @param PhabricatorUser Current viewer.
|
||||||
|
* @return this
|
||||||
|
* @task read
|
||||||
|
*/
|
||||||
|
final public function setViewer(PhabricatorUser $viewer) {
|
||||||
|
$this->viewer = $viewer;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the current viewer.
|
||||||
|
*
|
||||||
|
* @return PhabricatorUser Current viewer.
|
||||||
|
* @task read
|
||||||
|
*/
|
||||||
|
final public function getViewer() {
|
||||||
|
if (!$this->viewer) {
|
||||||
|
throw new PhutilInvalidStateException('setViewer');
|
||||||
|
}
|
||||||
|
return $this->viewer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test if a value is present in a request.
|
||||||
|
*
|
||||||
|
* @param AphrontRequest The incoming request.
|
||||||
|
* @param string The key to examine.
|
||||||
|
* @return bool True if a readable value is present in the request.
|
||||||
|
* @task read
|
||||||
|
*/
|
||||||
|
final public function getExists(AphrontRequest $request, $key) {
|
||||||
|
return $this->getParameterExists($request, $key);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read a value from a request.
|
||||||
|
*
|
||||||
|
* If the value is not present, a default value is returned (usually `null`).
|
||||||
|
* Use @{method:getExists} to test if a value is present.
|
||||||
|
*
|
||||||
|
* @param AphrontRequest The incoming request.
|
||||||
|
* @param string The key to examine.
|
||||||
|
* @return wild Value, or default if value is not present.
|
||||||
|
* @task read
|
||||||
|
*/
|
||||||
|
final public function getValue(AphrontRequest $request, $key) {
|
||||||
|
|
||||||
|
if (!$this->getExists($request, $key)) {
|
||||||
|
return $this->getParameterDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->getParameterValue($request, $key);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the default value for this parameter type.
|
||||||
|
*
|
||||||
|
* @return wild Default value for this type.
|
||||||
|
* @task read
|
||||||
|
*/
|
||||||
|
final public function getDefaultValue() {
|
||||||
|
return $this->getParameterDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* -( Information About the Type )----------------------------------------- */
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a short name for this type, like `string` or `list<phid>`.
|
||||||
|
*
|
||||||
|
* @return string Short type name.
|
||||||
|
* @task info
|
||||||
|
*/
|
||||||
|
final public function getTypeName() {
|
||||||
|
return $this->getParameterTypeName();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a list of human-readable descriptions of acceptable formats for this
|
||||||
|
* type.
|
||||||
|
*
|
||||||
|
* For example, a type might return strings like these:
|
||||||
|
*
|
||||||
|
* > Any positive integer.
|
||||||
|
* > A comma-separated list of PHIDs.
|
||||||
|
*
|
||||||
|
* This is used to explain to users how to specify a type when generating
|
||||||
|
* documentation.
|
||||||
|
*
|
||||||
|
* @return list<string> Human-readable list of acceptable formats.
|
||||||
|
* @task info
|
||||||
|
*/
|
||||||
|
final public function getFormatDescriptions() {
|
||||||
|
return $this->getParameterFormatDescriptions();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a list of human-readable examples of how to format this type as an
|
||||||
|
* HTTP GET parameter.
|
||||||
|
*
|
||||||
|
* For example, a type might return strings like these:
|
||||||
|
*
|
||||||
|
* > v=123
|
||||||
|
* > v[]=1&v[]=2
|
||||||
|
*
|
||||||
|
* This is used to show users how to specify parameters of this type in
|
||||||
|
* generated documentation.
|
||||||
|
*
|
||||||
|
* @return list<string> Human-readable list of format examples.
|
||||||
|
* @task info
|
||||||
|
*/
|
||||||
|
final public function getExamples() {
|
||||||
|
return $this->getParameterExamples();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* -( Utilities )---------------------------------------------------------- */
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call another type's existence check.
|
||||||
|
*
|
||||||
|
* This method allows a type to reuse the exitence behavior of a different
|
||||||
|
* type. For example, a "list of users" type may have the same basic
|
||||||
|
* existence check that a simpler "list of strings" type has, and can just
|
||||||
|
* call the simpler type to reuse its behavior.
|
||||||
|
*
|
||||||
|
* @param AphrontHTTPParameterType The other type.
|
||||||
|
* @param AphrontRequest Incoming request.
|
||||||
|
* @param string Key to examine.
|
||||||
|
* @return bool True if the parameter exists.
|
||||||
|
* @task util
|
||||||
|
*/
|
||||||
|
final protected function getExistsWithType(
|
||||||
|
AphrontHTTPParameterType $type,
|
||||||
|
AphrontRequest $request,
|
||||||
|
$key) {
|
||||||
|
|
||||||
|
$type->setViewer($this->getViewer());
|
||||||
|
|
||||||
|
return $type->getParameterExists($request, $key);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call another type's value parser.
|
||||||
|
*
|
||||||
|
* This method allows a type to reuse the parsing behavior of a different
|
||||||
|
* type. For example, a "list of users" type may start by running the same
|
||||||
|
* basic parsing that a simpler "list of strings" type does.
|
||||||
|
*
|
||||||
|
* @param AphrontHTTPParameterType The other type.
|
||||||
|
* @param AphrontRequest Incoming request.
|
||||||
|
* @param string Key to examine.
|
||||||
|
* @return wild Parsed value.
|
||||||
|
* @task util
|
||||||
|
*/
|
||||||
|
final protected function getValueWithType(
|
||||||
|
AphrontHTTPParameterType $type,
|
||||||
|
AphrontRequest $request,
|
||||||
|
$key) {
|
||||||
|
|
||||||
|
$type->setViewer($this->getViewer());
|
||||||
|
|
||||||
|
return $type->getValue($request, $key);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a list of all available parameter types.
|
||||||
|
*
|
||||||
|
* @return list<AphrontHTTPParameterType> List of all available types.
|
||||||
|
* @task util
|
||||||
|
*/
|
||||||
|
final public static function getAllTypes() {
|
||||||
|
return id(new PhutilClassMapQuery())
|
||||||
|
->setAncestorClass(__CLASS__)
|
||||||
|
->setUniqueMethod('getTypeName')
|
||||||
|
->setSortMethod('getTypeName')
|
||||||
|
->execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* -( Implementation )----------------------------------------------------- */
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test if a parameter exists in a request.
|
||||||
|
*
|
||||||
|
* See @{method:getExists}. By default, this method tests if the key is
|
||||||
|
* present in the request.
|
||||||
|
*
|
||||||
|
* To call another type's behavior in order to perform this check, use
|
||||||
|
* @{method:getExistsWithType}.
|
||||||
|
*
|
||||||
|
* @param AphrontRequest The incoming request.
|
||||||
|
* @param string The key to examine.
|
||||||
|
* @return bool True if a readable value is present in the request.
|
||||||
|
* @task impl
|
||||||
|
*/
|
||||||
|
protected function getParameterExists(AphrontRequest $request, $key) {
|
||||||
|
return $request->getExists($key);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse a value from a request.
|
||||||
|
*
|
||||||
|
* See @{method:getValue}. This method will //only// be called if this type
|
||||||
|
* has already asserted that the value exists with
|
||||||
|
* @{method:getParameterExists}.
|
||||||
|
*
|
||||||
|
* To call another type's behavior in order to parse a value, use
|
||||||
|
* @{method:getValueWithType}.
|
||||||
|
*
|
||||||
|
* @param AphrontRequest The incoming request.
|
||||||
|
* @param string The key to examine.
|
||||||
|
* @return wild Parsed value.
|
||||||
|
* @task impl
|
||||||
|
*/
|
||||||
|
abstract protected function getParameterValue(AphrontRequest $request, $key);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a simple type name string, like "string" or "list<phid>".
|
||||||
|
*
|
||||||
|
* See @{method:getTypeName}.
|
||||||
|
*
|
||||||
|
* @return string Short type name.
|
||||||
|
* @task impl
|
||||||
|
*/
|
||||||
|
abstract protected function getParameterTypeName();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a human-readable list of format descriptions.
|
||||||
|
*
|
||||||
|
* See @{method:getFormatDescriptions}.
|
||||||
|
*
|
||||||
|
* @return list<string> Human-readable list of acceptable formats.
|
||||||
|
* @task impl
|
||||||
|
*/
|
||||||
|
abstract protected function getParameterFormatDescriptions();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a human-readable list of examples.
|
||||||
|
*
|
||||||
|
* See @{method:getExamples}.
|
||||||
|
*
|
||||||
|
* @return list<string> Human-readable list of format examples.
|
||||||
|
* @task impl
|
||||||
|
*/
|
||||||
|
abstract protected function getParameterExamples();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the default value for this parameter type.
|
||||||
|
*
|
||||||
|
* See @{method:getDefaultValue}. If unspecified, the default is `null`.
|
||||||
|
*
|
||||||
|
* @return wild Default value.
|
||||||
|
* @task impl
|
||||||
|
*/
|
||||||
|
protected function getParameterDefault() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class AphrontPHIDHTTPParameterType
|
||||||
|
extends AphrontHTTPParameterType {
|
||||||
|
|
||||||
|
protected function getParameterValue(AphrontRequest $request, $key) {
|
||||||
|
return $request->getStr($key);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getParameterTypeName() {
|
||||||
|
return 'phid';
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getParameterFormatDescriptions() {
|
||||||
|
return array(
|
||||||
|
pht('A single object PHID.'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getParameterExamples() {
|
||||||
|
return array(
|
||||||
|
'v=PHID-XXXX-1111',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class AphrontPHIDListHTTPParameterType
|
||||||
|
extends AphrontHTTPParameterType {
|
||||||
|
|
||||||
|
protected function getParameterValue(AphrontRequest $request, $key) {
|
||||||
|
$type = new AphrontStringListHTTPParameterType();
|
||||||
|
return $this->getValueWithType($type, $request, $key);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getParameterTypeName() {
|
||||||
|
return 'list<phid>';
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getParameterFormatDescriptions() {
|
||||||
|
return array(
|
||||||
|
pht('Comma-separated list of PHIDs.'),
|
||||||
|
pht('List of PHIDs, as array.'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getParameterExamples() {
|
||||||
|
return array(
|
||||||
|
'v=PHID-XXXX-1111',
|
||||||
|
'v=PHID-XXXX-1111,PHID-XXXX-2222',
|
||||||
|
'v[]=PHID-XXXX-1111&v[]=PHID-XXXX-2222',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class AphrontSelectHTTPParameterType
|
||||||
|
extends AphrontHTTPParameterType {
|
||||||
|
|
||||||
|
protected function getParameterValue(AphrontRequest $request, $key) {
|
||||||
|
return $request->getStr($key);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getParameterTypeName() {
|
||||||
|
return 'select';
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getParameterFormatDescriptions() {
|
||||||
|
return array(
|
||||||
|
pht('A single value from the allowed set.'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getParameterExamples() {
|
||||||
|
return array(
|
||||||
|
'v=value',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class AphrontStringHTTPParameterType
|
||||||
|
extends AphrontHTTPParameterType {
|
||||||
|
|
||||||
|
protected function getParameterValue(AphrontRequest $request, $key) {
|
||||||
|
return $request->getStr($key);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getParameterTypeName() {
|
||||||
|
return 'string';
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getParameterFormatDescriptions() {
|
||||||
|
return array(
|
||||||
|
pht('A URL-encoded string.'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getParameterExamples() {
|
||||||
|
return array(
|
||||||
|
'v=simple',
|
||||||
|
'v=properly%20escaped%20text',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class AphrontStringListHTTPParameterType
|
||||||
|
extends AphrontHTTPParameterType {
|
||||||
|
|
||||||
|
protected function getParameterValue(AphrontRequest $request, $key) {
|
||||||
|
$list = $request->getArr($key, null);
|
||||||
|
|
||||||
|
if ($list === null) {
|
||||||
|
$list = $request->getStrList($key);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $list;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getParameterDefault() {
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getParameterTypeName() {
|
||||||
|
return 'list<string>';
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getParameterFormatDescriptions() {
|
||||||
|
return array(
|
||||||
|
pht('Comma-separated list of strings.'),
|
||||||
|
pht('List of strings, as array.'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getParameterExamples() {
|
||||||
|
return array(
|
||||||
|
'v=cat,dog,pig',
|
||||||
|
'v[]=cat&v[]=dog',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorConfigHTTPParameterTypesModule
|
||||||
|
extends PhabricatorConfigModule {
|
||||||
|
|
||||||
|
public function getModuleKey() {
|
||||||
|
return 'httpparameter';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getModuleName() {
|
||||||
|
return pht('HTTP Parameter Types');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function renderModuleStatus(AphrontRequest $request) {
|
||||||
|
$viewer = $request->getViewer();
|
||||||
|
|
||||||
|
$types = AphrontHTTPParameterType::getAllTypes();
|
||||||
|
|
||||||
|
$table = id(new PhabricatorHTTPParameterTypeTableView())
|
||||||
|
->setHTTPParameterTypes($types);
|
||||||
|
|
||||||
|
return id(new PHUIObjectBoxView())
|
||||||
|
->setHeaderText(pht('HTTP Parameter Types'))
|
||||||
|
->setTable($table);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,56 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorHTTPParameterTypeTableView
|
||||||
|
extends AphrontView {
|
||||||
|
|
||||||
|
private $types;
|
||||||
|
|
||||||
|
public function setHTTPParameterTypes(array $types) {
|
||||||
|
assert_instances_of($types, 'AphrontHTTPParameterType');
|
||||||
|
$this->types = $types;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getHTTPParameterTypes() {
|
||||||
|
return $this->types;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function render() {
|
||||||
|
$types = $this->getHTTPParameterTypes();
|
||||||
|
$types = mpull($types, null, 'getTypeName');
|
||||||
|
|
||||||
|
$br = phutil_tag('br');
|
||||||
|
|
||||||
|
$rows = array();
|
||||||
|
foreach ($types as $name => $type) {
|
||||||
|
$formats = $type->getFormatDescriptions();
|
||||||
|
$formats = phutil_implode_html($br, $formats);
|
||||||
|
|
||||||
|
$examples = $type->getExamples();
|
||||||
|
$examples = phutil_implode_html($br, $examples);
|
||||||
|
|
||||||
|
$rows[] = array(
|
||||||
|
$name,
|
||||||
|
$formats,
|
||||||
|
$examples,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$table = id(new AphrontTableView($rows))
|
||||||
|
->setHeaders(
|
||||||
|
array(
|
||||||
|
pht('Type'),
|
||||||
|
pht('Formats'),
|
||||||
|
pht('Examples'),
|
||||||
|
))
|
||||||
|
->setColumnClasses(
|
||||||
|
array(
|
||||||
|
'pri top',
|
||||||
|
'top',
|
||||||
|
'wide top prewrap',
|
||||||
|
));
|
||||||
|
|
||||||
|
return $table;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -194,35 +194,29 @@ abstract class PhabricatorEditField extends Phobject {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function getValueExistsInSubmit(AphrontRequest $request, $key) {
|
protected function getValueExistsInSubmit(AphrontRequest $request, $key) {
|
||||||
return $request->getExists($key);
|
return $this->getHTTPParameterType()->getExists($request, $key);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function getValueFromSubmit(AphrontRequest $request, $key) {
|
protected function getValueFromSubmit(AphrontRequest $request, $key) {
|
||||||
return $request->getStr($key);
|
return $this->getHTTPParameterType()->getValue($request, $key);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function getDefaultValue() {
|
protected function getDefaultValue() {
|
||||||
return null;
|
return $this->getHTTPParameterType()->getDefaultValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function getListFromRequest(
|
final public function getHTTPParameterType() {
|
||||||
AphrontRequest $request,
|
$type = $this->newHTTPParameterType();
|
||||||
$key) {
|
|
||||||
|
|
||||||
$list = $request->getArr($key, null);
|
if ($type) {
|
||||||
if ($list === null) {
|
$type->setViewer($this->getViewer());
|
||||||
$list = $request->getStrList($key);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$list) {
|
return $type;
|
||||||
return array();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $list;
|
protected function newHTTPParameterType() {
|
||||||
}
|
return new AphrontStringHTTPParameterType();
|
||||||
|
|
||||||
public function getHTTPParameterType() {
|
|
||||||
return 'string';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setEditTypeKey($edit_type_key) {
|
public function setEditTypeKey($edit_type_key) {
|
||||||
|
@ -290,7 +284,7 @@ abstract class PhabricatorEditField extends Phobject {
|
||||||
id(new PhabricatorSimpleEditType())
|
id(new PhabricatorSimpleEditType())
|
||||||
->setEditType($type_key)
|
->setEditType($type_key)
|
||||||
->setTransactionType($transaction_type)
|
->setTransactionType($transaction_type)
|
||||||
->setValueType($this->getHTTPParameterType())
|
->setValueType($this->getHTTPParameterType()->getTypeName())
|
||||||
->setDescription($this->getDescription())
|
->setDescription($this->getDescription())
|
||||||
->setMetadata($this->metadata),
|
->setMetadata($this->metadata),
|
||||||
);
|
);
|
||||||
|
|
|
@ -51,8 +51,8 @@ final class PhabricatorPolicyEditField
|
||||||
return $control;
|
return $control;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getHTTPParameterType() {
|
protected function newHTTPParameterType() {
|
||||||
return 'phid';
|
return new AphrontPHIDHTTPParameterType();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,8 +22,8 @@ final class PhabricatorSelectEditField
|
||||||
->setOptions($this->getOptions());
|
->setOptions($this->getOptions());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getHTTPParameterType() {
|
protected function newHTTPParameterType() {
|
||||||
return 'select';
|
return new AphrontSelectHTTPParameterType();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,8 +9,8 @@ final class PhabricatorSpaceEditField
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getHTTPParameterType() {
|
protected function newHTTPParameterType() {
|
||||||
return 'phid';
|
return new AphrontPHIDHTTPParameterType();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,11 +18,6 @@ abstract class PhabricatorTokenizerEditField
|
||||||
return $control;
|
return $control;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setOriginalValue(array $value) {
|
|
||||||
$this->originalValue = $value;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setValue($value) {
|
public function setValue($value) {
|
||||||
$this->originalValue = $value;
|
$this->originalValue = $value;
|
||||||
return parent::setValue($value);
|
return parent::setValue($value);
|
||||||
|
@ -33,11 +28,7 @@ abstract class PhabricatorTokenizerEditField
|
||||||
// correctly is easier?
|
// correctly is easier?
|
||||||
$this->originalValue = $request->getArr($key.'.original');
|
$this->originalValue = $request->getArr($key.'.original');
|
||||||
|
|
||||||
return $this->getListFromRequest($request, $key);
|
return parent::getValueFromSubmit($request, $key);
|
||||||
}
|
|
||||||
|
|
||||||
protected function getDefaultValue() {
|
|
||||||
return array();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function getValueForTransaction() {
|
protected function getValueForTransaction() {
|
||||||
|
@ -87,8 +78,8 @@ abstract class PhabricatorTokenizerEditField
|
||||||
return $new;
|
return $new;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getHTTPParameterType() {
|
protected function newHTTPParameterType() {
|
||||||
return 'list<phid>';
|
return new AphrontPHIDListHTTPParameterType();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,7 +43,7 @@ final class PhabricatorApplicationEditHTTPParameterHelpView
|
||||||
if ($type === null) {
|
if ($type === null) {
|
||||||
unset($fields[$key]);
|
unset($fields[$key]);
|
||||||
}
|
}
|
||||||
$types[$type][] = $field;
|
$types[$type->getTypeName()] = $type;
|
||||||
}
|
}
|
||||||
|
|
||||||
$intro = pht(<<<EOTEXT
|
$intro = pht(<<<EOTEXT
|
||||||
|
@ -95,7 +95,7 @@ EOTEXT
|
||||||
$rows[] = array(
|
$rows[] = array(
|
||||||
$field->getLabel(),
|
$field->getLabel(),
|
||||||
$field->getKey(),
|
$field->getKey(),
|
||||||
$field->getHTTPParameterType(),
|
$field->getHTTPParameterType()->getTypeName(),
|
||||||
$field->getDescription(),
|
$field->getDescription(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -234,75 +234,8 @@ shows how to format values for each field type.
|
||||||
EOTEXT
|
EOTEXT
|
||||||
);
|
);
|
||||||
|
|
||||||
// TODO: This should be formalized and modularized.
|
$types_table = id(new PhabricatorHTTPParameterTypeTableView())
|
||||||
$type_spec = array(
|
->setHTTPParameterTypes($types);
|
||||||
'string' => array(
|
|
||||||
'format' => pht('URL encoded text.'),
|
|
||||||
'examples' => array(
|
|
||||||
'v=simple',
|
|
||||||
'v=properly%20escaped%20text',
|
|
||||||
),
|
|
||||||
),
|
|
||||||
'select' => array(
|
|
||||||
'format' => pht('Value from allowed set.'),
|
|
||||||
'examples' => array(
|
|
||||||
'v=value',
|
|
||||||
),
|
|
||||||
),
|
|
||||||
'list<phid>' => array(
|
|
||||||
'format' => array(
|
|
||||||
pht('Comma-separated list of PHIDs.'),
|
|
||||||
pht('List of PHIDs, as array.'),
|
|
||||||
),
|
|
||||||
'examples' => array(
|
|
||||||
'v=PHID-XXXX-1111,PHID-XXXX-2222',
|
|
||||||
'v[]=PHID-XXXX-1111&v[]=PHID-XXXX-2222',
|
|
||||||
),
|
|
||||||
),
|
|
||||||
'phid' => array(
|
|
||||||
'format' => pht('Single PHID.'),
|
|
||||||
'examples' => pht('v=PHID-XXX-1111'),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
$rows = array();
|
|
||||||
$br = phutil_tag('br');
|
|
||||||
foreach ($types as $type => $fields) {
|
|
||||||
$spec = idx($type_spec, $type, array());
|
|
||||||
|
|
||||||
$field_list = mpull($fields, 'getKey');
|
|
||||||
$field_list = phutil_implode_html($br, $field_list);
|
|
||||||
|
|
||||||
$format_list = idx($spec, 'format', array());
|
|
||||||
$format_list = phutil_implode_html($br, (array)$format_list);
|
|
||||||
|
|
||||||
$example_list = idx($spec, 'examples', array());
|
|
||||||
$example_list = phutil_implode_html($br, (array)$example_list);
|
|
||||||
|
|
||||||
$rows[] = array(
|
|
||||||
$type,
|
|
||||||
$field_list,
|
|
||||||
$format_list,
|
|
||||||
$example_list,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
$types_table = id(new AphrontTableView($rows))
|
|
||||||
->setNoDataString(pht('This object has no fields with types.'))
|
|
||||||
->setHeaders(
|
|
||||||
array(
|
|
||||||
pht('Type'),
|
|
||||||
pht('Fields'),
|
|
||||||
pht('Formats'),
|
|
||||||
pht('Examples'),
|
|
||||||
))
|
|
||||||
->setColumnClasses(
|
|
||||||
array(
|
|
||||||
'pri top',
|
|
||||||
'top',
|
|
||||||
'top',
|
|
||||||
'wide top prewrap',
|
|
||||||
));
|
|
||||||
|
|
||||||
return array(
|
return array(
|
||||||
$this->renderInstructions($intro),
|
$this->renderInstructions($intro),
|
||||||
|
|
Loading…
Reference in a new issue