requireOwnedListId($request, $args); return $this->json($response, [ 'items' => array_map($this->present(...), $this->items->allForList($listId)), ]); } /** * POST /api/lists/{listId}/items */ public function store(Request $request, Response $response, array $args): Response { $listId = $this->requireOwnedListId($request, $args); $validator = new Validator($this->body($request)); $text = $validator->requiredString('text', self::TEXT_MAX); $complete = $validator->optionalBool('complete') ?? false; $position = $validator->optionalInt('position', 0); $validator->assert(); $item = $this->items->create($listId, $text, $complete, $position); $this->lists->touch($listId); return $this->json($response, ['item' => $this->present($item)], 201); } /** * GET /api/lists/{listId}/items/{itemId} */ public function show(Request $request, Response $response, array $args): Response { $listId = $this->requireOwnedListId($request, $args); return $this->json($response, ['item' => $this->present($this->requireItem($listId, $args))]); } /** * PATCH /api/lists/{listId}/items/{itemId} */ public function update(Request $request, Response $response, array $args): Response { $listId = $this->requireOwnedListId($request, $args); $item = $this->requireItem($listId, $args); $validator = new Validator($this->body($request)); $fields = []; if ($validator->has('text')) { $fields['text'] = $validator->requiredString('text', self::TEXT_MAX); } if ($validator->has('complete')) { $fields['complete'] = $validator->optionalBool('complete'); } if ($validator->has('position')) { $fields['position'] = $validator->optionalInt('position', 0); } if ($fields === [] && !$validator->failed()) { $validator->add('text', 'Provide at least one of: text, complete, position.'); } $validator->assert(); $updated = $this->items->update($item['id'], $listId, $fields); $this->lists->touch($listId); return $this->json($response, ['item' => $this->present($updated)]); } /** * DELETE /api/lists/{listId}/items/{itemId} */ public function destroy(Request $request, Response $response, array $args): Response { $listId = $this->requireOwnedListId($request, $args); $this->items->delete($this->requireItem($listId, $args)['id']); $this->lists->touch($listId); return $response->withStatus(204); } /** * @param array $args */ private function requireOwnedListId(Request $request, array $args): int { $list = $this->lists->findOwnedBy((int) $args['listId'], $this->user($request)['id']); if ($list === null) { throw new ApiException('List not found.', 404); } return $list['id']; } /** * @param array $args * @return array{id: int, list_id: int, text: string, complete: bool, position: int, created_at: string, updated_at: string} */ private function requireItem(int $listId, array $args): array { $item = $this->items->findInList((int) $args['itemId'], $listId); if ($item === null) { throw new ApiException('Item not found.', 404); } return $item; } /** * @param array{id: int, list_id: int, text: string, complete: bool, position: int, created_at: string, updated_at: string} $item * @return array */ private function present(array $item): array { return [ 'id' => $item['id'], 'list_id' => $item['list_id'], 'text' => $item['text'], 'complete' => $item['complete'], 'position' => $item['position'], 'created_at' => $item['created_at'], 'updated_at' => $item['updated_at'], ]; } }