implement post and comment controllers
Wires PostController (recent, show, create, delete, listByUser) and CommentController (listForPost, create, delete) to the existing use cases. Posts and comments expose author display names alongside user IDs. CommentRepository binding added to RepositoryServiceProvider.
This commit is contained in:
parent
8614858558
commit
59d4ed88c4
4 changed files with 342 additions and 0 deletions
124
backend/app/Controllers/CommentController.php
Normal file
124
backend/app/Controllers/CommentController.php
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
<?php
|
||||
|
||||
namespace App\Controllers;
|
||||
|
||||
use App\Comment\Comment;
|
||||
use App\Comment\UseCases\CreateComment\CreateComment;
|
||||
use App\Comment\UseCases\CreateComment\CreateCommentRequest;
|
||||
use App\Comment\UseCases\DeleteComment\DeleteComment;
|
||||
use App\Comment\UseCases\DeleteComment\DeleteCommentRequest;
|
||||
use App\Comment\UseCases\ListCommentsForPost\ListCommentsForPost;
|
||||
use App\Comment\UseCases\ListCommentsForPost\ListCommentsForPostRequest;
|
||||
use App\Exceptions\BadRequestException;
|
||||
use App\Exceptions\ForbiddenException;
|
||||
use App\User\User;
|
||||
use App\User\UserRepository;
|
||||
use DomainException;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class CommentController
|
||||
{
|
||||
public function __construct(
|
||||
private CreateComment $createComment,
|
||||
private DeleteComment $deleteComment,
|
||||
private ListCommentsForPost $listCommentsForPost,
|
||||
private UserRepository $userRepo,
|
||||
) {}
|
||||
|
||||
public function listForPost(Request $request, int $postId): JsonResponse
|
||||
{
|
||||
try {
|
||||
$comments = $this->listCommentsForPost->execute(
|
||||
new ListCommentsForPostRequest(postId: $postId),
|
||||
);
|
||||
} catch (BadRequestException $exception) {
|
||||
return new JsonResponse(
|
||||
['error' => $exception->getMessage()], 400,
|
||||
);
|
||||
}
|
||||
|
||||
return new JsonResponse([
|
||||
'comments' => array_map(
|
||||
function (Comment $comment) {
|
||||
return $this->serialize($comment);
|
||||
},
|
||||
$comments,
|
||||
),
|
||||
], 200);
|
||||
}
|
||||
|
||||
public function create(Request $request, int $postId): JsonResponse
|
||||
{
|
||||
/** @var User $user */
|
||||
$user = $request->attributes->get('user');
|
||||
try {
|
||||
$comment = $this->createComment->execute(new CreateCommentRequest(
|
||||
postId: $postId,
|
||||
userId: $user->getId(),
|
||||
body: $request->input('body'),
|
||||
));
|
||||
} catch (BadRequestException $exception) {
|
||||
return new JsonResponse(
|
||||
['error' => $exception->getMessage()], 400,
|
||||
);
|
||||
} catch (DomainException $exception) {
|
||||
return new JsonResponse(
|
||||
['error' => $exception->getMessage()], 404,
|
||||
);
|
||||
}
|
||||
|
||||
return new JsonResponse([
|
||||
'comment' => $this->serialize($comment),
|
||||
], 201);
|
||||
}
|
||||
|
||||
public function delete(Request $request, int $id): JsonResponse
|
||||
{
|
||||
/** @var User $user */
|
||||
$user = $request->attributes->get('user');
|
||||
try {
|
||||
$this->deleteComment->execute(new DeleteCommentRequest(
|
||||
commentId: $id,
|
||||
requesterId: $user->getId(),
|
||||
requesterIsAdmin: $user->isAdmin(),
|
||||
));
|
||||
} catch (BadRequestException $exception) {
|
||||
return new JsonResponse(
|
||||
['error' => $exception->getMessage()], 400,
|
||||
);
|
||||
} catch (ForbiddenException $exception) {
|
||||
return new JsonResponse(
|
||||
['error' => $exception->getMessage()], 403,
|
||||
);
|
||||
}
|
||||
|
||||
return new JsonResponse(null, 204);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{
|
||||
* id: int,
|
||||
* postId: int,
|
||||
* userId: int,
|
||||
* authorDisplayName: string,
|
||||
* body: string,
|
||||
* createdAt: string
|
||||
* }
|
||||
*/
|
||||
private function serialize(Comment $comment): array
|
||||
{
|
||||
$author = $this->userRepo->find($comment->getUserId());
|
||||
|
||||
return [
|
||||
'id' => $comment->getId(),
|
||||
'postId' => $comment->getPostId(),
|
||||
'userId' => $comment->getUserId(),
|
||||
'authorDisplayName' => $author === null
|
||||
? ''
|
||||
: $author->getDisplayName(),
|
||||
'body' => $comment->getBody(),
|
||||
'createdAt' => $comment->getCreatedAt()->format(DATE_ATOM),
|
||||
];
|
||||
}
|
||||
}
|
||||
181
backend/app/Controllers/PostController.php
Normal file
181
backend/app/Controllers/PostController.php
Normal file
|
|
@ -0,0 +1,181 @@
|
|||
<?php
|
||||
|
||||
namespace App\Controllers;
|
||||
|
||||
use App\Exceptions\BadRequestException;
|
||||
use App\Exceptions\ForbiddenException;
|
||||
use App\Post\Post;
|
||||
use App\Post\UseCases\CreatePost\CreatePost;
|
||||
use App\Post\UseCases\CreatePost\CreatePostRequest;
|
||||
use App\Post\UseCases\DeletePost\DeletePost;
|
||||
use App\Post\UseCases\DeletePost\DeletePostRequest;
|
||||
use App\Post\UseCases\GetPost\GetPost;
|
||||
use App\Post\UseCases\ListRecentPosts\ListRecentPosts;
|
||||
use App\Post\UseCases\ListRecentPosts\ListRecentPostsRequest;
|
||||
use App\Post\UseCases\ListUserPosts\ListUserPosts;
|
||||
use App\Post\UseCases\ListUserPosts\ListUserPostsRequest;
|
||||
use App\User\User;
|
||||
use App\User\UserRepository;
|
||||
use DomainException;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class PostController
|
||||
{
|
||||
private const RECENT_LIMIT = 20;
|
||||
|
||||
public function __construct(
|
||||
private CreatePost $createPost,
|
||||
private DeletePost $deletePost,
|
||||
private GetPost $getPost,
|
||||
private ListRecentPosts $listRecentPosts,
|
||||
private ListUserPosts $listUserPosts,
|
||||
private UserRepository $userRepo,
|
||||
) {}
|
||||
|
||||
public function recent(Request $request): JsonResponse
|
||||
{
|
||||
try {
|
||||
$posts = $this->listRecentPosts->execute(
|
||||
new ListRecentPostsRequest(limit: self::RECENT_LIMIT),
|
||||
);
|
||||
} catch (BadRequestException $exception) {
|
||||
return new JsonResponse(
|
||||
['error' => $exception->getMessage()], 400,
|
||||
);
|
||||
}
|
||||
|
||||
return new JsonResponse([
|
||||
'posts' => array_map(
|
||||
function (Post $post) {
|
||||
return $this->serialize($post);
|
||||
},
|
||||
$posts,
|
||||
),
|
||||
], 200);
|
||||
}
|
||||
|
||||
public function show(Request $request, int $id): JsonResponse
|
||||
{
|
||||
try {
|
||||
$post = $this->getPost->execute($id);
|
||||
} catch (BadRequestException $exception) {
|
||||
return new JsonResponse(
|
||||
['error' => $exception->getMessage()], 400,
|
||||
);
|
||||
}
|
||||
if ($post === null) {
|
||||
return new JsonResponse(['error' => 'post not found'], 404);
|
||||
}
|
||||
|
||||
return new JsonResponse([
|
||||
'post' => $this->serialize($post),
|
||||
], 200);
|
||||
}
|
||||
|
||||
public function listByUser(
|
||||
Request $request,
|
||||
string $displayName,
|
||||
): JsonResponse {
|
||||
$user = $this->userRepo->findByDisplayName($displayName);
|
||||
if ($user === null) {
|
||||
return new JsonResponse(['error' => 'user not found'], 404);
|
||||
}
|
||||
try {
|
||||
$posts = $this->listUserPosts->execute(
|
||||
new ListUserPostsRequest(userId: $user->getId()),
|
||||
);
|
||||
} catch (BadRequestException $exception) {
|
||||
return new JsonResponse(
|
||||
['error' => $exception->getMessage()], 400,
|
||||
);
|
||||
}
|
||||
|
||||
return new JsonResponse([
|
||||
'user' => [
|
||||
'id' => $user->getId(),
|
||||
'displayName' => $user->getDisplayName(),
|
||||
],
|
||||
'posts' => array_map(
|
||||
function (Post $post) {
|
||||
return $this->serialize($post);
|
||||
},
|
||||
$posts,
|
||||
),
|
||||
], 200);
|
||||
}
|
||||
|
||||
public function create(Request $request): JsonResponse
|
||||
{
|
||||
/** @var User $user */
|
||||
$user = $request->attributes->get('user');
|
||||
try {
|
||||
$post = $this->createPost->execute(new CreatePostRequest(
|
||||
userId: $user->getId(),
|
||||
title: $request->input('title'),
|
||||
body: $request->input('body'),
|
||||
));
|
||||
} catch (BadRequestException $exception) {
|
||||
return new JsonResponse(
|
||||
['error' => $exception->getMessage()], 400,
|
||||
);
|
||||
}
|
||||
|
||||
return new JsonResponse([
|
||||
'post' => $this->serialize($post),
|
||||
], 201);
|
||||
}
|
||||
|
||||
public function delete(Request $request, int $id): JsonResponse
|
||||
{
|
||||
/** @var User $user */
|
||||
$user = $request->attributes->get('user');
|
||||
try {
|
||||
$this->deletePost->execute(new DeletePostRequest(
|
||||
postId: $id,
|
||||
requesterId: $user->getId(),
|
||||
requesterIsAdmin: $user->isAdmin(),
|
||||
));
|
||||
} catch (BadRequestException $exception) {
|
||||
return new JsonResponse(
|
||||
['error' => $exception->getMessage()], 400,
|
||||
);
|
||||
} catch (ForbiddenException $exception) {
|
||||
return new JsonResponse(
|
||||
['error' => $exception->getMessage()], 403,
|
||||
);
|
||||
} catch (DomainException $exception) {
|
||||
return new JsonResponse(
|
||||
['error' => $exception->getMessage()], 409,
|
||||
);
|
||||
}
|
||||
|
||||
return new JsonResponse(null, 204);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{
|
||||
* id: int,
|
||||
* userId: int,
|
||||
* authorDisplayName: string,
|
||||
* title: string,
|
||||
* body: string,
|
||||
* createdAt: string
|
||||
* }
|
||||
*/
|
||||
private function serialize(Post $post): array
|
||||
{
|
||||
$author = $this->userRepo->find($post->getUserId());
|
||||
|
||||
return [
|
||||
'id' => $post->getId(),
|
||||
'userId' => $post->getUserId(),
|
||||
'authorDisplayName' => $author === null
|
||||
? ''
|
||||
: $author->getDisplayName(),
|
||||
'title' => $post->getTitle(),
|
||||
'body' => $post->getBody(),
|
||||
'createdAt' => $post->getCreatedAt()->format(DATE_ATOM),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -4,6 +4,8 @@ namespace App\Providers;
|
|||
|
||||
use App\Auth\EloquentSessionRepository;
|
||||
use App\Auth\SessionRepository;
|
||||
use App\Comment\CommentRepository;
|
||||
use App\Comment\EloquentCommentRepository;
|
||||
use App\Email\EmailConfirmationToken\EloquentEmailConfirmationTokenRepository;
|
||||
use App\Email\EmailConfirmationToken\EmailConfirmationTokenRepository;
|
||||
use App\Post\EloquentPostRepository;
|
||||
|
|
@ -32,5 +34,9 @@ class RepositoryServiceProvider extends ServiceProvider
|
|||
PostRepository::class,
|
||||
EloquentPostRepository::class,
|
||||
);
|
||||
$this->app->bind(
|
||||
CommentRepository::class,
|
||||
EloquentCommentRepository::class,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
<?php
|
||||
|
||||
use App\Controllers\AuthController;
|
||||
use App\Controllers\CommentController;
|
||||
use App\Controllers\PostController;
|
||||
use App\Http\Middleware\AuthMiddleware;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
|
|
@ -15,3 +17,32 @@ Route::post('/logout', [AuthController::class, 'logout'])
|
|||
->middleware(AuthMiddleware::class);
|
||||
Route::get('/me', [AuthController::class, 'me'])
|
||||
->middleware(AuthMiddleware::class);
|
||||
|
||||
Route::get('/posts', [PostController::class, 'recent']);
|
||||
Route::get('/posts/{id}', [PostController::class, 'show'])
|
||||
->whereNumber('id');
|
||||
Route::post('/posts', [PostController::class, 'create'])
|
||||
->middleware(AuthMiddleware::class);
|
||||
Route::delete('/posts/{id}', [PostController::class, 'delete'])
|
||||
->whereNumber('id')
|
||||
->middleware(AuthMiddleware::class);
|
||||
|
||||
Route::get(
|
||||
'/users/{displayName}/posts',
|
||||
[PostController::class, 'listByUser'],
|
||||
);
|
||||
|
||||
Route::get(
|
||||
'/posts/{postId}/comments',
|
||||
[CommentController::class, 'listForPost'],
|
||||
)->whereNumber('postId');
|
||||
Route::post(
|
||||
'/posts/{postId}/comments',
|
||||
[CommentController::class, 'create'],
|
||||
)->whereNumber('postId')
|
||||
->middleware(AuthMiddleware::class);
|
||||
Route::delete(
|
||||
'/comments/{id}',
|
||||
[CommentController::class, 'delete'],
|
||||
)->whereNumber('id')
|
||||
->middleware(AuthMiddleware::class);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue