4 * @task config Configuring Fields
5 * @task error Handling Errors
6 * @task io Reading and Writing Field Values
7 * @task conduit Integration with Conduit
8 * @task util Utility Methods
10 abstract class PhabricatorSearchField
extends Phobject
{
17 private $aliases = array();
18 private $errors = array();
22 private $enableForConduit = true;
25 /* -( Configuring Fields )------------------------------------------------- */
29 * Set the primary key for the field, like `projectPHIDs`.
31 * You can set human-readable aliases with @{method:setAliases}.
33 * The key should be a short, unique (within a search engine) string which
34 * does not contain any special characters.
36 * @param string Unique key which identifies the field.
40 public function setKey($key) {
47 * Get the field's key.
49 * @return string Unique key for this field.
52 public function getKey() {
58 * Set a human-readable label for the field.
60 * This should be a short text string, like "Reviewers" or "Colors".
62 * @param string Short, human-readable field label.
66 public function setLabel($label) {
67 $this->label
= $label;
73 * Get the field's human-readable label.
75 * @return string Short, human-readable field label.
78 public function getLabel() {
84 * Set the acting viewer.
86 * Engines do not need to do this explicitly; it will be done on their
87 * behalf by the caller.
89 * @param PhabricatorUser Viewer.
93 public function setViewer(PhabricatorUser
$viewer) {
94 $this->viewer
= $viewer;
100 * Get the acting viewer.
102 * @return PhabricatorUser Viewer.
105 public function getViewer() {
106 return $this->viewer
;
111 * Provide alternate field aliases, usually more human-readable versions
114 * These aliases can be used when building GET requests, so you can provide
115 * an alias like `authors` to let users write `&authors=alincoln` instead of
116 * `&authorPHIDs=alincoln`. This is a little easier to use.
118 * @param list<string> List of aliases for this field.
122 public function setAliases(array $aliases) {
123 $this->aliases
= $aliases;
129 * Get aliases for this field.
131 * @return list<string> List of aliases for this field.
134 public function getAliases() {
135 return $this->aliases
;
140 * Provide an alternate field key for Conduit.
142 * This can allow you to choose a more usable key for API endpoints.
143 * If no key is provided, the main key is used.
145 * @param string Alternate key for Conduit.
149 public function setConduitKey($conduit_key) {
150 $this->conduitKey
= $conduit_key;
156 * Get the field key for use in Conduit.
158 * @return string Conduit key for this field.
161 public function getConduitKey() {
162 if ($this->conduitKey
!== null) {
163 return $this->conduitKey
;
166 return $this->getKey();
171 * Set a human-readable description for this field.
173 * @param string Human-readable description.
177 public function setDescription($description) {
178 $this->description
= $description;
184 * Get this field's human-readable description.
186 * @return string|null Human-readable description.
189 public function getDescription() {
190 return $this->description
;
195 * Hide this field from the web UI.
197 * @param bool True to hide the field from the web UI.
201 public function setIsHidden($is_hidden) {
202 $this->isHidden
= $is_hidden;
208 * Should this field be hidden from the web UI?
210 * @return bool True to hide the field in the web UI.
213 public function getIsHidden() {
214 return $this->isHidden
;
218 /* -( Handling Errors )---------------------------------------------------- */
221 protected function addError($short, $long) {
222 $this->errors
[] = array($short, $long);
226 public function getErrors() {
227 return $this->errors
;
230 protected function validateControlValue($value) {
234 protected function getShortError() {
235 $error = head($this->getErrors());
243 /* -( Reading and Writing Field Values )----------------------------------- */
246 public function readValueFromRequest(AphrontRequest
$request) {
247 $check = array_merge(array($this->getKey()), $this->getAliases());
248 foreach ($check as $key) {
249 if ($this->getValueExistsInRequest($request, $key)) {
250 return $this->getValueFromRequest($request, $key);
253 return $this->getDefaultValue();
256 protected function getValueExistsInRequest(AphrontRequest
$request, $key) {
257 return $request->getExists($key);
260 abstract protected function getValueFromRequest(
261 AphrontRequest
$request,
264 public function readValueFromSavedQuery(PhabricatorSavedQuery
$saved) {
265 $value = $saved->getParameter(
267 $this->getDefaultValue());
268 $this->value
= $this->didReadValueFromSavedQuery($value);
269 $this->validateControlValue($value);
273 protected function didReadValueFromSavedQuery($value) {
277 public function getValue() {
281 protected function getValueForControl() {
285 protected function getDefaultValue() {
289 public function getValueForQuery($value) {
294 /* -( Rendering Controls )------------------------------------------------- */
297 protected function newControl() {
298 throw new PhutilMethodNotImplementedException();
302 protected function renderControl() {
303 if ($this->getIsHidden()) {
307 $control = $this->newControl();
313 // TODO: We should `setError($this->getShortError())` here, but it looks
314 // terrible in the form layout.
317 ->setValue($this->getValueForControl())
318 ->setName($this->getKey())
319 ->setLabel($this->getLabel());
322 public function appendToForm(AphrontFormView
$form) {
323 $control = $this->renderControl();
324 if ($control !== null) {
325 $form->appendControl($this->renderControl());
331 /* -( Integration with Conduit )------------------------------------------- */
337 final public function getConduitParameterType() {
338 if (!$this->getEnableForConduit()) {
342 $type = $this->newConduitParameterType();
345 $type->setViewer($this->getViewer());
351 protected function newConduitParameterType() {
355 public function getValueExistsInConduitRequest(array $constraints) {
356 return $this->getConduitParameterType()->getExists(
358 $this->getConduitKey());
361 public function readValueFromConduitRequest(
365 return $this->getConduitParameterType()->getValue(
367 $this->getConduitKey(),
371 public function getValidConstraintKeys() {
372 return $this->getConduitParameterType()->getKeys(
373 $this->getConduitKey());
376 final public function setEnableForConduit($enable) {
377 $this->enableForConduit
= $enable;
381 final public function getEnableForConduit() {
382 return $this->enableForConduit
;
385 public function newConduitConstants() {
390 /* -( Utility Methods )----------------------------------------------------- */
394 * Read a list of items from the request, in either array format or string
397 * list[]=item1&list[]=item2
400 * This provides flexibility when constructing URIs, especially from external
403 * @param AphrontRequest Request to read strings from.
404 * @param string Key to read in the request.
405 * @return list<string> List of values.
408 protected function getListFromRequest(
409 AphrontRequest
$request,
412 $list = $request->getArr($key, null);
413 if ($list === null) {
414 $list = $request->getStrList($key);