- Add AKSRT\Core\Color::sanitize($value, $allow_alpha) as the single PHP color sanitizer; replace sanitize_hex_color calls and per-class regexes (FloatButtons, FieldSchema, ThemeSearch, icon cards, TicketStatusService) - SchemaProvider / ControllerBase sanitize `color` fields as colors; alpha kept only when the schema sets showAlpha - Split SchemaProvider OAuth validation and option matching into sibling traits to stay under the 1000-line limit - Add AksColorPicker.vue + utils/color.js mirroring the PHP rules; AksField, FloatBtnCommonFields and TicketStatusPanel use it - Widget background color input now uses wpColorPicker - Remove dead AksCompositeField dimensions/spacing/background branches and the unused Gutenberg ColorPicker var - Add color-unification contract test; update harness requires and tests Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
76 lines
2.2 KiB
PHP
76 lines
2.2 KiB
PHP
<?php
|
|
/**
|
|
* SchemaProvider 枚举字段取值归一化(大小写不敏感匹配 / 选项声明值回写)。
|
|
*
|
|
* @package AKSRT
|
|
*/
|
|
|
|
namespace AKSRT\Admin;
|
|
|
|
defined('ABSPATH') || exit;
|
|
|
|
trait SchemaProviderOptionMatch {
|
|
|
|
/**
|
|
* 对大小写不敏感字段(case_insensitive),把值归一化为选项中的规范写法;
|
|
* 匹配不到返回 null。
|
|
*
|
|
* @param mixed $value
|
|
* @param array<int,mixed> $options
|
|
*/
|
|
private function normalize_case_insensitive_option($value, array $options): ?string {
|
|
if (!is_string($value) || $value === '') {
|
|
return null;
|
|
}
|
|
$lower = strtolower(trim($value));
|
|
foreach ($options as $opt) {
|
|
$opt_value = is_array($opt) ? ($opt['value'] ?? null) : $opt;
|
|
if (is_string($opt_value) && strtolower($opt_value) === $lower) {
|
|
return $opt_value;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Resolve a submitted enum value to the value declared by its option.
|
|
*
|
|
* Payloads reach the sanitizer as strings (or numbers), so a strict match
|
|
* against the schema would reject a valid choice whenever the option value
|
|
* is not itself a string -- e.g. 积分兑换明细.level declares 1 / 2 while the
|
|
* SPA submits them as numbers and sanitize_text_field() then turns them into
|
|
* "1" / "2". Returning the declared value keeps the stored type aligned with
|
|
* the schema, which the radio/select controls compare with === when they
|
|
* re-render a saved setting.
|
|
*
|
|
* Returns null when nothing matches, so validation still reports the
|
|
* invalid value instead of silently rewriting the operator's input.
|
|
*
|
|
* @param mixed $value
|
|
* @param array<int,mixed> $options
|
|
* @return mixed
|
|
*/
|
|
private function match_option_value($value, array $options) {
|
|
foreach ($options as $opt) {
|
|
$opt_value = is_array($opt) ? ($opt['value'] ?? null) : $opt;
|
|
if ($opt_value === $value) {
|
|
return $opt_value;
|
|
}
|
|
}
|
|
if (is_bool($value) || !is_scalar($value)) {
|
|
return null;
|
|
}
|
|
$needle = (string) $value;
|
|
foreach ($options as $opt) {
|
|
$opt_value = is_array($opt) ? ($opt['value'] ?? null) : $opt;
|
|
if (is_bool($opt_value) || !is_scalar($opt_value)) {
|
|
continue;
|
|
}
|
|
if ((string) $opt_value === $needle) {
|
|
return $opt_value;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
}
|