update entiity parse
This commit is contained in:
@@ -9,7 +9,7 @@ use App\Model\Company;
|
||||
use App\Model\Platform;
|
||||
use App\Model\Store;
|
||||
use App\Entity\Parse\Traits\EntityParseHelper;
|
||||
use Hyperf\Amqp\Message\ConsumerMessageInterface;
|
||||
use Hyperf\Collection\LazyCollection;
|
||||
use InvalidArgumentException;
|
||||
|
||||
/**
|
||||
@@ -18,13 +18,13 @@ use InvalidArgumentException;
|
||||
* 使用工厂方法模式 + 延迟初始化
|
||||
* 提供消息解析的通用框架和默认实现
|
||||
*
|
||||
* @method static static create(ConsumerMessageInterface $message)
|
||||
* @method static static create(array $data)
|
||||
*/
|
||||
abstract class EntityParse implements EntityParseInterface
|
||||
{
|
||||
use EntityParseHelper;
|
||||
|
||||
protected ConsumerMessageInterface $message;
|
||||
protected array $data;
|
||||
protected ?Platform $platform = null;
|
||||
protected ?Company $company = null;
|
||||
protected ?Store $store = null;
|
||||
@@ -41,30 +41,67 @@ abstract class EntityParse implements EntityParseInterface
|
||||
/**
|
||||
* 工厂方法:创建解析器实例
|
||||
*
|
||||
* @param ConsumerMessageInterface $message
|
||||
* @param array $data
|
||||
* @return static
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public static function create(ConsumerMessageInterface $message): static
|
||||
public static function create(array $data): static
|
||||
{
|
||||
$instance = new static();
|
||||
$instance->message = $message;
|
||||
$instance->data = $data;
|
||||
|
||||
// 在初始化前先验证数据
|
||||
if (!$instance->messageValidate($data)) {
|
||||
throw new InvalidArgumentException('Message validation failed: required fields missing');
|
||||
}
|
||||
|
||||
$instance->initialize();
|
||||
return $instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* 消息数据验证
|
||||
*
|
||||
* 默认实现:验证必需字段
|
||||
* 子类可以覆写以添加自定义验证逻辑
|
||||
*
|
||||
* @param array $data
|
||||
* @return bool
|
||||
*/
|
||||
public function messageValidate(array $data): bool
|
||||
{
|
||||
// 验证必需字段
|
||||
$requiredFields = ['company_id', 'platform_id', 'store_id', 'unique_id', 'raw_data'];
|
||||
|
||||
foreach ($requiredFields as $field) {
|
||||
if (!isset($data[$field])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 延迟初始化
|
||||
* 在 message 设置后执行作用域匹配和验证
|
||||
* 在 data 设置后执行作用域匹配和验证
|
||||
*
|
||||
* @return void
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
protected function initialize(): void
|
||||
{
|
||||
$this->platform = $this->platformScopeMatch($this->message);
|
||||
$this->company = $this->companyScopeMatch($this->message);
|
||||
$this->store = $this->storeScopeMatch($this->message);
|
||||
// 提取 metadata
|
||||
$metadata = [
|
||||
'company_id' => $this->data['company_id'],
|
||||
'platform_id' => $this->data['platform_id'],
|
||||
'store_id' => $this->data['store_id'],
|
||||
'unique_id' => $this->data['unique_id'],
|
||||
];
|
||||
|
||||
$this->platform = $this->platformScopeMatch($metadata);
|
||||
$this->company = $this->companyScopeMatch($metadata);
|
||||
$this->store = $this->storeScopeMatch($metadata);
|
||||
|
||||
$this->validateScope();
|
||||
}
|
||||
@@ -93,47 +130,46 @@ abstract class EntityParse implements EntityParseInterface
|
||||
/**
|
||||
* 平台作用域匹配 - 提供默认实现
|
||||
*
|
||||
* 从 exchange 名称中提取平台信息
|
||||
* 从 metadata 中提取平台信息
|
||||
* 子类可以覆盖此方法以实现自定义逻辑
|
||||
*
|
||||
* @param ConsumerMessageInterface $message
|
||||
* @param array $metadata
|
||||
* @return Platform
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function platformScopeMatch(ConsumerMessageInterface $message): Platform
|
||||
public function platformScopeMatch(array $metadata): Platform
|
||||
{
|
||||
return $this->extractPlatformFromExchange($message);
|
||||
return $this->extractPlatformFromMetadata($metadata);
|
||||
}
|
||||
|
||||
/**
|
||||
* 实体匹配 - 提供默认实现
|
||||
*
|
||||
* 从 routing key 中提取实体类型
|
||||
* 从 metadata 中提取实体类型
|
||||
* 子类可以覆盖此方法以实现自定义逻辑
|
||||
*
|
||||
* @param ConsumerMessageInterface $message
|
||||
* @param array $metadata
|
||||
* @return Entity
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function entityMatch(ConsumerMessageInterface $message): Entity
|
||||
public function entityMatch(array $metadata): Entity
|
||||
{
|
||||
return $this->extractEntityFromRoutingKey($message);
|
||||
return $this->extractEntityFromMetadata($metadata);
|
||||
}
|
||||
|
||||
/**
|
||||
* 唯一标识符提取 - 提供默认实现
|
||||
*
|
||||
* 默认从消息体中提取 id 或 unique_id
|
||||
* 默认从 metadata 中提取 unique_id
|
||||
* 子类可以覆盖此方法以实现自定义逻辑
|
||||
*
|
||||
* @param ConsumerMessageInterface $message
|
||||
* @param array $metadata
|
||||
* @return string|int
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function entityUniqueIdentifierExtract(ConsumerMessageInterface $message): string|int
|
||||
public function entityUniqueIdentifierExtract(array $metadata): string|int
|
||||
{
|
||||
$data = $this->extractMessageData($message);
|
||||
return $this->extractUniqueIdentifier($data);
|
||||
return $metadata['unique_id'] ?? throw new InvalidArgumentException('unique_id not found in metadata');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -141,42 +177,41 @@ abstract class EntityParse implements EntityParseInterface
|
||||
*
|
||||
* 必须由子类实现,因为不同平台的公司识别逻辑不同
|
||||
*
|
||||
* @param ConsumerMessageInterface $message
|
||||
* @param array $metadata
|
||||
* @return Company
|
||||
*/
|
||||
abstract public function companyScopeMatch(ConsumerMessageInterface $message): Company;
|
||||
abstract public function companyScopeMatch(array $metadata): Company;
|
||||
|
||||
/**
|
||||
* 店铺作用域匹配 - 抽象方法
|
||||
*
|
||||
* 必须由子类实现,因为不同平台的店铺识别逻辑不同
|
||||
*
|
||||
* @param ConsumerMessageInterface $message
|
||||
* @param array $metadata
|
||||
* @return Store
|
||||
*/
|
||||
abstract public function storeScopeMatch(ConsumerMessageInterface $message): Store;
|
||||
abstract public function storeScopeMatch(array $metadata): Store;
|
||||
|
||||
/**
|
||||
* 实体数据映射 - 抽象方法
|
||||
*
|
||||
* 必须由子类实现,因为不同平台的数据结构不同
|
||||
*
|
||||
* @param array $data
|
||||
* @param Entity $entity
|
||||
* @return Entity
|
||||
* @param array $rawData
|
||||
* @return LazyCollection
|
||||
*/
|
||||
abstract public function entityMap(array $data, Entity $entity): Entity;
|
||||
abstract public function entityMap(array $rawData): LazyCollection;
|
||||
|
||||
// ==================== Getter 方法 ====================
|
||||
|
||||
/**
|
||||
* 获取消息对象
|
||||
* 获取消息数据
|
||||
*
|
||||
* @return ConsumerMessageInterface
|
||||
* @return array
|
||||
*/
|
||||
public function getMessage(): ConsumerMessageInterface
|
||||
public function getData(): array
|
||||
{
|
||||
return $this->message;
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -9,6 +9,7 @@ use Hyperf\Contract\ConfigInterface;
|
||||
use Hyperf\Stringable\Str;
|
||||
use InvalidArgumentException;
|
||||
use Psr\Container\ContainerInterface;
|
||||
use PhpAmqpLib\Message\AMQPMessage;
|
||||
|
||||
/**
|
||||
* EntityParseFactory 工厂类
|
||||
@@ -102,66 +103,90 @@ class EntityParseFactory
|
||||
/**
|
||||
* 根据消息自动创建 Parser 实例(静态方法)
|
||||
*
|
||||
* @param ConsumerMessageInterface $message
|
||||
* @param string|null $entityType 实体类型(可选,如果不指定则从 routing key 中提取)
|
||||
* @param AMQPMessage $message
|
||||
* @param string|null $entityType 实体类型(可选,如果不指定则从 payload 中提取)
|
||||
* @return EntityParseInterface
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public static function createFromMessage(
|
||||
ConsumerMessageInterface $message,
|
||||
AMQPMessage $message,
|
||||
?string $entityType = null
|
||||
): EntityParseInterface {
|
||||
// 1. 从 exchange 中提取平台名称
|
||||
$platformName = self::extractPlatformName($message);
|
||||
// 1. 从消息体中解析数据
|
||||
$data = json_decode($message->getBody(), true);
|
||||
|
||||
// 2. 如果未指定实体类型,从 routing key 中提取
|
||||
if ($entityType === null) {
|
||||
$entityType = self::extractEntityType($message);
|
||||
if (!is_array($data)) {
|
||||
throw new InvalidArgumentException('Invalid message body: expected JSON array');
|
||||
}
|
||||
|
||||
// 3. 获取对应的 Parser 类
|
||||
// 2. 从 data 中提取平台名称
|
||||
$platformName = self::extractPlatformNameFromData($data);
|
||||
|
||||
// 3. 如果未指定实体类型,从 data 或 routing key 中提取
|
||||
if ($entityType === null) {
|
||||
$entityType = self::extractEntityTypeFromData($data, $message);
|
||||
}
|
||||
|
||||
// 4. 获取对应的 Parser 类
|
||||
$parserClass = self::resolveParserClass($platformName, $entityType);
|
||||
|
||||
// 4. 创建并返回 Parser 实例
|
||||
return $parserClass::create($message);
|
||||
// 5. 创建并返回 Parser 实例,传递解析后的数据
|
||||
return $parserClass::create($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从 exchange 中提取平台名称
|
||||
* 从数据中提取平台名称
|
||||
*
|
||||
* 规则:exchange 格式为 "platform.exchange"
|
||||
* 例如:tmall.exchange -> tmall
|
||||
*
|
||||
* @param ConsumerMessageInterface $message
|
||||
* @param array $data
|
||||
* @return string
|
||||
*/
|
||||
private static function extractPlatformName(ConsumerMessageInterface $message): string
|
||||
private static function extractPlatformNameFromData(array $data): string
|
||||
{
|
||||
$exchange = $message->getExchange();
|
||||
|
||||
$platformName = Str::of($exchange)
|
||||
->before('.')
|
||||
->lower()
|
||||
->toString();
|
||||
|
||||
if (empty($platformName)) {
|
||||
throw new InvalidArgumentException("Cannot extract platform name from exchange: {$exchange}");
|
||||
// 优先从 platform_id 获取,如果没有则尝试从其他字段获取
|
||||
if (isset($data['platform_id'])) {
|
||||
// 这里可以根据 platform_id 映射到平台名称
|
||||
// 简化处理:假设需要从数据库或配置中查找
|
||||
// 当前先直接使用 platform_id 作为平台名称
|
||||
return self::resolvePlatformName($data['platform_id']);
|
||||
}
|
||||
|
||||
return $platformName;
|
||||
throw new InvalidArgumentException("Cannot extract platform name from data: platform_id missing");
|
||||
}
|
||||
|
||||
/**
|
||||
* 从 routing key 中提取实体类型
|
||||
* 根据 platform_id 解析平台名称
|
||||
*
|
||||
* 规则:routing key 格式为 "entity.action"
|
||||
* 例如:order.create -> order
|
||||
*
|
||||
* @param ConsumerMessageInterface $message
|
||||
* @param mixed $platformId
|
||||
* @return string
|
||||
*/
|
||||
private static function extractEntityType(ConsumerMessageInterface $message): string
|
||||
private static function resolvePlatformName($platformId): string
|
||||
{
|
||||
// TODO: 从配置或数据库中根据 platform_id 查找平台名称
|
||||
// 临时方案:使用简单的映射
|
||||
$platformMap = [
|
||||
1 => 'taobao',
|
||||
2 => 'tmall',
|
||||
3 => 'jd',
|
||||
// ... 其他平台
|
||||
];
|
||||
|
||||
if (isset($platformMap[$platformId])) {
|
||||
return $platformMap[$platformId];
|
||||
}
|
||||
|
||||
throw new InvalidArgumentException("Unknown platform_id: {$platformId}");
|
||||
}
|
||||
|
||||
/**
|
||||
* 从数据或路由键中提取实体类型
|
||||
*
|
||||
* @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)
|
||||
@@ -169,11 +194,11 @@ class EntityParseFactory
|
||||
->lower()
|
||||
->toString();
|
||||
|
||||
if (empty($entityType)) {
|
||||
throw new InvalidArgumentException("Cannot extract entity type from routing key: {$routingKey}");
|
||||
if (!empty($entityType)) {
|
||||
return $entityType;
|
||||
}
|
||||
|
||||
return $entityType;
|
||||
throw new InvalidArgumentException("Cannot extract entity type from routing key: {$routingKey}");
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,11 +4,11 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Entity\Parse;
|
||||
|
||||
use Hyperf\Amqp\Message\ConsumerMessageInterface;
|
||||
use App\Model\Company;
|
||||
use App\Model\Platform;
|
||||
use App\Model\Store;
|
||||
use App\Model\Model as Entity;
|
||||
use Hyperf\Collection\LazyCollection;
|
||||
|
||||
/**
|
||||
* EntityParseInterface 接口
|
||||
@@ -17,61 +17,74 @@ use App\Model\Model as Entity;
|
||||
*/
|
||||
interface EntityParseInterface
|
||||
{
|
||||
/**
|
||||
* 消息数据验证
|
||||
*
|
||||
* 验证消息数据是否包含必需字段
|
||||
*
|
||||
* @param array $data
|
||||
* @return bool
|
||||
*/
|
||||
public function messageValidate(array $data): bool;
|
||||
|
||||
/**
|
||||
* 公司作用域匹配
|
||||
*
|
||||
* @param ConsumerMessageInterface $message
|
||||
* @param array $metadata
|
||||
* @return Company
|
||||
*/
|
||||
public function companyScopeMatch(ConsumerMessageInterface $message): Company;
|
||||
public function companyScopeMatch(array $metadata): Company;
|
||||
|
||||
/**
|
||||
* 平台作用域匹配
|
||||
*
|
||||
* @param ConsumerMessageInterface $message
|
||||
* @param array $metadata
|
||||
* @return Platform
|
||||
*/
|
||||
public function platformScopeMatch(ConsumerMessageInterface $message): Platform;
|
||||
public function platformScopeMatch(array $metadata): Platform;
|
||||
|
||||
/**
|
||||
* 店铺作用域匹配
|
||||
*
|
||||
* @param ConsumerMessageInterface $message
|
||||
* @param array $metadata
|
||||
* @return Store
|
||||
*/
|
||||
public function storeScopeMatch(ConsumerMessageInterface $message): Store;
|
||||
public function storeScopeMatch(array $metadata): Store;
|
||||
|
||||
/**
|
||||
* 实体类型匹配
|
||||
*
|
||||
* @param ConsumerMessageInterface $message
|
||||
* 根据 metadata 返回实体模板实例
|
||||
*
|
||||
* @param array $metadata
|
||||
* @return Entity
|
||||
*/
|
||||
public function entityMatch(ConsumerMessageInterface $message): Entity;
|
||||
public function entityMatch(array $metadata): Entity;
|
||||
|
||||
/**
|
||||
* 实体数据映射
|
||||
*
|
||||
* @param array $data
|
||||
* @param Entity $entity
|
||||
* @return Entity
|
||||
* 将原始数据转换为可填充到 Model 的数据集合
|
||||
*
|
||||
* @param array $rawData
|
||||
* @return LazyCollection
|
||||
*/
|
||||
public function entityMap(array $data, Entity $entity): Entity;
|
||||
public function entityMap(array $rawData): LazyCollection;
|
||||
|
||||
/**
|
||||
* 提取实体唯一标识符
|
||||
*
|
||||
* @param ConsumerMessageInterface $message
|
||||
* @param array $metadata
|
||||
* @return string|int
|
||||
*/
|
||||
public function entityUniqueIdentifierExtract(ConsumerMessageInterface $message): string|int;
|
||||
public function entityUniqueIdentifierExtract(array $metadata): string|int;
|
||||
|
||||
/**
|
||||
* 获取消息对象
|
||||
* 获取消息数据
|
||||
*
|
||||
* @return ConsumerMessageInterface
|
||||
* @return array
|
||||
*/
|
||||
public function getMessage(): ConsumerMessageInterface;
|
||||
public function getData(): array;
|
||||
|
||||
/**
|
||||
* 获取平台对象
|
||||
|
||||
Reference in New Issue
Block a user