mirror of
https://we.phorge.it/source/phorge.git
synced 2025-02-02 01:48:23 +01:00
Convert 'class' config options to new validation
Summary: Ref T12845. These options prompt the user to select from among concrete subclasses of some base class. Test Plan: Set, deleted and mangled these values from the web UI and CLI. Reviewers: chad, amckinley Reviewed By: amckinley Maniphest Tasks: T12845 Differential Revision: https://secure.phabricator.com/D18159
This commit is contained in:
parent
72119e786c
commit
0afdabff00
5 changed files with 78 additions and 49 deletions
|
@ -2329,6 +2329,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorChatLogEvent' => 'applications/chatlog/storage/PhabricatorChatLogEvent.php',
|
||||
'PhabricatorChatLogQuery' => 'applications/chatlog/query/PhabricatorChatLogQuery.php',
|
||||
'PhabricatorChunkedFileStorageEngine' => 'applications/files/engine/PhabricatorChunkedFileStorageEngine.php',
|
||||
'PhabricatorClassConfigType' => 'applications/config/type/PhabricatorClassConfigType.php',
|
||||
'PhabricatorClusterConfigOptions' => 'applications/config/option/PhabricatorClusterConfigOptions.php',
|
||||
'PhabricatorClusterDatabasesConfigOptionType' => 'infrastructure/cluster/config/PhabricatorClusterDatabasesConfigOptionType.php',
|
||||
'PhabricatorClusterException' => 'infrastructure/cluster/exception/PhabricatorClusterException.php',
|
||||
|
@ -7575,6 +7576,7 @@ phutil_register_library_map(array(
|
|||
),
|
||||
'PhabricatorChatLogQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
||||
'PhabricatorChunkedFileStorageEngine' => 'PhabricatorFileStorageEngine',
|
||||
'PhabricatorClassConfigType' => 'PhabricatorTextConfigType',
|
||||
'PhabricatorClusterConfigOptions' => 'PhabricatorApplicationConfigOptions',
|
||||
'PhabricatorClusterDatabasesConfigOptionType' => 'PhabricatorConfigJSONOptionType',
|
||||
'PhabricatorClusterException' => 'Exception',
|
||||
|
|
|
@ -350,20 +350,6 @@ final class PhabricatorConfigEditController
|
|||
case 'set':
|
||||
$set_value = array_fill_keys($request->getStrList('value'), true);
|
||||
break;
|
||||
case 'class':
|
||||
if (!class_exists($value)) {
|
||||
$e_value = pht('Invalid');
|
||||
$errors[] = pht('Class does not exist.');
|
||||
} else {
|
||||
$base = $option->getBaseClass();
|
||||
if (!is_subclass_of($value, $base)) {
|
||||
$e_value = pht('Invalid');
|
||||
$errors[] = pht('Class is not of valid type.');
|
||||
} else {
|
||||
$set_value = $value;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
$json = json_decode($value, true);
|
||||
if ($json === null && strtolower($value) != 'null') {
|
||||
|
@ -409,8 +395,6 @@ final class PhabricatorConfigEditController
|
|||
} else {
|
||||
$type = $option->getType();
|
||||
switch ($type) {
|
||||
case 'class':
|
||||
return $value;
|
||||
case 'set':
|
||||
return implode("\n", nonempty(array_keys($value), array()));
|
||||
default:
|
||||
|
@ -440,21 +424,6 @@ final class PhabricatorConfigEditController
|
|||
} else {
|
||||
$type = $option->getType();
|
||||
switch ($type) {
|
||||
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 'set':
|
||||
$control = id(new AphrontFormTextAreaControl())
|
||||
->setCaption(pht('Separate values with newlines or commas.'));
|
||||
|
|
|
@ -72,9 +72,6 @@ final class PhabricatorConfigManagementSetWorkflow
|
|||
} else {
|
||||
$type = $option->getType();
|
||||
switch ($type) {
|
||||
case 'class':
|
||||
$value = (string)$value;
|
||||
break;
|
||||
default:
|
||||
$value = json_decode($value, true);
|
||||
if (!is_array($value)) {
|
||||
|
|
|
@ -43,21 +43,6 @@ abstract class PhabricatorApplicationConfigOptions extends Phobject {
|
|||
}
|
||||
|
||||
switch ($option->getType()) {
|
||||
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)) {
|
||||
|
|
76
src/applications/config/type/PhabricatorClassConfigType.php
Normal file
76
src/applications/config/type/PhabricatorClassConfigType.php
Normal file
|
@ -0,0 +1,76 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorClassConfigType
|
||||
extends PhabricatorTextConfigType {
|
||||
|
||||
const TYPEKEY = 'class';
|
||||
|
||||
public function validateStoredValue(
|
||||
PhabricatorConfigOption $option,
|
||||
$value) {
|
||||
|
||||
if (!is_string($value)) {
|
||||
throw $this->newException(
|
||||
pht(
|
||||
'Option "%s" is of type "%s", but the configured value is not '.
|
||||
'a string.',
|
||||
$option->getKey(),
|
||||
$this->getTypeKey()));
|
||||
}
|
||||
|
||||
$base = $option->getBaseClass();
|
||||
$map = $this->getClassOptions($option);
|
||||
|
||||
try {
|
||||
$ok = class_exists($value);
|
||||
} catch (Exception $ex) {
|
||||
$ok = false;
|
||||
}
|
||||
|
||||
if (!$ok) {
|
||||
throw $this->newException(
|
||||
pht(
|
||||
'Option "%s" is of type "%s", but the configured value is not the '.
|
||||
'name of a known class. Valid selections are: %s.',
|
||||
$option->getKey(),
|
||||
$this->getTypeKey(),
|
||||
implode(', ', array_keys($map))));
|
||||
}
|
||||
|
||||
if (!isset($map[$value])) {
|
||||
throw $this->newException(
|
||||
pht(
|
||||
'Option "%s" is of type "%s", but the current value ("%s") is not '.
|
||||
'a known, concrete subclass of base class "%s". Valid selections '.
|
||||
'are: %s.',
|
||||
$option->getKey(),
|
||||
$this->getTypeKey(),
|
||||
$value,
|
||||
$base,
|
||||
implode(', ', array_keys($map))));
|
||||
}
|
||||
}
|
||||
|
||||
protected function newControl(PhabricatorConfigOption $option) {
|
||||
$map = array(
|
||||
'' => pht('(Use Default)'),
|
||||
) + $this->getClassOptions($option);
|
||||
|
||||
return id(new AphrontFormSelectControl())
|
||||
->setOptions($map);
|
||||
}
|
||||
|
||||
private function getClassOptions(PhabricatorConfigOption $option) {
|
||||
$symbols = id(new PhutilSymbolLoader())
|
||||
->setType('class')
|
||||
->setAncestorClass($option->getBaseClass())
|
||||
->setConcreteOnly(true)
|
||||
->selectSymbolsWithoutLoading();
|
||||
|
||||
$map = ipull($symbols, 'name', 'name');
|
||||
asort($map);
|
||||
|
||||
return $map;
|
||||
}
|
||||
|
||||
}
|
Loading…
Add table
Reference in a new issue