mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-16 11:52:40 +01:00
8ec413b972
Summary: Ref T9964. I added several hacks to get these working. Clean them up and pull this into a proper extension. The behavior in the web UI is: - they work in all applications; but - they only show up in the UI if a value is specified. So if you visit `/view/?ids=1,2` you get the field, but normally it's not present. We could refine this later. I'm going to add documentation about how to prefill these forms regardless, which should make this discoverable by reading the documentation. There's one teensey weensey hack: in the API, I push these fields to the top of the table. That one feels OK, since it's purely a convenience/display adjustment. Test Plan: Queried by IDs, reviewed docs. Reviewers: chad Reviewed By: chad Maniphest Tasks: T9964 Differential Revision: https://secure.phabricator.com/D14769
369 lines
7.9 KiB
PHP
369 lines
7.9 KiB
PHP
<?php
|
|
|
|
/**
|
|
* @task config Configuring Fields
|
|
* @task error Handling Errors
|
|
* @task io Reading and Writing Field Values
|
|
* @task conduit Integration with Conduit
|
|
* @task util Utility Methods
|
|
*/
|
|
abstract class PhabricatorSearchField extends Phobject {
|
|
|
|
private $key;
|
|
private $conduitKey;
|
|
private $viewer;
|
|
private $value;
|
|
private $label;
|
|
private $aliases = array();
|
|
private $errors = array();
|
|
private $description;
|
|
|
|
|
|
/* -( Configuring Fields )------------------------------------------------- */
|
|
|
|
|
|
/**
|
|
* Set the primary key for the field, like `projectPHIDs`.
|
|
*
|
|
* You can set human-readable aliases with @{method:setAliases}.
|
|
*
|
|
* The key should be a short, unique (within a search engine) string which
|
|
* does not contain any special characters.
|
|
*
|
|
* @param string Unique key which identifies the field.
|
|
* @return this
|
|
* @task config
|
|
*/
|
|
public function setKey($key) {
|
|
$this->key = $key;
|
|
return $this;
|
|
}
|
|
|
|
|
|
/**
|
|
* Get the field's key.
|
|
*
|
|
* @return string Unique key for this field.
|
|
* @task config
|
|
*/
|
|
public function getKey() {
|
|
return $this->key;
|
|
}
|
|
|
|
|
|
/**
|
|
* Set a human-readable label for the field.
|
|
*
|
|
* This should be a short text string, like "Reviewers" or "Colors".
|
|
*
|
|
* @param string Short, human-readable field label.
|
|
* @return this
|
|
* task config
|
|
*/
|
|
public function setLabel($label) {
|
|
$this->label = $label;
|
|
return $this;
|
|
}
|
|
|
|
|
|
/**
|
|
* Get the field's human-readable label.
|
|
*
|
|
* @return string Short, human-readable field label.
|
|
* @task config
|
|
*/
|
|
public function getLabel() {
|
|
return $this->label;
|
|
}
|
|
|
|
|
|
/**
|
|
* Set the acting viewer.
|
|
*
|
|
* Engines do not need to do this explicitly; it will be done on their
|
|
* behalf by the caller.
|
|
*
|
|
* @param PhabricatorUser Viewer.
|
|
* @return this
|
|
* @task config
|
|
*/
|
|
public function setViewer(PhabricatorUser $viewer) {
|
|
$this->viewer = $viewer;
|
|
return $this;
|
|
}
|
|
|
|
|
|
/**
|
|
* Get the acting viewer.
|
|
*
|
|
* @return PhabricatorUser Viewer.
|
|
* @task config
|
|
*/
|
|
public function getViewer() {
|
|
return $this->viewer;
|
|
}
|
|
|
|
|
|
/**
|
|
* Provide alternate field aliases, usually more human-readable versions
|
|
* of the key.
|
|
*
|
|
* These aliases can be used when building GET requests, so you can provide
|
|
* an alias like `authors` to let users write `&authors=alincoln` instead of
|
|
* `&authorPHIDs=alincoln`. This is a little easier to use.
|
|
*
|
|
* @param list<string> List of aliases for this field.
|
|
* @return this
|
|
* @task config
|
|
*/
|
|
public function setAliases(array $aliases) {
|
|
$this->aliases = $aliases;
|
|
return $this;
|
|
}
|
|
|
|
|
|
/**
|
|
* Get aliases for this field.
|
|
*
|
|
* @return list<string> List of aliases for this field.
|
|
* @task config
|
|
*/
|
|
public function getAliases() {
|
|
return $this->aliases;
|
|
}
|
|
|
|
|
|
/**
|
|
* Provide an alternate field key for Conduit.
|
|
*
|
|
* This can allow you to choose a more usable key for API endpoints.
|
|
* If no key is provided, the main key is used.
|
|
*
|
|
* @param string Alternate key for Conduit.
|
|
* @return this
|
|
* @task config
|
|
*/
|
|
public function setConduitKey($conduit_key) {
|
|
$this->conduitKey = $conduit_key;
|
|
return $this;
|
|
}
|
|
|
|
|
|
/**
|
|
* Get the field key for use in Conduit.
|
|
*
|
|
* @return string Conduit key for this field.
|
|
* @task config
|
|
*/
|
|
public function getConduitKey() {
|
|
if ($this->conduitKey !== null) {
|
|
return $this->conduitKey;
|
|
}
|
|
|
|
return $this->getKey();
|
|
}
|
|
|
|
|
|
/**
|
|
* Set a human-readable description for this field.
|
|
*
|
|
* @param string Human-readable description.
|
|
* @return this
|
|
* @task config
|
|
*/
|
|
public function setDescription($description) {
|
|
$this->description = $description;
|
|
return $this;
|
|
}
|
|
|
|
|
|
/**
|
|
* Get this field's human-readable description.
|
|
*
|
|
* @return string|null Human-readable description.
|
|
* @task config
|
|
*/
|
|
public function getDescription() {
|
|
return $this->description;
|
|
}
|
|
|
|
|
|
/* -( Handling Errors )---------------------------------------------------- */
|
|
|
|
|
|
protected function addError($short, $long) {
|
|
$this->errors[] = array($short, $long);
|
|
return $this;
|
|
}
|
|
|
|
public function getErrors() {
|
|
return $this->errors;
|
|
}
|
|
|
|
protected function validateControlValue($value) {
|
|
return;
|
|
}
|
|
|
|
protected function getShortError() {
|
|
$error = head($this->getErrors());
|
|
if ($error) {
|
|
return head($error);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
|
|
/* -( Reading and Writing Field Values )----------------------------------- */
|
|
|
|
|
|
public function readValueFromRequest(AphrontRequest $request) {
|
|
$check = array_merge(array($this->getKey()), $this->getAliases());
|
|
foreach ($check as $key) {
|
|
if ($this->getValueExistsInRequest($request, $key)) {
|
|
return $this->getValueFromRequest($request, $key);
|
|
}
|
|
}
|
|
return $this->getDefaultValue();
|
|
}
|
|
|
|
protected function getValueExistsInRequest(AphrontRequest $request, $key) {
|
|
return $request->getExists($key);
|
|
}
|
|
|
|
abstract protected function getValueFromRequest(
|
|
AphrontRequest $request,
|
|
$key);
|
|
|
|
public function readValueFromSavedQuery(PhabricatorSavedQuery $saved) {
|
|
$value = $saved->getParameter(
|
|
$this->getKey(),
|
|
$this->getDefaultValue());
|
|
$this->value = $this->didReadValueFromSavedQuery($value);
|
|
$this->validateControlValue($value);
|
|
return $this;
|
|
}
|
|
|
|
protected function didReadValueFromSavedQuery($value) {
|
|
return $value;
|
|
}
|
|
|
|
public function getValue() {
|
|
return $this->value;
|
|
}
|
|
|
|
protected function getValueForControl() {
|
|
return $this->value;
|
|
}
|
|
|
|
protected function getDefaultValue() {
|
|
return null;
|
|
}
|
|
|
|
public function getValueForQuery($value) {
|
|
return $value;
|
|
}
|
|
|
|
|
|
/* -( Rendering Controls )------------------------------------------------- */
|
|
|
|
|
|
protected function newControl() {
|
|
throw new PhutilMethodNotImplementedException();
|
|
}
|
|
|
|
|
|
protected function renderControl() {
|
|
$control = $this->newControl();
|
|
|
|
if (!$control) {
|
|
return null;
|
|
}
|
|
|
|
// TODO: We should `setError($this->getShortError())` here, but it looks
|
|
// terrible in the form layout.
|
|
|
|
return $control
|
|
->setValue($this->getValueForControl())
|
|
->setName($this->getKey())
|
|
->setLabel($this->getLabel());
|
|
}
|
|
|
|
public function appendToForm(AphrontFormView $form) {
|
|
$control = $this->renderControl();
|
|
if ($control !== null) {
|
|
$form->appendControl($this->renderControl());
|
|
}
|
|
return $this;
|
|
}
|
|
|
|
|
|
/* -( Integration with Conduit )------------------------------------------- */
|
|
|
|
|
|
/**
|
|
* @task conduit
|
|
*/
|
|
final public function getConduitParameterType() {
|
|
$type = $this->newConduitParameterType();
|
|
|
|
if ($type) {
|
|
$type->setViewer($this->getViewer());
|
|
}
|
|
|
|
return $type;
|
|
}
|
|
|
|
protected function newConduitParameterType() {
|
|
return null;
|
|
}
|
|
|
|
public function getValueExistsInConduitRequest(array $constraints) {
|
|
return $this->getConduitParameterType()->getExists(
|
|
$constraints,
|
|
$this->getConduitKey());
|
|
}
|
|
|
|
public function readValueFromConduitRequest(array $constraints) {
|
|
return $this->getConduitParameterType()->getValue(
|
|
$constraints,
|
|
$this->getConduitKey());
|
|
}
|
|
|
|
|
|
/* -( Utility Methods )----------------------------------------------------- */
|
|
|
|
|
|
/**
|
|
* Read a list of items from the request, in either array format or string
|
|
* format:
|
|
*
|
|
* list[]=item1&list[]=item2
|
|
* list=item1,item2
|
|
*
|
|
* This provides flexibility when constructing URIs, especially from external
|
|
* sources.
|
|
*
|
|
* @param AphrontRequest Request to read strings from.
|
|
* @param string Key to read in the request.
|
|
* @return list<string> List of values.
|
|
* @task utility
|
|
*/
|
|
protected function getListFromRequest(
|
|
AphrontRequest $request,
|
|
$key) {
|
|
|
|
$list = $request->getArr($key, null);
|
|
if ($list === null) {
|
|
$list = $request->getStrList($key);
|
|
}
|
|
|
|
if (!$list) {
|
|
return array();
|
|
}
|
|
|
|
return $list;
|
|
}
|
|
|
|
|
|
|
|
}
|