getAttribute('user'); if (!$user instanceof User) { return $this->errorResponse( $response, 401, 'unauthenticated' ); } $text = $this->textRepository->find($textId); if ($text === null) { return $response->withStatus(404); } if (!$this->userMayAccessText($user, $text)) { return $this->errorResponse( $response, 403, 'forbidden' ); } $nodes = $this->nodeRepository->findByTextId($textId); $data = array_map(function ($node) { return [ 'id' => $node->getId(), 'title' => $node->getTitle(), 'parentNodeId' => $node->getParentNode()?->getId(), ]; }, $nodes); $response->getBody()->write(json_encode(array_values($data))); return $response->withHeader('Content-Type', 'application/json'); } public function createNode( Request $request, Response $response, CreateNode $createNodeUseCase, ): Response { $user = $request->getAttribute('user'); if (!$user instanceof User) { return $this->errorResponse( $response, 401, 'unauthenticated' ); } $data = json_decode((string) $request->getBody(), true) ?? []; $textId = isset($data['textId']) ? (int) $data['textId'] : null; $title = $data['title'] ?? null; $parentNodeId = isset($data['parentNodeId']) ? (int) $data['parentNodeId'] : null; if ($textId !== null) { $ownershipResponse = $this->checkTextOwnership( $user, $textId, $response, ); if ($ownershipResponse !== null) { return $ownershipResponse; } } try { $node = $createNodeUseCase->execute(new CreateNodeRequest( textId: $textId, title: $title, parentNodeId: $parentNodeId, )); } catch (BadRequestException $e) { $response->getBody()->write(json_encode(['error' => $e->getMessage()])); return $response->withStatus(400)->withHeader('Content-Type', 'application/json'); } catch (DomainException $e) { $response->getBody()->write(json_encode(['error' => $e->getMessage()])); return $response->withStatus(404)->withHeader('Content-Type', 'application/json'); } $response->getBody()->write(json_encode([ 'id' => $node->getId(), 'title' => $node->getTitle(), 'parentNodeId' => $node->getParentNode()?->getId(), ])); return $response->withStatus(201)->withHeader('Content-Type', 'application/json'); } public function bulkCreateNodes( Request $request, Response $response, BulkCreateNodes $bulkCreateNodesUseCase, ): Response { $user = $request->getAttribute('user'); if (!$user instanceof User) { return $this->errorResponse( $response, 401, 'unauthenticated' ); } $data = json_decode((string) $request->getBody(), true) ?? []; $textId = isset($data['textId']) ? (int) $data['textId'] : null; $parentNodeId = isset($data['parentNodeId']) ? (int) $data['parentNodeId'] : null; $titlePrefix = isset($data['titlePrefix']) ? (string) $data['titlePrefix'] : null; $count = isset($data['count']) ? (int) $data['count'] : null; if ($textId !== null) { $ownershipResponse = $this->checkTextOwnership( $user, $textId, $response, ); if ($ownershipResponse !== null) { return $ownershipResponse; } } try { $nodes = $bulkCreateNodesUseCase->execute(new BulkCreateNodesRequest( textId: $textId, parentNodeId: $parentNodeId, titlePrefix: $titlePrefix, count: $count, )); } catch (BadRequestException $e) { $response->getBody()->write(json_encode(['error' => $e->getMessage()])); return $response->withStatus(400)->withHeader('Content-Type', 'application/json'); } catch (DomainException $e) { $response->getBody()->write(json_encode(['error' => $e->getMessage()])); return $response->withStatus(404)->withHeader('Content-Type', 'application/json'); } $result = array_map(function ($node) { return [ 'id' => $node->getId(), 'title' => $node->getTitle(), 'parentNodeId' => $node->getParentNode()?->getId(), ]; }, $nodes); $response->getBody()->write(json_encode(array_values($result))); return $response->withStatus(201)->withHeader('Content-Type', 'application/json'); } private function checkTextOwnership( User $user, int $textId, Response $response, ): ?Response { $text = $this->textRepository->find($textId); if ($text === null) { return null; } if (!$this->userMayAccessText($user, $text)) { return $this->errorResponse( $response, 403, 'forbidden' ); } return null; } private function userMayAccessText(User $user, Text $text): bool { if ($user->isAdmin()) { return true; } return $text->getUser()->getId() === $user->getId(); } private function errorResponse( Response $response, int $status, string $message, ): Response { $response->getBody()->write( json_encode(['error' => $message]) ); return $response->withStatus($status) ->withHeader('Content-Type', 'application/json'); } }