$plugin, 'display_name' => $config['plugin']['display_name'] ?? $plugin, ]; // 按插件名存储,避免冲突 $pluginConfigs[$plugin] = $config; } } return $pluginConfigs; } /** * 合并系统配置和插件配置 */ protected static function mergeConfigs(array $systemConfig, array $pluginConfigs): array { $merged = $systemConfig; // 初始化合并结构 if (!isset($merged['types'])) { $merged['types'] = []; } if (!isset($merged['field_mappings'])) { $merged['field_mappings'] = []; } if (!isset($merged['default_field_mappings'])) { $merged['default_field_mappings'] = []; } // 合并插件配置 foreach ($pluginConfigs as $pluginName => $pluginConfig) { // 合并审核类型 if (isset($pluginConfig['types'])) { foreach ($pluginConfig['types'] as $typeKey => $typeConfig) { $merged['types'][$typeKey] = $typeConfig; } } // 合并字段映射 if (isset($pluginConfig['field_mappings'])) { foreach ($pluginConfig['field_mappings'] as $typeKey => $mappings) { $merged['field_mappings'][$typeKey] = $mappings; } } // 合并格式化函数 if (isset($pluginConfig['formatters'])) { if (!isset($merged['formatters'])) { $merged['formatters'] = []; } $merged['formatters'] = array_merge($merged['formatters'], $pluginConfig['formatters']); } } return $merged; } /** * 构建字段映射索引 */ protected static function buildFieldMappings(): void { self::$fieldMappings = []; $config = self::$configCache; // 1. 处理所有审核类型 foreach ($config['field_mappings'] ?? [] as $typeKey => $mapping) { if (is_string($mapping) && class_exists($mapping)) { // 简单映射:类型 => 模型类 self::$fieldMappings[$typeKey] = [ 'model' => $mapping, 'fields' => [], ]; } elseif (is_array($mapping)) { // 详细映射配置 self::$fieldMappings[$typeKey] = $mapping; } } // 2. 获取 morph_map 映射(用于通过别名查找模型) $morphMap = config('morph_map.map', []); // 3. 关联 morph_map 和 field_mappings foreach ($morphMap as $alias => $modelClass) { // 如果 field_mappings 中有此模型的配置,建立关联 foreach (self::$fieldMappings as $typeKey => $mapping) { $mappingModel = $mapping['model'] ?? null; if ($mappingModel && $mappingModel === $modelClass) { // 建立别名到配置的映射 self::$fieldMappings['_by_morph'][$alias] = $typeKey; break; } } } } /** * 初始化格式化函数 */ protected static function initFormatters(): void { $config = self::$configCache; self::$formatters = $config['formatters'] ?? []; // 内置格式化函数 $builtinFormatters = [ 'trim' => fn($value) => trim($value ?? ''), 'html_to_text' => fn($html) => strip_tags($html ?? ''), 'implode' => function($value, $glue = ',') { if (is_array($value)) { return implode($glue, $value); } return $value; }, 'datetime' => function($timestamp, $format = 'Y-m-d H:i:s') { if (is_numeric($timestamp)) { return date($format, (int)$timestamp); } return $timestamp; }, 'limit' => function($text, $length = 50) { return Str::limit($text, $length); }, ]; self::$formatters = array_merge($builtinFormatters, self::$formatters); } /** * 格式化字段值 */ protected static function formatValue($value, ?array $fieldConfig): mixed { if ($value === null || empty($fieldConfig)) { return $value; } // 应用格式化函数 $format = $fieldConfig['format'] ?? null; if ($format) { // 处理带参数的格式化函数,如 "implode:、" if (is_string($format) && str_contains($format, ':')) { [$func, $param] = explode(':', $format, 2); $formatter = self::$formatters[$func] ?? null; if ($formatter) { return $formatter($value, $param); } } elseif (isset(self::$formatters[$format])) { return self::$formatters[$format]($value); } } return $value; } /** * 根据 morph_map 别名获取字段配置 */ protected static function getFieldConfigByMorphAlias(string $morphAlias): ?array { $config = self::$fieldMappings['_by_morph'][$morphAlias] ?? null; if (!$config) { return null; } return self::$fieldMappings[$config] ?? null; } /** * 根据审核记录获取字段映射配置 */ protected static function getFieldConfig(Review $review): ?array { $reviewableType = $review->reviewable_type; // 1. 首先尝试通过 morph_map 别名查找 $morphMap = config('morph_map.map', []); $morphAlias = array_search($reviewableType, $morphMap, true); if ($morphAlias !== false) { $config = self::getFieldConfigByMorphAlias($morphAlias); if ($config) { return $config; } } // 2. 直接通过 reviewable_type(完整类名)查找 return self::$fieldMappings[$reviewableType] ?? null; } /** * 获取单个字段的值 */ protected static function getFieldValue($model, string $fieldName, array $fieldConfig): mixed { if (!$model || empty($fieldConfig)) { return $fieldConfig['fallback'] ?? null; } $type = $fieldConfig['type'] ?? 'attribute'; $source = $fieldConfig['source'] ?? $fieldName; switch ($type) { case 'attribute': // 直接属性 $value = $model->{$source} ?? null; break; case 'relation': // 通过关联获取 if (method_exists($model, $source)) { $relation = $model->{$source}; if ($relation) { $attribute = $fieldConfig['attribute'] ?? 'name'; $value = $relation->{$attribute} ?? null; } else { $value = null; } } else { $value = null; } break; case 'callback': // 回调函数 $callback = $fieldConfig['callback'] ?? null; if (is_callable($callback)) { $value = $callback($model); } else { $value = null; } break; case 'fixed': // 固定值 $value = $fieldConfig['value'] ?? null; break; default: $value = null; } // 应用默认值 if ($value === null || $value === '') { $value = $fieldConfig['fallback'] ?? null; } // 格式化 return self::formatValue($value, $fieldConfig); } /** * 映射审核记录字段 * * @param Review $review 审核记录 * @param array $extraFields 额外需要映射的字段 * @return array 映射后的字段数组 */ public static function mapReview(Review $review, array $extraFields = []): array { self::init(); $reviewable = $review->reviewable; $fieldConfig = self::getFieldConfig($review); // 如果找不到配置,返回基本信息 if (!$fieldConfig || !$reviewable) { return self::getFallbackFields($review); } $fields = []; // 1. 映射标准字段 $standardFields = ['title', 'content', 'applicant']; foreach ($standardFields as $field) { $fieldConfigItem = $fieldConfig['fields'][$field] ?? self::$configCache['default_field_mappings'][$field] ?? null; $fields[$field] = self::getFieldValue($reviewable, $field, $fieldConfigItem); } // 2. 映射额外字段 foreach ($extraFields as $field) { if (isset($fieldConfig['fields'][$field])) { $fields[$field] = self::getFieldValue($reviewable, $field, $fieldConfig['fields'][$field]); } } // 3. 添加审核基础信息 $fields = array_merge($fields, self::getBaseReviewFields($review, $fieldConfig)); return $fields; } /** * 批量映射审核记录 */ public static function mapReviews(Collection $reviews, array $extraFields = []): Collection { return $reviews->map(function (Review $review) use ($extraFields) { $mapped = self::mapReview($review, $extraFields); // 将映射字段合并到审核记录中 foreach ($mapped as $key => $value) { if (!isset($review->{$key})) { $review->{$key} = $value; } } return $review; }); } /** * 获取审核基础字段(无需配置) */ protected static function getBaseReviewFields(Review $review, ?array $fieldConfig = null): array { return [ 'id' => $review->id, 'reviewable_type' => $review->reviewable_type, 'reviewable_id' => $review->reviewable_id, 'status' => $review->status, 'status_text' => $review->status_text, 'reason' => $review->reason, 'reviewer_id' => $review->reviewer_id, 'reviewer_name' => $review->reviewer?->real_name, 'reviewed_at' => $review->reviewed_at, 'created_at' => $review->created_at, 'updated_at' => $review->updated_at, 'display_name' => $fieldConfig['display_name'] ?? $review->reviewable_type, 'morph_alias' => self::getMorphAlias($review->reviewable_type), ]; } /** * 获取 fallback 字段(当找不到配置时) */ protected static function getFallbackFields(Review $review): array { $reviewable = $review->reviewable; return array_merge( self::getBaseReviewFields($review), [ 'title' => $reviewable ? '已删除的数据' : '数据不存在', 'content' => '', 'applicant' => '未知', ] ); } /** * 通过类名获取 morph_map 别名 */ protected static function getMorphAlias(string $className): ?string { $morphMap = config('morph_map.map', []); return array_search($className, $morphMap, true) ?: null; } /** * 获取所有已配置的审核类型 */ public static function getConfiguredTypes(): array { self::init(); $types = []; foreach (self::$fieldMappings as $key => $config) { if ($key === '_by_morph') continue; $types[$key] = [ 'display_name' => $config['display_name'] ?? $key, 'model' => $config['model'] ?? null, 'morph_alias' => self::getMorphAlias($config['model'] ?? ''), 'priority' => $config['priority'] ?? 0, 'icon' => $config['extra']['icon'] ?? null, 'color' => $config['extra']['color'] ?? null, ]; } // 按优先级排序 uasort($types, fn($a, $b) => ($b['priority'] ?? 0) <=> ($a['priority'] ?? 0)); return $types; } /** * 获取指定类型的字段配置 */ public static function getTypeConfig(string $typeKey): ?array { self::init(); return self::$fieldMappings[$typeKey] ?? null; } }