milpa/workflow
Composer 安装命令:
composer require milpa/workflow
包简介
ORM-backed data-driven state machine for the Milpa PHP framework: states, transitions and approval gates with evidence, plus a VerifierInterface bridge into the core verification seam.
README 文档
README
Milpa Workflow
The ORM-backed, data-driven state machine of the Milpa PHP framework: states, transitions and approval gates — with evidence attachments — configured in the database instead of hardcoded, plus
StateMachineVerifier, a bridge ontomilpa/core'sVerifierInterface.
milpa/workflow is the family's first tier-2 package: Doctrine ORM is an honest
runtime dependency (used only through findBy/findOneBy/QueryBuilder on the
package's own entities), not a zero-dep primitive like milpa/core. Everything else
about the family still holds — no product coupling, no concrete container, opaque
identity.
Install
composer require milpa/workflow
Quick example
use Milpa\Workflow\StateMachine\DataDrivenStateMachine; use Milpa\Workflow\StateMachine\TransitionContext; use Milpa\Workflow\Gates\DefaultGateEvaluator; use Milpa\Workflow\Services\GatePassageService; // $em is a Doctrine\ORM\EntityManagerInterface wired to a schema that has run // doctrine/orm's schema tool over Milpa\Workflow\Entities\*; $gate is a // GateDefinition your domain configured (e.g. persisted via a migration/seeder). $stateMachine = new DataDrivenStateMachine($em, new DefaultGateEvaluator()); $gateService = new GatePassageService($em); // Ask whether 'lead' -> 'qualified' is currently possible for domain 'opportunity'. $context = new TransitionContext(actorId: 7, actorRole: 'sales', entityId: 99, domain: 'opportunity'); $result = $stateMachine->canTransition('opportunity', 'lead', 'qualified', $context); if (!$result->isPassed()) { // $result->missingFields / $result->missingEvidence explain exactly what's missing. } // Request (and later approve) a gate passage against a GateDefinition your domain // configured (e.g. `$em->getRepository(GateDefinition::class)->findOneBy([...])`). // Principals are opaque strings the engine never resolves — the consuming product // owns identity. $passage = $gateService->requestPassage($gate, 'opportunity', 99, requesterId: 'member:7'); $gateService->approvePassage($passage, approverId: 'member:12', notes: 'fit score confirmed');
What it does — and doesn't
Contracts\StateMachineInterface(implemented byStateMachine\DataDrivenStateMachine) — readsEntities\StateDefinition/TransitionDefinition/GateDefinitionfrom the database to answercanTransition(),getAvailableTransitions(),transition(), and lookups by domain/code. No transition graph is hardcoded in PHP.Contracts\GateServiceInterface(implemented byServices\GatePassageService) — request/approve/reject/waive an append-onlyEntities\GatePassage, with the anti-self-approval constraint enforced at the service layer (Exceptions\SelfApprovalException).Verification\StateMachineVerifier— runs the gate machinery throughmilpa/core'sVerifierInterface: a genericVerificationRequest/VerificationContextin, aVerificationResultout, bridged losslessly throughStateMachine\GateResult. This is the monorepo's only automatedVerifierInterfaceimplementation — the deterministic counterpart to a human/agent-supplied verification.- Opaque identity everywhere a principal is stored:
Entities\Evidence::$uploadedByandEntities\GatePassage::$requestedBy/$approvedByare plain strings such as"member:42". The engine never resolves them to an entity — the consuming product owns identity resolution (seeADR-001/ design note D9). - No product coupling. The polymorphic
entity_type/entity_idpair onGatePassagelets any domain (opportunity, project, invoice, ...) register its own states/transitions/gates without this package knowing about it.
Namespace layout
Public contracts live under Contracts/ (not Interfaces/, which is milpa/core's
established, already-published convention) — this package follows the family
convention adopted from ola 2 onward: new packages use Contracts/ for
interfaces/value-objects that form the package's public seam, while
concern-scoped strategy interfaces stay colocated with their concern
(StateMachine\GateEvaluatorInterface lives in StateMachine/, next to the
GateResult/TransitionContext types it operates on).
Testing
The test suite is standalone: it exercises the state machine's transition/gate
logic and the StateMachineVerifier bridge against stub implementations of
Contracts\StateMachineInterface/StateMachine\GateEvaluatorInterface and
hand-built entity graphs — no live database, no Doctrine bootstrap. The two
Doctrine-backed services (StateMachine\DataDrivenStateMachine's repository
lookups and Services\GatePassageService's persistence) talk to
EntityManagerInterface through findBy/findOneBy/QueryBuilder only; nothing
in this package requires a schema migration or a running MySQL to validate its
logic.
Requirements
- PHP ≥ 8.3
doctrine/orm^3.0 (the package's one runtime dependency beyondmilpa/core)milpa/core—VerifierInterface, theVerificationRequest/VerificationContext/VerificationResultvalue objects, andSupport\UuidGenerator
Documentation
Full API reference: getmilpa.github.io/workflow — generated straight from the source DocBlocks and dressed with the Milpa design system.
Contributing
Contributions are welcome — see CONTRIBUTING.md. Please report security issues via SECURITY.md, and note that this project follows a Code of Conduct.
License
Apache-2.0 © TeamX Agency.
Milpa is designed, built, and maintained by TeamX Agency.
统计信息
- 总下载量: 0
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 0
- 点击次数: 1
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: Apache-2.0
- 更新时间: 2026-07-08