Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion lib/private/AppConfig.php
Original file line number Diff line number Diff line change
Expand Up @@ -795,11 +795,19 @@ private function setTypedValue(
int $type,
): bool {
$this->assertParams($app, $key);
if (!$this->matchAndApplyLexiconDefinition($app, $key, $lazy, $type)) {
/** @var ?Entry $lexiconEntry */
$lexiconEntry = null;
if (!$this->matchAndApplyLexiconDefinition($app, $key, $lazy, $type, lexiconEntry: $lexiconEntry)) {
return false; // returns false as database is not updated
}
$this->loadConfig(null, $lazy ?? true);

// lexicon entry might have requested a check on the value
$confirmationClosure = $lexiconEntry?->onSetConfirmation();
if ($confirmationClosure !== null && !$confirmationClosure($value)) {
return false;
}

$sensitive = $this->isTyped(self::VALUE_SENSITIVE, $type);
$inserted = $refreshCache = false;

Expand Down
27 changes: 18 additions & 9 deletions lib/private/Config/UserConfig.php
Original file line number Diff line number Diff line change
Expand Up @@ -1100,12 +1100,20 @@ private function setTypedValue(
}

$this->assertParams($userId, $app, $key);
if (!$this->matchAndApplyLexiconDefinition($userId, $app, $key, $lazy, $type, $flags)) {
/** @var ?Entry $lexiconEntry */
$lexiconEntry = null;
if (!$this->matchAndApplyLexiconDefinition($userId, $app, $key, $lazy, $type, $flags, lexiconEntry: $lexiconEntry)) {
// returns false as database is not updated
return false;
}
$this->loadConfig($userId, $lazy);

// lexicon entry might have requested a check on the value
$confirmationClosure = $lexiconEntry?->onSetConfirmation();
if ($confirmationClosure !== null && !$confirmationClosure($value)) {
return false;
}

$inserted = $refreshCache = false;
$origValue = $value;
$sensitive = $this->isFlagged(self::FLAG_SENSITIVE, $flags);
Expand Down Expand Up @@ -1937,6 +1945,7 @@ private function matchAndApplyLexiconDefinition(
ValueType &$type = ValueType::MIXED,
int &$flags = 0,
?string &$default = null,
?Entry &$lexiconEntry = null,
): bool {
$configDetails = $this->getConfigDetailsFromLexicon($app);
if (array_key_exists($key, $configDetails['aliases']) && !$this->ignoreLexiconAliases) {
Expand All @@ -1953,18 +1962,18 @@ private function matchAndApplyLexiconDefinition(
return true;
}

/** @var Entry $configValue */
$configValue = $configDetails['entries'][$key];
/** @var Entry $lexiconEntry */
$lexiconEntry = $configDetails['entries'][$key];
if ($type === ValueType::MIXED) {
// we overwrite if value was requested as mixed
$type = $configValue->getValueType();
} elseif ($configValue->getValueType() !== $type) {
$type = $lexiconEntry->getValueType();
} elseif ($lexiconEntry->getValueType() !== $type) {
throw new TypeConflictException('The user config key ' . $app . '/' . $key . ' is typed incorrectly in relation to the config lexicon');
}

$lazy = $configValue->isLazy();
$flags = $configValue->getFlags();
if ($configValue->isDeprecated()) {
$lazy = $lexiconEntry->isLazy();
$flags = $lexiconEntry->getFlags();
if ($lexiconEntry->isDeprecated()) {
$this->logger->notice('User config key ' . $app . '/' . $key . ' is set as deprecated.');
}

Expand All @@ -1976,7 +1985,7 @@ private function matchAndApplyLexiconDefinition(

// only look for default if needed, default from Lexicon got priority if not overwritten by admin
if ($default !== null) {
$default = $this->getSystemDefault($app, $configValue) ?? $configValue->getDefault($this->presetManager->getLexiconPreset()) ?? $default;
$default = $this->getSystemDefault($app, $lexiconEntry) ?? $lexiconEntry->getDefault($this->presetManager->getLexiconPreset()) ?? $default;
}

// returning false will make get() returning $default and set() not changing value in database
Expand Down
17 changes: 17 additions & 0 deletions lib/public/Config/Lexicon/Entry.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,10 @@ class Entry {
* @param string|null $rename source in case of a rename of a config key.
* @param int $options additional bitflag options {@see self::RENAME_INVERT_BOOLEAN}
* @param string $note additional note and warning related to the use of the config key.
* @param (Closure(string $value): bool)|null $onSetConfirm callback to be called when a config value is set. {@see onSetConfirmation()} for more details.
*
* @since 32.0.0
* @since 34.0.0 added $onSetConfirm
* @psalm-suppress PossiblyInvalidCast
* @psalm-suppress RiskyCast
*/
Expand All @@ -51,6 +53,7 @@ public function __construct(
private readonly ?string $rename = null,
private readonly int $options = 0,
private readonly string $note = '',
private readonly ?Closure $onSetConfirm = null,
) {
// key can only contain alphanumeric chars and underscore "_"
if (preg_match('/[^[:alnum:]_]/', $key)) {
Expand Down Expand Up @@ -195,6 +198,20 @@ public function getNote(): string {
return $this->note;
}

/**
* Returns an optional callback to be called when a config value is set.
* If not null, the callback will be called before the config value is set.
* Callable must accept a string-typed parameter containing the new value.
* String-typed parameter can be referenced and modified to a new value from the Callable.
* Callback must return a boolean indicating if the set operation should be allowed.
*
* @return (Closure(string $value): bool)|null
* @since 34.0.0
*/
public function onSetConfirmation(): ?Closure {
return $this->onSetConfirm;
}

/**
* returns if config key is set as lazy
*
Expand Down
Loading