entityMatch($message); * $rawData = json_decode($message->getBody(), true); * $entity = $parser->entityMap($rawData, $entity); * $entity->save(); * * // 指定实体类型(覆盖自动提取) * $parser = EntityParseFactory::createFromMessage($message, 'order'); * * 命名约定(推荐方式): * - 创建符合命名约定的 Parser 类,工厂自动查找 * - 类名:{Entity} * - 命名空间:App\Platform\{Platform}\EntityParse * - 示例:App\Platform\Shopee\EntityParse\Order * * 平台名称来源: * - 从 platforms 表中根据 platform_id 查询 name 字段 * - 示例:platform_id=25 -> name='Shopee' -> App\Platform\Shopee\EntityParse\Order * * 如果找不到对应的 Parser 类,将抛出 InvalidArgumentException * * 配置文件(可选): * - 如需覆盖默认行为,可在 config/autoload/entity_parse.php 中配置 * - 配置格式:[platform_id => ['entity_type' => ParserClass]] * - 支持通配符 '*' 匹配所有实体类型 */ class EntityParseFactory { /** * 平台与 Parser 类的映射表 * 格式:[platform_id => ['entity_type' => ParserClass]] * 示例:[25 => ['order' => ShopeeOrderParser, 'product' => ShopeeProductParser]] * * @var array>> */ private static array $registry = []; /** * 容器实例 */ private static ?ContainerInterface $container = null; /** * 配置实例 */ private static ?ConfigInterface $config = null; /** * 设置容器(由框架注入) * * @param ContainerInterface $container * @return void */ public static function setContainer(ContainerInterface $container): void { self::$container = $container; self::$config = $container->get(ConfigInterface::class); self::loadConfig(); } /** * 从配置文件加载平台映射 * * @return void */ private static function loadConfig(): void { if (!self::$config) { return; } $parsers = self::$config->get('entity_parse.platforms', []); foreach ($parsers as $platform => $entities) { foreach ($entities as $entityType => $parserClass) { self::register($platform, $entityType, $parserClass); } } } /** * 根据消息自动创建 Parser 实例(静态方法) * * @param AMQPMessage $message * @param string|null $entityType 实体类型(可选,如果不指定则从 payload 中提取) * @return EntityParseInterface * @throws InvalidArgumentException */ public static function createFromMessage( AMQPMessage $message, ?string $entityType = null ): EntityParseInterface { // 1. 从消息体中解析数据 $data = json_decode($message->getBody(), true); if (!is_array($data)) { throw new InvalidArgumentException('Invalid message body: expected JSON array'); } // 2. 从 data 中提取 platform_id if (!isset($data['platform_id'])) { throw new InvalidArgumentException('Missing required field: platform_id'); } $platformId = (int) $data['platform_id']; // 3. 如果未指定实体类型,从 routing key 中提取 if ($entityType === null) { $entityType = self::extractEntityTypeFromData($data, $message); } // 4. 获取对应的 Parser 类 $parserClass = self::resolveParserClass($platformId, $entityType); // 5. 创建并返回 Parser 实例,传递解析后的数据和消息对象 return $parserClass::create($data, $message); } /** * 从路由键中提取实体类型 * * @param array $data * @param AMQPMessage $message * @return string */ private static function extractEntityTypeFromData(array $data, AMQPMessage $message): string { // 优先从 routing key 中提取 $routingKey = $message->getRoutingKey(); $entityType = Str::of($routingKey) ->before('.') ->lower() ->toString(); if (!empty($entityType)) { return $entityType; } throw new InvalidArgumentException("Cannot extract entity type from routing key: {$routingKey}"); } /** * 解析 Parser 类名 * * 优先级: * 1. 手动注册的映射 * 2. 配置文件中的映射 * 3. 命名约定自动查找 * * @param int $platformId * @param string $entityType * @return class-string * @throws InvalidArgumentException */ private static function resolveParserClass(int $platformId, string $entityType): string { // 1. 检查手动注册的映射 if (isset(self::$registry[$platformId][$entityType])) { return self::$registry[$platformId][$entityType]; } // 2. 检查通配符映射(支持 * 匹配所有实体类型) if (isset(self::$registry[$platformId]['*'])) { return self::$registry[$platformId]['*']; } // 3. 使用命名约定自动查找 $parserClass = self::findByConvention($platformId, $entityType); if ($parserClass) { // 自动注册以提高后续性能 self::register($platformId, $entityType, $parserClass); return $parserClass; } throw new InvalidArgumentException( "Cannot find parser for platform_id '{$platformId}' and entity '{$entityType}'. " . "Please register it using EntityParseFactory::register() or create a parser class following the naming convention." ); } /** * 根据命名约定查找 Parser 类 * * 命名约定: * - 类名:{Entity} * - 命名空间:App\Platform\{Platform}\EntityParse * * 示例: * - platform_id: 25 (Shopee), entity: order -> App\Platform\Shopee\EntityParse\Order * - platform_id: 2 (Tmall), entity: product -> App\Platform\Tmall\EntityParse\Product * * @param int $platformId * @param string $entityType * @return class-string|null */ private static function findByConvention(int $platformId, string $entityType): ?string { // 从数据库查询平台信息 $platform = Platform::find($platformId); if (!$platform || !isset($platform->name)) { return null; } // 使用平台名称构建类名(处理多词平台名,如 "Amazon Japan" -> "AmazonJapan") $platformPascal = Str::of($platform->name) ->replace(' ', '') // 移除空格 ->studly() // 转换为 StudlyCase ->toString(); $entityPascal = Str::of($entityType)->studly()->toString(); // 标准命名:App\Platform\Shopee\EntityParse\Order $class = "App\\Platform\\{$platformPascal}\\EntityParse\\{$entityPascal}"; if (class_exists($class) && is_subclass_of($class, EntityParse::class)) { return $class; } return null; } /** * 手动注册平台与 Parser 的映射关系 * * @param int $platformId 平台 ID(如:25 表示 Shopee) * @param string $entityType 实体类型(小写),使用 '*' 表示匹配所有实体类型 * @param class-string $parserClass Parser 类名 * @return void * @throws InvalidArgumentException */ public static function register(int $platformId, string $entityType, string $parserClass): void { // 验证 Parser 类是否存在 if (!class_exists($parserClass)) { throw new InvalidArgumentException("Parser class '{$parserClass}' does not exist"); } // 验证 Parser 类是否继承自 EntityParse if (!is_subclass_of($parserClass, EntityParse::class)) { throw new InvalidArgumentException( "Parser class '{$parserClass}' must extend " . EntityParse::class ); } // 注册映射 self::$registry[$platformId][$entityType] = $parserClass; } /** * 批量注册平台映射 * * @param array>> $mappings * @return void */ public static function registerBatch(array $mappings): void { foreach ($mappings as $platformId => $entities) { foreach ($entities as $entityType => $parserClass) { self::register($platformId, $entityType, $parserClass); } } } /** * 获取所有已注册的映射 * * @return array>> */ public static function getRegistry(): array { return self::$registry; } /** * 清空所有注册的映射(主要用于测试) * * @return void */ public static function clearRegistry(): void { self::$registry = []; } /** * 检查指定平台和实体类型的 Parser 是否已注册 * * @param int $platformId * @param string $entityType * @return bool */ public static function hasParser(int $platformId, string $entityType): bool { return isset(self::$registry[$platformId][$entityType]) || isset(self::$registry[$platformId]['*']); } }