Claude-skill-registry acc-create-state
Generates State pattern for PHP 8.5. Creates state machines with context, state interface, and concrete states for behavior changes. Includes unit tests.
install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/acc-create-state" ~/.claude/skills/majiayu000-claude-skill-registry-acc-create-state && rm -rf "$T"
manifest:
skills/data/acc-create-state/SKILL.mdsource content
State Pattern Generator
Creates State pattern infrastructure for objects that change behavior based on internal state.
When to Use
| Scenario | Example |
|---|---|
| Object behavior varies by state | Order (pending, paid, shipped) |
| Many conditionals based on state | Document workflow |
| State-specific transitions | Subscription lifecycle |
| Finite state machines | Payment processing |
Component Characteristics
StateInterface
- Defines available actions
- Returns new state after transition
- Encapsulates state-specific behavior
Context
- Holds current state
- Delegates actions to state
- Manages state transitions
Concrete States
- Implement behavior for each state
- Handle valid/invalid transitions
- Return appropriate next state
Generation Process
Step 1: Analyze State Machine
Determine:
- All possible states
- Actions/transitions between states
- Which actions are valid per state
- Terminal states (no outgoing transitions)
Step 2: Generate State Components
Path:
src/Domain/{BoundedContext}/State/
— State contract with all actions{Name}StateInterface.php
— Base class with default (invalid) implementationsAbstract{Name}State.php
— Concrete state for each state (PendingState, PaidState, etc.){StateName}State.php
— Factory for reconstitution from storage{Name}StateFactory.php
Path:
src/Domain/{BoundedContext}/Exception/
— Exception for invalid transitionsInvalidStateTransitionException.php
Step 3: Update Entity
Path:
src/Domain/{BoundedContext}/Entity/
Update entity to use state pattern with delegation methods.
Step 4: Generate Tests
Path:
tests/Unit/Domain/{BoundedContext}/State/
— Test each concrete state{StateName}StateTest.php
— Test full state machine{Entity}StateTransitionTest.php
File Placement
| Component | Path |
|---|---|
| State Interface | |
| Concrete States | |
| State Factory | |
| Entity with State | |
| Exception | |
| Unit Tests | |
Naming Conventions
| Component | Pattern | Example |
|---|---|---|
| Interface | | |
| Abstract State | | |
| Concrete State | | , |
| Factory | | |
| Exception | | |
| Test | | |
Quick Template Reference
State Interface
interface {Name}StateInterface { public function getName(): string; public function {action1}({Context} $context): self; public function {action2}({Context} $context): self; public function canTransitionTo(self $state): bool; /** @return array<string> */ public function allowedTransitions(): array; }
Abstract State
abstract readonly class Abstract{Name}State implements {Name}StateInterface { public function {action1}({Context} $context): {Name}StateInterface { throw InvalidStateTransitionException::actionNotAllowed('{action1}', $this->getName()); } public function canTransitionTo({Name}StateInterface $state): bool { return in_array($state->getName(), $this->allowedTransitions(), true); } }
Concrete State
final readonly class {StateName}State extends Abstract{Name}State { public function getName(): string { return '{state_name}'; } public function {action1}({Context} $context): {Name}StateInterface { $context->recordEvent(new {Event}($context->id())); return new {NextState}State(); } public function allowedTransitions(): array { return ['{next_state_1}', '{next_state_2}']; } }
State Factory
final class {Name}StateFactory { public static function fromName(string $name): {Name}StateInterface { return match ($name) { 'pending' => new PendingState(), 'confirmed' => new ConfirmedState(), default => throw new \InvalidArgumentException("Unknown state: $name"), }; } }
Usage Example
// Entity with state $order = new Order($id, $customerId, $items); $order->confirm(); // Pending -> Confirmed $order->pay(); // Confirmed -> Paid $order->ship(); // Paid -> Shipped $order->deliver(); // Shipped -> Delivered // Check state if ($order->isInState('delivered')) { // ... } // Reconstitute from storage $state = OrderStateFactory::fromName($row['state']); $order = new Order($id, $customerId, $items, $state);
State Diagram Template
┌──────────┐ action1 ┌──────────┐ action2 ┌──────────┐ │ State1 │───────────▶│ State2 │───────────▶│ State3 │ └────┬─────┘ └────┬─────┘ └──────────┘ │ │ │ cancel │ cancel │ │ ▼ ▼ ┌──────────┐ ┌──────────┐ │Cancelled │ │Cancelled │ └──────────┘ └──────────┘
Anti-patterns to Avoid
| Anti-pattern | Problem | Solution |
|---|---|---|
| Mutable States | Shared state pollution | Make states readonly |
| God State | One state handles all | Split into specific states |
| Missing Transitions | Silent failures | Throw on invalid action |
| State in Entity | Mixed concerns | Extract to State classes |
| No Factory | Hard to reconstitute | Add StateFactory |
References
For complete PHP templates and examples, see:
— State interface, abstract, concrete templatesreferences/templates.md
— Order state machine example and testsreferences/examples.md