public function validateOption(PhabricatorConfigOption $option, $value) { if ($value === $option->getDefault()) { return; } if ($value === null) { return; } if ($option->isCustomType()) { try { return $option->getCustomObject()->validateOption($option, $value); } catch (Exception $ex) { // If custom validators threw exceptions, convert them to configuation // validation exceptions so we repair the configuration and raise // an error. throw new PhabricatorConfigValidationException($ex->getMessage()); } } switch ($option->getType()) { case 'bool': if ($value !== true && $value !== false) { throw new PhabricatorConfigValidationException(pht("Option '%s' is of type bool, but value is not true or false.", $option->getKey())); } break; case 'int': if (!is_int($value)) { throw new PhabricatorConfigValidationException(pht("Option '%s' is of type int, but value is not an integer.", $option->getKey())); } break; case 'string': if (!is_string($value)) { throw new PhabricatorConfigValidationException(pht("Option '%s' is of type string, but value is not a string.", $option->getKey())); } break; case 'class': $symbols = id(new PhutilSymbolLoader())->setType('class')->setAncestorClass($option->getBaseClass())->setConcreteOnly(true)->selectSymbolsWithoutLoading(); $names = ipull($symbols, 'name', 'name'); if (empty($names[$value])) { throw new PhabricatorConfigValidationException(pht("Option '%s' value must name a class extending '%s'.", $option->getKey(), $option->getBaseClass())); } break; case 'set': $valid = true; if (!is_array($value)) { throw new PhabricatorConfigValidationException(pht("Option '%s' must be a set, but value is not an array.", $option->getKey())); } foreach ($value as $v) { if ($v !== true) { throw new PhabricatorConfigValidationException(pht("Option '%s' must be a set, but array contains values other " . "than 'true'.", $option->getKey())); } } break; case 'list<regex>': $valid = true; if (!is_array($value)) { throw new PhabricatorConfigValidationException(pht("Option '%s' must be a list of regular expressions, but value " . "is not an array.", $option->getKey())); } if ($value && array_keys($value) != range(0, count($value) - 1)) { throw new PhabricatorConfigValidationException(pht("Option '%s' must be a list of regular expressions, but the " . "value is a map with unnatural keys.", $option->getKey())); } foreach ($value as $v) { $ok = @preg_match($v, ''); if ($ok === false) { throw new PhabricatorConfigValidationException(pht("Option '%s' must be a list of regular expressions, but the " . "value '%s' is not a valid regular expression.", $option->getKey(), $v)); } } break; case 'list<string>': $valid = true; if (!is_array($value)) { throw new PhabricatorConfigValidationException(pht("Option '%s' must be a list of strings, but value is not " . "an array.", $option->getKey())); } if ($value && array_keys($value) != range(0, count($value) - 1)) { throw new PhabricatorConfigValidationException(pht("Option '%s' must be a list of strings, but the value is a " . "map with unnatural keys.", $option->getKey())); } foreach ($value as $v) { if (!is_string($v)) { throw new PhabricatorConfigValidationException(pht("Option '%s' must be a list of strings, but it contains one " . "or more non-strings.", $option->getKey())); } } break; case 'wild': default: break; } $this->didValidateOption($option, $value); }
private function renderControl(PhabricatorConfigOption $option, $display_value, $e_value) { if ($option->isCustomType()) { $control = $option->getCustomObject()->renderControl($option, $display_value, $e_value); } else { $type = $option->getType(); switch ($type) { case 'int': case 'string': $control = id(new AphrontFormTextControl()); break; case 'bool': $control = id(new AphrontFormSelectControl())->setOptions(array('' => pht('(Use Default)'), 'true' => idx($option->getBoolOptions(), 0), 'false' => idx($option->getBoolOptions(), 1))); break; case 'enum': $options = array_mergev(array(array('' => pht('(Use Default)')), $option->getEnumOptions())); $control = id(new AphrontFormSelectControl())->setOptions($options); break; case 'class': $symbols = id(new PhutilSymbolLoader())->setType('class')->setAncestorClass($option->getBaseClass())->setConcreteOnly(true)->selectSymbolsWithoutLoading(); $names = ipull($symbols, 'name', 'name'); asort($names); $names = array('' => pht('(Use Default)')) + $names; $control = id(new AphrontFormSelectControl())->setOptions($names); break; case 'list<string>': case 'list<regex>': $control = id(new AphrontFormTextAreaControl())->setCaption(pht('Separate values with newlines.')); break; case 'set': $control = id(new AphrontFormTextAreaControl())->setCaption(pht('Separate values with newlines or commas.')); break; default: $control = id(new AphrontFormTextAreaControl())->setHeight(AphrontFormTextAreaControl::HEIGHT_VERY_TALL)->setCustomClass('PhabricatorMonospaced')->setCaption(pht('Enter value in JSON.')); break; } $control->setLabel(pht('Value'))->setError($e_value)->setValue($display_value)->setName('value'); } if ($option->getLocked()) { $control->setDisabled(true); } return $control; }