diff --git a/assets/styles/_detail.scss b/assets/styles/_detail.scss new file mode 100644 index 0000000..8923ae3 --- /dev/null +++ b/assets/styles/_detail.scss @@ -0,0 +1,12 @@ +.post-detail { + & .author { + font-weight: bold; + } + & .content { + padding-top: 1em; + padding-bottom: 1em; + } + & h3 { + font-size: 1.2rem; + } +} diff --git a/assets/styles/global.scss b/assets/styles/global.scss index 35c116d..490d951 100644 --- a/assets/styles/global.scss +++ b/assets/styles/global.scss @@ -1,3 +1,4 @@ $primary: darken(#66531e, 20%); @import "~bootstrap/scss/bootstrap"; +@import "detail"; diff --git a/src/Controller/DetailPostController.php b/src/Controller/DetailPostController.php index 8af5ed8..0f31694 100644 --- a/src/Controller/DetailPostController.php +++ b/src/Controller/DetailPostController.php @@ -1,8 +1,34 @@ '\d+'])] + public function detail(int $postId): Response + { + $post = $this->postRepository->find($postId); + + if ($post === null) { + throw new NotFoundHttpException('Post not found. Please check the provided ID. If the problem persists, contact the system administrator'); + } + + return $this->render( + 'detail_post/detail.html.twig', + ['post' => $post] + ); + } } diff --git a/src/Controller/ListPostController.php b/src/Controller/ListPostController.php index 0179afa..5ce5728 100644 --- a/src/Controller/ListPostController.php +++ b/src/Controller/ListPostController.php @@ -6,6 +6,7 @@ namespace App\Controller; use App\Repository\Post\PostRepository; use App\Utils\Paginator\Paginator; +use Psr\Log\LoggerInterface; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; @@ -18,6 +19,7 @@ final class ListPostController extends AbstractController private readonly int $maxVisiblePages, private readonly PostRepository $postRepository, private readonly Paginator $paginator, + private readonly LoggerInterface $logger, ) { } @@ -38,11 +40,13 @@ final class ListPostController extends AbstractController } if ($page === 0) { + $this->logger->error('Page number is zero. Redirecting to the first page.'); return $this->redirectToRoute('page_list', ['page' => 1]); } // If page number is out of range, redirect to the last page. if ($page > $totalPages) { + $this->logger->error(sprintf('Page number %d is out of range. Redirecting to the last page: %d', $page, $totalPages)); return $this->redirectToRoute('page_list', ['page' => $totalPages]); } diff --git a/templates/detail_post/detail.html.twig b/templates/detail_post/detail.html.twig new file mode 100644 index 0000000..05487cd --- /dev/null +++ b/templates/detail_post/detail.html.twig @@ -0,0 +1,31 @@ +{% extends 'base.html.twig' %} + +{% block body %} +
+

{{ post.title }}

+
+ by {{ post.user.name }} ({{ post.user.email }}), {{ post.user.website }}) + work at {{ post.user.company.name }} +
+

+ {{ post.body }} +

+ {% if post.comments|length > 0 %} +

Comments:

+
+ {% for comment in post.comments %} +
+
+ {{ comment.name }} ({{ comment.email }}) +
+
+

+ {{ comment.body }} +

+
+
+ {% endfor %} +
+ {% endif %} +
+{% endblock %} diff --git a/tests/Web/DetailPostControllerTest.php b/tests/Web/DetailPostControllerTest.php new file mode 100644 index 0000000..1d51e74 --- /dev/null +++ b/tests/Web/DetailPostControllerTest.php @@ -0,0 +1,59 @@ +client = static::createClient(); + $this->bootDatabase(); + $this->bootFaker(); + $this->getFaker()->unique(); + } + + public function testPostDetail(): void + { + $post = $this->createPost(1); + $comments = []; + $comments[] = $this->createComment(1, $post); + $comments[] = $this->createComment(2, $post); + + $this->client->request('GET', '/posts/detail/1'); + + $this->assertResponseIsSuccessful(); + $this->assertSelectorTextSame('.t-title', $post->title); + $this->assertSelectorTextSame('.t-content', $post->body); + + $this->assertSelectorTextSame('.t-user-name', $post->user->name); + $this->assertSelectorTextSame('.t-user-email', $post->user->email); + $this->assertSelectorTextSame('.t-user-website', $post->user->website); + $this->assertSelectorTextSame('.t-user-company', $post->user->company->name); + $this->assertSelectorCount(2, '.t-comment'); + $this->assertSelectorTextSame('.t-comment:nth-child(1) .t-comment-name', $comments[0]->name); + $this->assertSelectorTextSame('.t-comment:nth-child(1) .t-comment-email', $comments[0]->email); + $this->assertSelectorTextSame('.t-comment:nth-child(1) .t-comment-body', $comments[0]->body); + } + + public function testPostDetailNotFound(): void + { + $this->client->request('GET', '/posts/detail/100'); + $this->assertResponseStatusCodeSame(404); + } +}