EnumUtil.php 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. <?php
  2. namespace app\utils;
  3. use ReflectionClass;
  4. use ReflectionException;
  5. /**
  6. * 智能枚举验证器
  7. * 自动发现并验证请求参数中的枚举字段
  8. */
  9. class EnumUtil
  10. {
  11. /**
  12. * 自动验证请求参数中的枚举字段
  13. *
  14. * @param string|object $enumClassOrInstance 枚举类名或实例
  15. * @param array $requestData 请求数据
  16. * @return array 验证结果 ['valid' => bool, 'errors' => array]
  17. */
  18. public static function autoValidate($enumClassOrInstance, array $requestData): array
  19. {
  20. $errors = [];
  21. try {
  22. $constants = self::getEnumConstants($enumClassOrInstance);
  23. foreach ($constants as $constName => $enumValues) {
  24. if (!self::isValidEnumArray($enumValues)) {
  25. continue;
  26. }
  27. $fieldName = self::constToFieldName($constName);
  28. if (array_key_exists($fieldName, $requestData)) {
  29. if (empty($requestData[$fieldName])) {
  30. continue;
  31. }
  32. $result = self::validateEnumValue($requestData[$fieldName], $enumValues, $constName);
  33. if (!$result['valid']) {
  34. $errors[] = $result['error'];
  35. }
  36. }
  37. }
  38. } catch (ReflectionException $e) {
  39. return [
  40. 'valid' => false,
  41. 'errors' => ["枚举验证异常: " . $e->getMessage()]
  42. ];
  43. }
  44. return empty($errors) ? [
  45. 'valid' => true,
  46. 'errors' => []
  47. ] : [
  48. 'valid' => false,
  49. 'errors' => $errors
  50. ];
  51. }
  52. /**
  53. * 获取枚举类的所有字段映射
  54. *
  55. * @param string|object $enumClassOrInstance 枚举类名或实例
  56. * @return array 字段映射 [字段名 => 枚举值数组]
  57. */
  58. public static function getFieldMappings($enumClassOrInstance): array
  59. {
  60. $mappings = [];
  61. try {
  62. $constants = self::getEnumConstants($enumClassOrInstance);
  63. foreach ($constants as $constName => $enumValues) {
  64. if (self::isValidEnumArray($enumValues)) {
  65. $mappings[self::constToFieldName($constName)] = $enumValues;
  66. }
  67. }
  68. } catch (ReflectionException $e) {
  69. // 忽略异常,返回空数组
  70. }
  71. return $mappings;
  72. }
  73. /**
  74. * 获取枚举类的常量
  75. *
  76. * @param string|object $enumClassOrInstance
  77. * @return array
  78. * @throws ReflectionException
  79. */
  80. private static function getEnumConstants($enumClassOrInstance): array
  81. {
  82. return (new ReflectionClass($enumClassOrInstance))->getConstants();
  83. }
  84. /**
  85. * 检查是否为有效的枚举数组(非MAP格式的数组)
  86. *
  87. * @param mixed $enumValues
  88. * @return bool
  89. */
  90. private static function isValidEnumArray($enumValues): bool
  91. {
  92. return is_array($enumValues) && !empty($enumValues) && !self::isMapFormat($enumValues);
  93. }
  94. /**
  95. * 将枚举常量名转换为字段名
  96. *
  97. * @param string $constName 常量名称
  98. * @return string 字段名
  99. */
  100. private static function constToFieldName(string $constName): string
  101. {
  102. return strtolower($constName);
  103. }
  104. /**
  105. * 验证单个枚举值
  106. *
  107. * @param mixed $value 要验证的值
  108. * @param array $enumValues 枚举值数组
  109. * @param string $constName 常量名称
  110. * @return array 验证结果 ['valid' => bool, 'error' => string|null]
  111. */
  112. private static function validateEnumValue($value, array $enumValues, string $constName): array
  113. {
  114. $validValues = array_keys($enumValues);
  115. $normalizedValue = is_numeric($value) ? (int)$value : $value;
  116. if (!in_array($normalizedValue, $validValues, true)) {
  117. return [
  118. 'valid' => false,
  119. 'error' => self::constToFieldName($constName) . "参数错误,值:{$value}"
  120. ];
  121. }
  122. return [
  123. 'valid' => true,
  124. 'error' => null
  125. ];
  126. }
  127. /**
  128. * 检查枚举值数组是否为MAP格式(包含code字段)
  129. *
  130. * @param array $enumValues 枚举值数组
  131. * @return bool
  132. */
  133. private static function isMapFormat(array $enumValues): bool
  134. {
  135. if (empty($enumValues)) {
  136. return false;
  137. }
  138. $firstValue = reset($enumValues);
  139. return is_array($firstValue) && isset($firstValue['code']);
  140. }
  141. }