--- name: acc-create-action description: Generates ADR Action classes for PHP 8.5. Creates single-responsibility HTTP endpoint handlers with PSR-7 support. Includes unit tests. --- # Action Generator Generate ADR-compliant Action classes for HTTP endpoints. ## Action Characteristics - **Single Responsibility**: One action = one HTTP endpoint - **Input Parsing**: Collects and parses request input - **Domain Invocation**: Calls UseCase/Handler - **Response Delegation**: Passes result to Responder - **No Business Logic**: Thin coordination layer - **Invokable**: Single `__invoke()` method ## Template ```php handler->handle($command); return $this->responder->respond($result); } {privateMethods} } ``` ## Test Template ```php handler = $this->createMock({Action}Handler::class); $this->responder = $this->createMock({Action}Responder::class); $this->action = new {Action}Action($this->handler, $this->responder); } public function testInvokesHandlerWithCommand(): void { $request = $this->createRequest([{testData}]); $result = $this->createMock({Action}Result::class); $response = $this->createMock(ResponseInterface::class); $this->handler ->expects($this->once()) ->method('handle') ->with($this->callback(fn ({Action}Command $cmd) => {commandAssertions} )) ->willReturn($result); $this->responder ->expects($this->once()) ->method('respond') ->with($result) ->willReturn($response); $actual = ($this->action)($request); self::assertSame($response, $actual); } private function createRequest(array $body): ServerRequestInterface { $stream = $this->createMock(StreamInterface::class); $request = $this->createMock(ServerRequestInterface::class); $request->method('getParsedBody')->willReturn($body); $request->method('getBody')->willReturn($stream); return $request; } } ``` ## Action Patterns by HTTP Method ### GET (Read Single) ```php getAttribute('id'); $query = new GetUserByIdQuery(userId: $userId); $result = $this->handler->handle($query); return $this->responder->respond($result); } } ``` ### GET (List with Pagination) ```php getQueryParams(); $query = new ListUsersQuery( page: (int) ($queryParams['page'] ?? 1), perPage: (int) ($queryParams['per_page'] ?? 20), search: $queryParams['search'] ?? null, ); $result = $this->handler->handle($query); return $this->responder->respond($result); } } ``` ### POST (Create) ```php getParsedBody(); $command = new CreateUserCommand( email: $body['email'] ?? '', name: $body['name'] ?? '', ); $result = $this->handler->handle($command); return $this->responder->respond($result); } } ``` ### PUT/PATCH (Update) ```php getAttribute('id'); $body = (array) $request->getParsedBody(); $command = new UpdateUserCommand( userId: $userId, name: $body['name'] ?? null, email: $body['email'] ?? null, ); $result = $this->handler->handle($command); return $this->responder->respond($result); } } ``` ### DELETE ```php getAttribute('id'); $command = new DeleteUserCommand(userId: $userId); $result = $this->handler->handle($command); return $this->responder->respond($result); } } ``` ## File Placement | Component | Path | |-----------|------| | Action | `src/Presentation/Api/{Context}/{Action}/{Action}Action.php` | | Action Interface | `src/Presentation/Shared/Action/ActionInterface.php` | | Test | `tests/Unit/Presentation/Api/{Context}/{Action}/{Action}ActionTest.php` | ## Generation Instructions When asked to create an Action: 1. **Identify HTTP method** (GET, POST, PUT, DELETE) 2. **Determine input source** (body, query params, route attributes) 3. **Identify Command/Query DTO** (what to pass to handler) 4. **Generate Action class** with proper namespace 5. **Generate test** with mocked dependencies ## Naming Conventions | HTTP Method | Action Name | Command/Query | |-------------|-------------|---------------| | GET (single) | Get{Resource}ByIdAction | Get{Resource}ByIdQuery | | GET (list) | List{Resource}sAction | List{Resource}sQuery | | POST | Create{Resource}Action | Create{Resource}Command | | PUT | Update{Resource}Action | Update{Resource}Command | | PATCH | Patch{Resource}Action | Patch{Resource}Command | | DELETE | Delete{Resource}Action | Delete{Resource}Command | ## References For detailed patterns and examples: - `references/templates.md` — Additional Action templates - `references/examples.md` — Real-world Action examples