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 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 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() { // TODO: We should `setError($this->getShortError())` here, but it looks // terrible in the form layout. return $this->newControl() ->setValue($this->getValueForControl()) ->setName($this->getKey()) ->setLabel($this->getLabel()); } public function appendToForm(AphrontFormView $form) { $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 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; } }