projects->allForOwner($this->user($request)['id']); return $this->json($response, ['projects' => array_map($this->present(...), $projects)]); } /** * POST /api/projects */ public function store(Request $request, Response $response): Response { $ownerId = $this->user($request)['id']; $validator = new Validator($this->body($request)); $title = $validator->requiredString('title', self::TITLE_MAX); $description = $validator->optionalString('description', self::DESCRIPTION_MAX) ?? ''; $validator->assert(); if ($this->projects->countForOwner($ownerId) >= self::MAX_PROJECTS_PER_OWNER) { throw new ApiException( sprintf('You have reached the maximum of %d projects.', self::MAX_PROJECTS_PER_OWNER), 409, ); } $project = $this->projects->create($ownerId, $title, $description); return $this->json($response, ['project' => $this->present($project)], 201); } /** * GET /api/projects/{projectId} */ public function show(Request $request, Response $response, array $args): Response { return $this->json($response, ['project' => $this->present($this->requireOwnedProject($request, $args))]); } /** * PATCH /api/projects/{projectId} */ public function update(Request $request, Response $response, array $args): Response { $project = $this->requireOwnedProject($request, $args); $validator = new Validator($this->body($request)); $fields = []; if ($validator->has('title')) { $fields['title'] = $validator->requiredString('title', self::TITLE_MAX); } if ($validator->has('description')) { $fields['description'] = $validator->optionalString('description', self::DESCRIPTION_MAX) ?? ''; } if ($fields === [] && !$validator->failed()) { $validator->add('title', 'Provide at least one of: title, description.'); } $validator->assert(); $updated = $this->projects->update($project['id'], $project['owner_id'], $fields); return $this->json($response, ['project' => $this->present($updated)]); } /** * DELETE /api/projects/{projectId} */ public function destroy(Request $request, Response $response, array $args): Response { $this->projects->delete($this->requireOwnedProject($request, $args)['id']); return $response->withStatus(204); } /** * Load the project named in the route, or 404 if it is missing or not owned * by the authenticated user. * * @param array $args * @return array{id: int, owner_id: int, title: string, description: string, card_count: int, completed_count: int, created_at: string, updated_at: string} */ private function requireOwnedProject(Request $request, array $args): array { $project = $this->projects->findOwnedBy((int) $args['projectId'], $this->user($request)['id']); if ($project === null) { throw new ApiException('Project not found.', 404); } return $project; } /** * @param array{id: int, owner_id: int, title: string, description: string, card_count: int, completed_count: int, created_at: string, updated_at: string} $project * @return array */ private function present(array $project): array { return [ 'id' => $project['id'], 'title' => $project['title'], 'description' => $project['description'], 'owner_id' => $project['owner_id'], 'card_count' => $project['card_count'], 'completed_count' => $project['completed_count'], 'created_at' => $project['created_at'], 'updated_at' => $project['updated_at'], ]; } }