
# 操作触发器

`Queuety::on_action()` 可将普通的 WordPress 操作转换为持久化工作流调度。

这样就能搭建一条清晰的桥梁：

`WordPress action -> mapped payload -> durable workflow`

当有趣的事件已经在 WordPress 中发生，而耗时较长或成本较高的响应需要异步执行时，这种方式就很有用。

## 示例：保存文章时审核内容

```php
use Queuety\Queuety;

Queuety::on_action(
    'save_post',
    workflow: 'content_review',
    map: static fn ( int $post_id, object $post, bool $update ): array => [
        'post_id' => $post_id,
        'post_type' => $post->post_type,
        'update' => $update,
    ],
    when: static fn ( int $post_id, object $post ): bool => 'post' === $post->post_type,
    idempotency_key: static fn ( int $post_id ): string => "save_post:{$post_id}",
);
```

在该示例中：

- `save_post` 仍是原始的 WordPress 事件
- `map` 将原始钩子参数转换为普通工作流状态
- `when` 会在事件进入队列前跳过不需要的事件
- `idempotency_key` 可防止重复触发钩子时分派重复运行

## 同步运行的内容

操作回调本身仍在当前 WordPress 请求中运行。

这意味着以下部分是同步的：

- `when`
- `map`
- `idempotency_key`

只有分派后工作流步骤才会异步运行。

## 载荷规则

映射后的载荷应包含普通数组、标量和 `null`。

不要将 `WP_Post` 之类的原始 WordPress 对象直接传入工作流状态。请先在 `map()` 中将其规范化：

```php
Queuety::on_action(
    'save_post',
    workflow: 'content_review',
    map: static fn ( int $post_id, object $post, bool $update ): array => [
        'post_id' => $post_id,
        'post_type' => $post->post_type,
        'post_status' => $post->post_status,
        'update' => $update,
    ],
);
```

以 `_` 开头的键会被拒绝，因为这些名称保留给内部工作流状态使用。

## 接受的参数

注册操作回调时，WordPress 需要指定 `accepted_args` 数量。

默认情况下，Queuety 会根据你的 `map`、`when` 和 `idempotency_key` 回调推断该数量，因此常见用法无需额外配置：

```php
Queuety::on_action(
    'save_post',
    workflow: 'content_review',
    map: static fn ( int $post_id, object $post, bool $update ): array => [
        'post_id' => $post_id,
        'update' => $update,
    ],
);
```

如需手动覆盖，请明确传入 `accepted_args`：

```php
Queuety::on_action(
    'comment_post',
    workflow: 'comment_review',
    accepted_args: 2,
);
```

## 内联工作流构建器

你可以分派已注册的工作流名称或内联 `WorkflowBuilder`。

如果特定钩子的工作流定义在同一个引导文件中，内联构建器会很有用：

```php
$review = Queuety::workflow( 'comment_review' )
    ->then( ModerateCommentStep::class )
    ->then( NotifyModeratorStep::class );

Queuety::on_action(
    'comment_post',
    workflow: $review,
    map: static fn ( int $comment_id ): array => [
        'comment_id' => $comment_id,
    ],
    idempotency_key: static fn ( int $comment_id ): string => "comment:{$comment_id}",
);
```

## 适用场景

在以下情况下使用操作触发器：

- WordPress 已经会发出你关注的事件
- 响应需要在请求超时或工作进程重启后继续
- 后续工作可能需要分支、等待或审批
- 重复触发钩子时需要持久化幂等性

如果工作与 WordPress 事件边界无关，请改用直接的 `Queuety::dispatch()` 或 `Queuety::workflow()` 调用。

## 不适用于过滤器

`Queuety::on_action()` 有意仅用于操作。

过滤器是在请求期间同步执行的转换。它们通常应保持同步，因为 WordPress 需要立即返回经过过滤的值。
