3471deb3f1
- 修改 AbstractProcessNode 中 ProcessContext 的命名空间引用为 app\flow\context\ProcessContext - 引入 app\flow\vo\CanHandleResult 用于节点处理结果表示 - 更新前置策略执行后对成功状态的判断,改为调用 isSuccess() 方法 - 增加日志记录细节,便于调试策略执行中断时的错误信息 - 优化代码注释,提升代码可读性和维护性
381 lines
9.8 KiB
PHP
381 lines
9.8 KiB
PHP
<?php
|
|
|
|
namespace app\flow;
|
|
|
|
use app\flow\config\ProcessConfig;
|
|
use app\flow\context\ProcessContext;
|
|
use app\flow\enum\VoiceMessage;
|
|
use app\flow\nodes\MorningWashNode;
|
|
use app\flow\nodes\ProcessNodeInterface;
|
|
use app\flow\strategies\MorningWashStrategy;
|
|
use app\flow\strategies\TimeValidationStrategy;
|
|
use app\flow\strategies\VoiceGenerationStrategy;
|
|
use app\utils\Logger;
|
|
|
|
/**
|
|
* 流程引擎类
|
|
* 组装流程链并执行流程
|
|
*/
|
|
class ProcessEngine
|
|
{
|
|
/**
|
|
* 流程配置
|
|
*/
|
|
protected ProcessConfig $config;
|
|
|
|
/**
|
|
* 流程链头节点
|
|
*/
|
|
protected ?ProcessNodeInterface $chainHead = null;
|
|
|
|
/**
|
|
* 节点映射表
|
|
*/
|
|
protected array $nodeMap = [];
|
|
|
|
/**
|
|
* 策略实例
|
|
*/
|
|
protected array $strategies = [];
|
|
|
|
/**
|
|
* 节点命名空间
|
|
*/
|
|
protected string $nodeNamespace = 'app\\flow\\nodes\\';
|
|
|
|
/**
|
|
* 构造函数
|
|
*/
|
|
public function __construct(?ProcessConfig $config = null)
|
|
{
|
|
$this->config = $config ?? new ProcessConfig();
|
|
$this->initStrategies();
|
|
$this->buildChain();
|
|
}
|
|
|
|
/**
|
|
* 初始化策略
|
|
*/
|
|
protected function initStrategies(): void
|
|
{
|
|
Logger::debug("[ProcessEngine] 初始化策略...");
|
|
// 晨洗判断策略
|
|
$this->strategies['morning_wash'] = new MorningWashStrategy(
|
|
$this->config->getMorningWashConfig()
|
|
);
|
|
|
|
// 时间验证策略
|
|
$this->strategies['time_validation'] = new TimeValidationStrategy(
|
|
$this->config->getTimeValidationConfig()
|
|
);
|
|
|
|
// 语音生成策略
|
|
$this->strategies['voice_generation'] = new VoiceGenerationStrategy(
|
|
$this->config->getVoiceTemplatesConfig()
|
|
);
|
|
Logger::debug("[ProcessEngine] 策略初始化完成");
|
|
}
|
|
|
|
/**
|
|
* 构建流程链
|
|
*/
|
|
protected function buildChain(): void
|
|
{
|
|
Logger::debug("[ProcessEngine] 构建流程链...");
|
|
$steps = $this->config->getSteps();
|
|
$prevNode = null;
|
|
|
|
foreach ($steps as $step) {
|
|
$node = $this->createNode($step->class);
|
|
Logger::debug("[ProcessEngine] 创建节点 {}", [$step->class]);
|
|
|
|
if ($node === null) {
|
|
Logger::warning("[ProcessEngine] 无法创建节点 {}", [$step->class]);
|
|
continue;
|
|
}
|
|
|
|
// 设置节点启用状态
|
|
$node->setEnabled($step->enabled);
|
|
Logger::debug(" [{}] 启用状态 {}", [$node->getName(), $step->enabled]);
|
|
|
|
// 添加策略
|
|
$this->attachStrategies($node, $step->code);
|
|
Logger::debug("[{}] 策略添加完成", [$node->getName()]);
|
|
|
|
// 保存到映射表
|
|
$this->nodeMap[$step->code] = $node;
|
|
Logger::debug("[{}] 保存到映射表", [$node->getName()]);
|
|
|
|
// 构建流程链
|
|
if ($prevNode === null) {
|
|
$this->chainHead = $node;
|
|
} else {
|
|
$prevNode->setNext($node);
|
|
}
|
|
// 添加配置
|
|
$node->setConfig($step);
|
|
Logger::debug("[{}] 设置原始配置: {}", [$node->getName(), json_encode($step)]);
|
|
|
|
$prevNode = $node;
|
|
Logger::debug("[{}] 节点创建完成", [$node->getName()]);
|
|
}
|
|
Logger::debug("[ProcessEngine] 流程链构建完成");
|
|
}
|
|
|
|
/**
|
|
* 创建节点实例
|
|
*/
|
|
protected function createNode(string $className): ?ProcessNodeInterface
|
|
{
|
|
// 添加命名空间
|
|
if (!str_contains($className, '\\')) {
|
|
$className = $this->nodeNamespace . $className;
|
|
}
|
|
|
|
if (!class_exists($className)) {
|
|
return null;
|
|
}
|
|
|
|
return new $className();
|
|
}
|
|
|
|
/**
|
|
* 为节点附加策略
|
|
*/
|
|
protected function attachStrategies(ProcessNodeInterface $node, string $stepCode): void
|
|
{
|
|
// 晨洗节点添加晨洗判断策略
|
|
if ($stepCode === MorningWashNode::getName()) {
|
|
$node->addStrategy($this->strategies['morning_wash']);
|
|
Logger::debug("[{}] 添加 MorningWashStrategy", [$node->getName()]);
|
|
}
|
|
|
|
// 有时间要求的步骤添加时间验证策略
|
|
$timeSteps = ['清洗', '漂洗', '消毒', '终末漂洗', '干燥'];
|
|
if (in_array($stepCode, $timeSteps)) {
|
|
$node->addStrategy($this->strategies['time_validation']);
|
|
Logger::debug("[{}] 添加 TimeValidationStrategy", [$node->getName()]);
|
|
}
|
|
|
|
// 除了晨洗所有节点都添加语音生成策略
|
|
if ($stepCode !== MorningWashNode::getName()) {
|
|
$node->addStrategy($this->strategies['voice_generation']);
|
|
Logger::debug("[{}] 添加 VoiceGenerationStrategy", [$node->getName()]);
|
|
}
|
|
|
|
// 存储节点添加语音生成策略
|
|
if ($stepCode === '存储') {
|
|
$node->addStrategy($this->strategies['voice_generation']);
|
|
Logger::debug("[{}] 存储节点配置完成", [$node->getName()]);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 执行流程
|
|
*/
|
|
public function execute(ProcessContext $context): ProcessContext
|
|
{
|
|
if ($this->chainHead === null) {
|
|
return $context->builder()->error(VoiceMessage::PROCESS_CHAIN_NOT_INITIALIZED)->build();
|
|
}
|
|
|
|
Logger::debug('[ProcessEngine] 开始执行流程链 readerType={} currentStep={} endoscope={}', [
|
|
$context->getReader()->type,
|
|
$context->getCurrentStep() ?: '(空)',
|
|
$context->getEndoscope()->name ?: $context->getEndoscope()->id ?: '-',
|
|
]);
|
|
|
|
$result = $this->chainHead->handle($context);
|
|
|
|
Logger::debug('[ProcessEngine] 流程执行完成 endoscope={} step={} success={} error={}', [
|
|
$result->getEndoscope()->name,
|
|
$result->getCurrentStep(),
|
|
$result->isSuccess() ? 'true' : 'false',
|
|
$result->getVoice()->errorMessage->value ?: '-',
|
|
]);
|
|
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* 快速执行(从数组创建上下文)
|
|
*/
|
|
public function executeFromArray(array $data): ProcessContext
|
|
{
|
|
$context = ProcessContext::create($data);
|
|
return $this->execute($context);
|
|
}
|
|
|
|
/**
|
|
* 获取配置
|
|
*/
|
|
public function getConfig(): ProcessConfig
|
|
{
|
|
return $this->config;
|
|
}
|
|
|
|
/**
|
|
* 更新配置并重建流程链
|
|
*/
|
|
public function updateConfig(ProcessConfig $config): self
|
|
{
|
|
$this->config = $config;
|
|
$this->nodeMap = [];
|
|
$this->chainHead = null;
|
|
$this->initStrategies();
|
|
$this->buildChain();
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* 获取节点
|
|
*/
|
|
public function getNode(string $code): ?ProcessNodeInterface
|
|
{
|
|
return $this->nodeMap[$code] ?? null;
|
|
}
|
|
|
|
/**
|
|
* 启用节点
|
|
*/
|
|
public function enableNode(string $code): self
|
|
{
|
|
$this->config->enableStep($code);
|
|
|
|
if (isset($this->nodeMap[$code])) {
|
|
$this->nodeMap[$code]->setEnabled(true);
|
|
}
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* 禁用节点
|
|
*/
|
|
public function disableNode(string $code): self
|
|
{
|
|
$this->config->skipStep($code);
|
|
|
|
if (isset($this->nodeMap[$code])) {
|
|
$this->nodeMap[$code]->setEnabled(false);
|
|
}
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* 设置节点启用状态
|
|
*/
|
|
public function setNodeEnabled(string $code, bool $enabled): self
|
|
{
|
|
return $enabled ? $this->enableNode($code) : $this->disableNode($code);
|
|
}
|
|
|
|
/**
|
|
* 获取所有节点
|
|
*/
|
|
public function getNodes(): array
|
|
{
|
|
return $this->nodeMap;
|
|
}
|
|
|
|
/**
|
|
* 获取启用的节点
|
|
*/
|
|
public function getEnabledNodes(): array
|
|
{
|
|
return array_filter($this->nodeMap, function ($node) {
|
|
return $node->isEnabled();
|
|
});
|
|
}
|
|
|
|
/**
|
|
* 添加自定义策略
|
|
*/
|
|
public function addStrategy(string $name, $strategy): self
|
|
{
|
|
$this->strategies[$name] = $strategy;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* 获取策略
|
|
*/
|
|
public function getStrategy(string $name)
|
|
{
|
|
return $this->strategies[$name] ?? null;
|
|
}
|
|
|
|
/**
|
|
* 设置步骤自定义语音
|
|
*/
|
|
public function setStepVoice(string $stepCode, string $voice): self
|
|
{
|
|
$this->config->setStepVoice($stepCode, $voice);
|
|
|
|
// 更新语音生成策略
|
|
if (isset($this->strategies['voice_generation'])) {
|
|
$this->strategies['voice_generation']->setStepVoice($stepCode, $voice);
|
|
}
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* 设置晨洗模式
|
|
*/
|
|
public function setMorningWashMode(string $mode): self
|
|
{
|
|
$this->config->setMorningWashMode($mode);
|
|
|
|
// 更新晨洗策略
|
|
if (isset($this->strategies['morning_wash'])) {
|
|
$this->strategies['morning_wash'] = new MorningWashStrategy(
|
|
$this->config->getMorningWashConfig()
|
|
);
|
|
}
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* 创建引擎(静态工厂方法)
|
|
*/
|
|
public static function create(?ProcessConfig $config = null): self
|
|
{
|
|
return new self($config);
|
|
}
|
|
|
|
/**
|
|
* 创建标准流程引擎
|
|
*/
|
|
public static function createStandard(): self
|
|
{
|
|
return new self(ProcessConfig::createStandard());
|
|
}
|
|
|
|
/**
|
|
* 创建无晨洗流程引擎
|
|
*/
|
|
public static function createNoMorningWash(): self
|
|
{
|
|
return new self(ProcessConfig::createNoMorningWash());
|
|
}
|
|
|
|
/**
|
|
* 创建简化流程引擎
|
|
*/
|
|
public static function createSimple(): self
|
|
{
|
|
return new self(ProcessConfig::createSimple());
|
|
}
|
|
|
|
/**
|
|
* 创建机洗流程引擎
|
|
*/
|
|
public static function createMachineWash(): self
|
|
{
|
|
return new self(ProcessConfig::createMachineWash());
|
|
}
|
|
}
|