1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-12-24 06:20:56 +01:00

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
This commit is contained in:
epriestley 2015-12-02 05:55:31 -08:00
parent 91447c54bc
commit c1ae5321d7
17 changed files with 188 additions and 31 deletions

View file

@ -103,6 +103,7 @@ phutil_register_library_map(array(
'AphrontAjaxResponse' => 'aphront/response/AphrontAjaxResponse.php',
'AphrontApplicationConfiguration' => 'aphront/configuration/AphrontApplicationConfiguration.php',
'AphrontBarView' => 'view/widget/bars/AphrontBarView.php',
'AphrontBoolHTTPParameterType' => 'aphront/httpparametertype/AphrontBoolHTTPParameterType.php',
'AphrontCSRFException' => 'aphront/exception/AphrontCSRFException.php',
'AphrontCalendarEventView' => 'applications/calendar/view/AphrontCalendarEventView.php',
'AphrontController' => 'aphront/AphrontController.php',
@ -139,6 +140,7 @@ phutil_register_library_map(array(
'AphrontHTTPProxyResponse' => 'aphront/response/AphrontHTTPProxyResponse.php',
'AphrontHTTPSink' => 'aphront/sink/AphrontHTTPSink.php',
'AphrontHTTPSinkTestCase' => 'aphront/sink/__tests__/AphrontHTTPSinkTestCase.php',
'AphrontIntHTTPParameterType' => 'aphront/httpparametertype/AphrontIntHTTPParameterType.php',
'AphrontIsolatedDatabaseConnectionTestCase' => 'infrastructure/storage/__tests__/AphrontIsolatedDatabaseConnectionTestCase.php',
'AphrontIsolatedHTTPSink' => 'aphront/sink/AphrontIsolatedHTTPSink.php',
'AphrontJSONResponse' => 'aphront/response/AphrontJSONResponse.php',
@ -3907,6 +3909,7 @@ phutil_register_library_map(array(
'AphrontAjaxResponse' => 'AphrontResponse',
'AphrontApplicationConfiguration' => 'Phobject',
'AphrontBarView' => 'AphrontView',
'AphrontBoolHTTPParameterType' => 'AphrontHTTPParameterType',
'AphrontCSRFException' => 'AphrontException',
'AphrontCalendarEventView' => 'AphrontView',
'AphrontController' => 'Phobject',
@ -3946,6 +3949,7 @@ phutil_register_library_map(array(
'AphrontHTTPProxyResponse' => 'AphrontResponse',
'AphrontHTTPSink' => 'Phobject',
'AphrontHTTPSinkTestCase' => 'PhabricatorTestCase',
'AphrontIntHTTPParameterType' => 'AphrontHTTPParameterType',
'AphrontIsolatedDatabaseConnectionTestCase' => 'PhabricatorTestCase',
'AphrontIsolatedHTTPSink' => 'AphrontHTTPSink',
'AphrontJSONResponse' => 'AphrontResponse',

View file

@ -0,0 +1,29 @@
<?php
final class AphrontBoolHTTPParameterType
extends AphrontHTTPParameterType {
protected function getParameterValue(AphrontRequest $request, $key) {
return $request->getBool($key);
}
protected function getParameterTypeName() {
return 'bool';
}
protected function getParameterFormatDescriptions() {
return array(
pht('A boolean value (true or false).'),
);
}
protected function getParameterExamples() {
return array(
'v=true',
'v=false',
'v=1',
'v=0',
);
}
}

View file

@ -0,0 +1,26 @@
<?php
final class AphrontIntHTTPParameterType
extends AphrontHTTPParameterType {
protected function getParameterValue(AphrontRequest $request, $key) {
return $request->getInt($key);
}
protected function getParameterTypeName() {
return 'int';
}
protected function getParameterFormatDescriptions() {
return array(
pht('An integer.'),
);
}
protected function getParameterExamples() {
return array(
'v=123',
);
}
}

View file

@ -685,10 +685,6 @@ abstract class PhabricatorEditEngine
$field->readValueFromRequest($request);
}
} else {
foreach ($fields as $field) {
$field->readValueFromObject($object);
}
}
}

View file

@ -299,24 +299,27 @@ abstract class PhabricatorEditField extends Phobject {
}
public function readValueFromRequest(AphrontRequest $request) {
$check = array_merge(array($this->getKey()), $this->getAliases());
$check = $this->getAllReadValueFromRequestKeys();
foreach ($check as $key) {
if (!$this->getValueExistsInRequest($request, $key)) {
continue;
}
$this->value = $this->getValueFromRequest($request, $key);
return;
break;
}
$this->readValueFromObject($this->getObject());
return $this;
}
public function readValueFromObject($object) {
$this->value = $this->getValueFromObject($object);
return $this;
public function getAllReadValueFromRequestKeys() {
$keys = array();
$keys[] = $this->getKey();
foreach ($this->getAliases() as $alias) {
$keys[] = $alias;
}
return $keys;
}
public function readDefaultValueFromConfiguration($value) {
@ -337,11 +340,11 @@ abstract class PhabricatorEditField extends Phobject {
}
protected function getValueExistsInRequest(AphrontRequest $request, $key) {
return $this->getValueExistsInSubmit($request, $key);
return $this->getHTTPParameterValueExists($request, $key);
}
protected function getValueFromRequest(AphrontRequest $request, $key) {
return $this->getValueFromSubmit($request, $key);
return $this->getHTTPParameterValue($request, $key);
}
@ -385,6 +388,16 @@ abstract class PhabricatorEditField extends Phobject {
}
protected function getValueExistsInSubmit(AphrontRequest $request, $key) {
return $this->getHTTPParameterValueExists($request, $key);
}
protected function getValueFromSubmit(AphrontRequest $request, $key) {
return $this->getHTTPParameterValue($request, $key);
}
protected function getHTTPParameterValueExists(
AphrontRequest $request,
$key) {
$type = $this->getHTTPParameterType();
if ($type) {
@ -394,8 +407,14 @@ abstract class PhabricatorEditField extends Phobject {
return false;
}
protected function getValueFromSubmit(AphrontRequest $request, $key) {
return $this->getHTTPParameterType()->getValue($request, $key);
protected function getHTTPParameterValue($request, $key) {
$type = $this->getHTTPParameterType();
if ($type) {
return $type->getValue($request, $key);
}
return null;
}
protected function getDefaultValue() {

View file

@ -95,7 +95,7 @@ EOTEXT
foreach ($fields as $field) {
$rows[] = array(
$field->getLabel(),
$field->getKey(),
head($field->getAllReadValueFromRequestKeys()),
$field->getHTTPParameterType()->getTypeName(),
$field->getDescription(),
);
@ -150,7 +150,7 @@ EOTEXT
$rows = array();
foreach ($fields as $field) {
$aliases = $field->getAliases();
$aliases = array_slice($field->getAllReadValueFromRequestKeys(), 1);
if (!$aliases) {
continue;
}

View file

@ -34,7 +34,10 @@ final class PhabricatorCustomFieldEditEngineExtension
PhabricatorCustomField::ROLE_EDIT);
$field_list->setViewer($viewer);
$field_list->readFieldsFromStorage($object);
if (!$engine->getIsCreate()) {
$field_list->readFieldsFromStorage($object);
}
$results = array();
foreach ($field_list->getFields() as $field) {

View file

@ -4,6 +4,7 @@ final class PhabricatorCustomFieldEditField
extends PhabricatorEditField {
private $customField;
private $httpParameterType;
public function setCustomField(PhabricatorCustomField $custom_field) {
$this->customField = $custom_field;
@ -14,14 +15,22 @@ final class PhabricatorCustomFieldEditField
return $this->customField;
}
public function setCustomFieldHTTPParameterType(
AphrontHTTPParameterType $type) {
$this->httpParameterType = $type;
return $this;
}
public function getCustomFieldHTTPParameterType() {
return $this->httpParameterType;
}
protected function buildControl() {
$field = $this->getCustomField();
$clone = clone $field;
if ($this->getIsSubmittedForm()) {
$value = $this->getValue();
$clone->setValueFromApplicationTransactions($value);
}
$value = $this->getValue();
$clone->setValueFromApplicationTransactions($value);
return $clone->renderEditControl(array());
}
@ -42,11 +51,6 @@ final class PhabricatorCustomFieldEditField
return $clone->getNewValueForApplicationTransactions();
}
protected function getValueExistsInRequest(AphrontRequest $request, $key) {
// For now, never read these out of the request.
return false;
}
protected function getValueExistsInSubmit(AphrontRequest $request, $key) {
return true;
}
@ -66,8 +70,31 @@ final class PhabricatorCustomFieldEditField
}
protected function newHTTPParameterType() {
// TODO: For now, don't support custom fields for HTTP prefill.
$type = $this->getCustomFieldHTTPParameterType();
if ($type) {
return clone $type;
}
return null;
}
public function getAllReadValueFromRequestKeys() {
$keys = array();
// NOTE: This piece of complexity is so we can expose a reasonable key in
// the UI ("custom.x") instead of a crufty internal key ("std:app:x").
// Perhaps we can simplify this some day.
// In the parent, this is just getKey(), but that returns a cumbersome
// key in EditFields. Use the simpler edit type key instead.
$keys[] = $this->getEditTypeKey();
foreach ($this->getAliases() as $alias) {
$keys[] = $alias;
}
return $keys;
}
}

View file

@ -1091,8 +1091,15 @@ abstract class PhabricatorCustomField extends Phobject {
}
protected function newEditField() {
return id(new PhabricatorCustomFieldEditField())
$field = id(new PhabricatorCustomFieldEditField())
->setCustomField($this);
$http_type = $this->getHTTPParameterType();
if ($http_type) {
$field->setCustomFieldHTTPParameterType($http_type);
}
return $field;
}
protected function newStandardEditField() {
@ -1109,6 +1116,13 @@ abstract class PhabricatorCustomField extends Phobject {
->setValue($this->getNewValueForApplicationTransactions());
}
protected function getHTTPParameterType() {
if ($this->proxy) {
return $this->proxy->getHTTPParameterType();
}
return null;
}
/**
* @task edit
*/

View file

@ -129,4 +129,8 @@ final class PhabricatorStandardCustomFieldBool
);
}
protected function getHTTPParameterType() {
return new AphrontBoolHTTPParameterType();
}
}

View file

@ -112,5 +112,9 @@ final class PhabricatorStandardCustomFieldInt
}
}
protected function getHTTPParameterType() {
return new AphrontIntHTTPParameterType();
}
}

View file

@ -80,4 +80,8 @@ final class PhabricatorStandardCustomFieldLink
);
}
protected function getHTTPParameterType() {
return new AphrontStringHTTPParameterType();
}
}

View file

@ -34,14 +34,21 @@ abstract class PhabricatorStandardCustomFieldPHIDs
}
public function setValueFromStorage($value) {
// NOTE: We're accepting either a JSON string (a real storage value) or
// an array (from HTTP parameter prefilling). This is a little hacky, but
// should hold until this can get cleaned up more thoroughly.
// TODO: Clean this up.
$result = array();
if ($value) {
if (!is_array($value)) {
$value = json_decode($value, true);
if (is_array($value)) {
$result = array_values($value);
}
}
$this->setFieldValue($value);
return $this;
}
@ -213,4 +220,8 @@ abstract class PhabricatorStandardCustomFieldPHIDs
return $value;
}
protected function getHTTPParameterType() {
return new AphrontPHIDListHTTPParameterType();
}
}

View file

@ -95,5 +95,9 @@ final class PhabricatorStandardCustomFieldRemarkup
);
}
protected function getHTTPParameterType() {
return new AphrontStringHTTPParameterType();
}
}

View file

@ -136,4 +136,8 @@ final class PhabricatorStandardCustomFieldSelect
->setValueMap($this->getOptions());
}
protected function getHTTPParameterType() {
return new AphrontSelectHTTPParameterType();
}
}

View file

@ -63,4 +63,8 @@ final class PhabricatorStandardCustomFieldText
);
}
protected function getHTTPParameterType() {
return new AphrontStringHTTPParameterType();
}
}

View file

@ -11,4 +11,8 @@ final class PhabricatorStandardCustomFieldUsers
return new PhabricatorPeopleDatasource();
}
protected function getHTTPParameterType() {
return new AphrontUserListHTTPParameterType();
}
}