Files
wordpress-theme-aksrt/src/Admin/SchemaProviderOptionMatch.php
T
kate522andClaude Fable 5 57ff405691 refactor(color): unify color sanitizing and picking behind shared components
- 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>
2026-10-28 20:47:41 +08:00

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;
}
}