diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 4c01dbf6f..694de43e4 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -12,16 +12,11 @@ jobs: strategy: matrix: include: - - php: '7.4' - symfony_require: '4.4.*' - - php: '7.4' - symfony_require: '5.4.*' - php: '8.1' symfony_require: '4.4.*' - - php: '8.1' + - php: '8.3' symfony_require: '5.4.*' - - php: '8.1' - symfony_require: '6.4.*' + fail-fast: false steps: - name: Checkout diff --git a/.gitignore b/.gitignore index 1b3c55185..ff94b1289 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ vendor .php_cs.cache .phpunit.result.cache .idea/* +tests/Functional/app/data/* \ No newline at end of file diff --git a/composer.json b/composer.json index 00f41e772..1fb8c5eca 100644 --- a/composer.json +++ b/composer.json @@ -22,38 +22,39 @@ "require": { "php": ">=7.4", "friendsofsymfony/rest-bundle": "^3.0", - "jms/serializer-bundle": "^2.0|^3.0|^4.0|^5.3", - "symfony/framework-bundle": "^4.3|^5.4|^6.4", - "symfony/asset": "^3.4|^4.3|^5.4|^6.4", - "symfony/dependency-injection": "^4.3|^5.4|^6.4", - "symfony/routing": "^4.3|^5.4|^6.4", - "symfony/security-bundle": "^4.3|^5.4|^6.4", - "symfony/yaml": "^4.3|^5.4|^6.4", - "symfony/form": "^4.3|^5.4|^6.4", - "symfony/validator": "^4.3|^5.4|^6.4", - "symfony/twig-bundle": "^4.3|^5.4|^6.4", - "symfony/twig-bridge": "^4.3|^5.4|^6.4", + "jms/serializer-bundle": "^3.0", + "symfony/framework-bundle": "^5.4", + "symfony/asset": "^5.4", + "symfony/dependency-injection": "^5.4", + "symfony/routing": "^5.4", + "symfony/security-bundle": "^5.4", + "symfony/yaml": "^5.4", + "symfony/form": "^5.4", + "symfony/validator": "^5.4", + "symfony/twig-bundle": "^5.4", + "symfony/twig-bridge": "^5.4", "twig/twig": "^2.0|^3.0", "phpoption/phpoption": "^1.1", - "doctrine/annotations": "^1.0" + "doctrine/annotations": "^1.0", + "handcraftedinthealps/rest-routing-bundle": "^1.0" }, "suggest": { - "friendsofsymfony/user-bundle": "Allows for user integration.", "ornicar/akismet-bundle": "Integrate Akismet for spam detection.", "symfony/acl-bundle": "Integrates the ACL Security component.", "symfony/assetic-bundle": "Integrates Assetic into Symfony." }, "require-dev": { - "symfony/browser-kit": "^4.3|^5.4|^6.4", - "symfony/dom-crawler": "^4.3|^5.4|^6.4", - "symfony/css-selector": "^4.3|^5.4|^6.4", - "doctrine/orm": "^2.3", - "doctrine/doctrine-bundle": "^2.0", - "friendsofsymfony/user-bundle": "^3.0", + "symfony/browser-kit": "^5.4", + "symfony/dom-crawler": "^5.4", + "symfony/css-selector": "^5.4", + "doctrine/orm": "^2.8", + "doctrine/doctrine-bundle": "^2.4", "ornicar/akismet-bundle": "dev-master", - "symfony/expression-language": "^4.3|^5.4|^6.4", - "symfony/phpunit-bridge": "^4.3|^5.4|^6.4", - "phpunit/phpunit": "^9.4" + "symfony/expression-language": "^5.4", + "symfony/phpunit-bridge": "^5.4", + "phpunit/phpunit": "^9.4", + "sonata-project/user-bundle": "^5.10", + "symfony/process": "^6.4" }, "extra": { "branch-alias": { diff --git a/src/Controller/ThreadController.php b/src/Controller/ThreadController.php index 55e8461f7..45bc82fbf 100644 --- a/src/Controller/ThreadController.php +++ b/src/Controller/ThreadController.php @@ -15,9 +15,9 @@ use FOS\CommentBundle\Model\ThreadInterface; use FOS\RestBundle\Controller\AbstractFOSRestController; use FOS\RestBundle\View\View; +use FOS\RestBundle\View\ViewHandlerInterface; use Psr\Container\ContainerExceptionInterface; use Psr\Container\NotFoundExceptionInterface; -use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\Form\FormInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; @@ -35,12 +35,7 @@ class ThreadController extends AbstractFOSRestController const VIEW_FLAT = 'flat'; const VIEW_TREE = 'tree'; - /** - * Presents the form to use to create a new Thread. - * - * @return Response - */ - public function newThreadsAction() + public function newThreadsAction(Request $request): Response { $form = $this->container->get('fos_comment.form_factory.thread')->createForm(); @@ -55,14 +50,7 @@ public function newThreadsAction() return $this->handleView($view); } - /** - * Gets the thread for a given id. - * - * @param string $id - * - * @return Response - */ - public function getThreadAction($id) + public function getThreadAction(Request $request, string $id): Response { $manager = $this->container->get('fos_comment.manager.thread'); @@ -78,14 +66,7 @@ public function getThreadAction($id) return $this->handleView($view); } - /** - * Gets the threads for the specified ids. - * - * @param Request $request - * - * @return Response - */ - public function getThreadsActions(Request $request) + public function getThreadsActions(Request $request): Response { $ids = $request->query->get('ids'); @@ -101,14 +82,7 @@ public function getThreadsActions(Request $request) return $this->handleView($view); } - /** - * Creates a new Thread from the submitted data. - * - * @param Request $request The current request - * - * @return Response - */ - public function postThreadsAction(Request $request) + public function postThreadsAction(Request $request): Response { $threadManager = $this->container->get('fos_comment.manager.thread'); $thread = $threadManager->createThread(); @@ -130,15 +104,7 @@ public function postThreadsAction(Request $request) return $this->handleView($this->onCreateThreadError($form)); } - /** - * Get the edit form the open/close a thread. - * - * @param Request $request Current request - * @param mixed $id Thread id - * - * @return Response - */ - public function editThreadCommentableAction(Request $request, $id) + public function editThreadCommentableAction(Request $request, string $id): Response { $manager = $this->container->get('fos_comment.manager.thread'); $thread = $manager->findThreadById($id); @@ -154,27 +120,19 @@ public function editThreadCommentableAction(Request $request, $id) $view = View::create() ->setData([ - 'data' => [ - 'form' => $form, - 'id' => $id, - 'isCommentable' => $thread->isCommentable(), - ], - 'template' => '@FOSComment/Thread/commentable.html.twig', - ] - ); + 'data' => [ + 'form' => $form, + 'id' => $id, + 'isCommentable' => $thread->isCommentable(), + ], + 'template' => '@FOSComment/Thread/commentable.html.twig', + ] + ); return $this->handleView($view); } - /** - * Edits the thread. - * - * @param Request $request Currently request - * @param mixed $id Thread id - * - * @return Response - */ - public function patchThreadCommentableAction(Request $request, $id) + public function patchThreadCommentableAction(Request $request, string $id): Response { $manager = $this->container->get('fos_comment.manager.thread'); $thread = $manager->findThreadById($id); @@ -196,15 +154,7 @@ public function patchThreadCommentableAction(Request $request, $id) return $this->handleView($this->onOpenThreadError($form)); } - /** - * Presents the form to use to create a new Comment for a Thread. - * - * @param Request $request - * @param string $id - * - * @return Response - */ - public function newThreadCommentsAction(Request $request, $id) + public function newThreadCommentsAction(Request $request, string $id): Response { $thread = $this->container->get('fos_comment.manager.thread')->findThreadById($id); if (!$thread) { @@ -220,36 +170,30 @@ public function newThreadCommentsAction(Request $request, $id) $view = View::create() ->setData([ - 'data' => [ - 'form' => $form->createView(), - 'first' => 0 === $thread->getNumComments(), - 'thread' => $thread, - 'parent' => $parent, - 'id' => $id, - ], - 'template' => '@FOSComment/Thread/comment_new.html.twig', - ] - ); + 'data' => [ + 'form' => $form->createView(), + 'first' => 0 === $thread->getNumComments(), + 'thread' => $thread, + 'parent' => $parent, + 'id' => $id, + ], + 'template' => '@FOSComment/Thread/comment_new.html.twig', + ] + ); return $this->handleView($view); } - /** - * Get a comment of a thread. - * - * @param string $id Id of the thread - * @param mixed $commentId Id of the comment - * - * @return Response - */ - public function getThreadCommentAction($id, $commentId) + public function getThreadCommentAction(Request $request, string $id, ?string $commentId): Response { $thread = $this->container->get('fos_comment.manager.thread')->findThreadById($id); $comment = $this->container->get('fos_comment.manager.comment')->findCommentById($commentId); $parent = null; if (null === $thread || null === $comment || $comment->getThread() !== $thread) { - throw new NotFoundHttpException(sprintf("No comment with id '%s' found for thread with id '%s'", $commentId, $id)); + throw new NotFoundHttpException( + sprintf("No comment with id '%s' found for thread with id '%s'", $commentId, $id) + ); } $ancestors = $comment->getAncestors(); @@ -259,35 +203,28 @@ public function getThreadCommentAction($id, $commentId) $view = View::create() ->setData([ - 'data' => [ - 'comment' => $comment, - 'thread' => $thread, - 'parent' => $parent, - 'depth' => $comment->getDepth(), - ], - 'template' => '@FOSComment/Thread/comment.html.twig', - ] - ); + 'data' => [ + 'comment' => $comment, + 'thread' => $thread, + 'parent' => $parent, + 'depth' => $comment->getDepth(), + ], + 'template' => '@FOSComment/Thread/comment.html.twig', + ] + ); return $this->handleView($view); } - /** - * Get the delete form for a comment. - * - * @param Request $request Current request - * @param string $id Id of the thread - * @param mixed $commentId Id of the comment - * - * @return Response - */ - public function removeThreadCommentAction(Request $request, $id, $commentId) + public function removeThreadCommentAction(Request $request, string $id, ?string $commentId): Response { $thread = $this->container->get('fos_comment.manager.thread')->findThreadById($id); $comment = $this->container->get('fos_comment.manager.comment')->findCommentById($commentId); if (null === $thread || null === $comment || $comment->getThread() !== $thread) { - throw new NotFoundHttpException(sprintf("No comment with id '%s' found for thread with id '%s'", $commentId, $id)); + throw new NotFoundHttpException( + sprintf("No comment with id '%s' found for thread with id '%s'", $commentId, $id) + ); } $form = $this->container->get('fos_comment.form_factory.delete_comment')->createForm(); @@ -297,28 +234,19 @@ public function removeThreadCommentAction(Request $request, $id, $commentId) $view = View::create() ->setData([ - 'data' => [ - 'form' => $form, - 'id' => $id, - 'commentId' => $commentId, - ], - 'template' => '@FOSComment/Thread/comment_remove.html.twig', - ] - ); + 'data' => [ + 'form' => $form, + 'id' => $id, + 'commentId' => $commentId, + ], + 'template' => '@FOSComment/Thread/comment_remove.html.twig', + ] + ); return $this->handleView($view); } - /** - * Edits the comment state. - * - * @param Request $request Current request - * @param mixed $id Thread id - * @param mixed $commentId Id of the comment - * - * @return Response - */ - public function patchThreadCommentStateAction(Request $request, $id, $commentId) + public function patchThreadCommentStateAction(Request $request, string $id, ?string $commentId): Response { $manager = $this->container->get('fos_comment.manager.comment'); $thread = $this->container->get('fos_comment.manager.thread')->findThreadById($id); @@ -344,18 +272,20 @@ public function patchThreadCommentStateAction(Request $request, $id, $commentId) /** * Presents the form to use to edit a Comment for a Thread. * - * @param string $id Id of the thread - * @param mixed $commentId Id of the comment + * @param string $id Id of the thread + * @param mixed $commentId Id of the comment * * @return Response */ - public function editThreadCommentAction($id, $commentId) + public function editThreadCommentAction(Request $request, string $id, ?string $commentId): Response { $thread = $this->container->get('fos_comment.manager.thread')->findThreadById($id); $comment = $this->container->get('fos_comment.manager.comment')->findCommentById($commentId); if (null === $thread || null === $comment || $comment->getThread() !== $thread) { - throw new NotFoundHttpException(sprintf("No comment with id '%s' found for thread with id '%s'", $commentId, $id)); + throw new NotFoundHttpException( + sprintf("No comment with id '%s' found for thread with id '%s'", $commentId, $id) + ); } $form = $this->container->get('fos_comment.form_factory.comment')->createForm(null, ['method' => 'PUT']); @@ -363,27 +293,18 @@ public function editThreadCommentAction($id, $commentId) $view = View::create() ->setData([ - 'data' => [ - 'form' => $form->createView(), - 'comment' => $comment, - ], - 'template' => '@FOSComment/Thread/comment_edit.html.twig', - ] - ); + 'data' => [ + 'form' => $form->createView(), + 'comment' => $comment, + ], + 'template' => '@FOSComment/Thread/comment_edit.html.twig', + ] + ); return $this->handleView($view); } - /** - * Edits a given comment. - * - * @param Request $request Current request - * @param string $id Id of the thread - * @param mixed $commentId Id of the comment - * - * @return Response - */ - public function putThreadCommentsAction(Request $request, $id, $commentId) + public function putThreadCommentsAction(Request $request, string $id, ?string $commentId): Response { $commentManager = $this->container->get('fos_comment.manager.comment'); @@ -391,7 +312,9 @@ public function putThreadCommentsAction(Request $request, $id, $commentId) $comment = $commentManager->findCommentById($commentId); if (null === $thread || null === $comment || $comment->getThread() !== $thread) { - throw new NotFoundHttpException(sprintf("No comment with id '%s' found for thread with id '%s'", $commentId, $id)); + throw new NotFoundHttpException( + sprintf("No comment with id '%s' found for thread with id '%s'", $commentId, $id) + ); } $form = $this->container->get('fos_comment.form_factory.comment')->createForm(null, ['method' => 'PUT']); @@ -407,16 +330,7 @@ public function putThreadCommentsAction(Request $request, $id, $commentId) return $this->handleView($this->onEditCommentError($form, $id, $comment->getParent())); } - /** - * Get the comments of a thread. Creates a new thread if none exists. - * - * @param Request $request Current request - * @param string $id Id of the thread - * - * @return Response - * - */ - public function getThreadCommentsAction(Request $request, $id) + public function getThreadCommentsAction(Request $request, string $id): Response { $displayDepth = $request->query->get('displayDepth'); $sorter = $request->query->get('sorter'); @@ -437,12 +351,12 @@ public function getThreadCommentsAction(Request $request, $id) $view = View::create() ->setStatusCode(Response::HTTP_BAD_REQUEST) ->setData([ - 'data' => [ - 'errors' => $errors, - ], - 'template' => '@FOSComment/Thread/errors.html.twig', - ] - ); + 'data' => [ + 'errors' => $errors, + ], + 'template' => '@FOSComment/Thread/errors.html.twig', + ] + ); return $this->handleView($view); } @@ -474,16 +388,16 @@ public function getThreadCommentsAction(Request $request, $id) $view = View::create() ->setData([ - 'data' => [ - 'comments' => $comments, - 'displayDepth' => $displayDepth, - 'sorter' => 'date', - 'thread' => $thread, - 'view' => $viewMode, - ], - 'template' => '@FOSComment/Thread/comments.html.twig', - ] - ); + 'data' => [ + 'comments' => $comments, + 'displayDepth' => $displayDepth, + 'sorter' => 'date', + 'thread' => $thread, + 'view' => $viewMode, + ], + 'template' => '@FOSComment/Thread/comments.html.twig', + ] + ); // Register a special handler for RSS. Only available on this route. if ('rss' === $request->getRequestFormat()) { @@ -502,17 +416,7 @@ public function getThreadCommentsAction(Request $request, $id) return $this->handleView($view); } - /** - * Creates a new Comment for the Thread from the submitted data. - * - * @param Request $request The current request - * @param string $id The id of the thread - * - * @return Response - * - * @todo Add support for comment parent (in form?) - */ - public function postThreadCommentsAction(Request $request, $id) + public function postThreadCommentsAction(Request $request, string $id): Response { $thread = $this->container->get('fos_comment.manager.thread')->findThreadById($id); if (!$thread) { @@ -540,51 +444,39 @@ public function postThreadCommentsAction(Request $request, $id) return $this->handleView($this->onCreateCommentError($form, $id, $parent)); } - /** - * Get the votes of a comment. - * - * @param string $id Id of the thread - * @param mixed $commentId Id of the comment - * - * @return Response - */ - public function getThreadCommentVotesAction($id, $commentId) + public function getThreadCommentVotesAction(Request $request, string $id, ?string $commentId): Response { $thread = $this->container->get('fos_comment.manager.thread')->findThreadById($id); $comment = $this->container->get('fos_comment.manager.comment')->findCommentById($commentId); if (null === $thread || null === $comment || $comment->getThread() !== $thread) { - throw new NotFoundHttpException(sprintf("No comment with id '%s' found for thread with id '%s'", $commentId, $id)); + throw new NotFoundHttpException( + sprintf("No comment with id '%s' found for thread with id '%s'", $commentId, $id) + ); } $view = View::create() ->setData([ - 'data' => [ - 'commentScore' => $comment->getScore(), - ], - 'template' => '@FOSComment/Thread/comment_votes.html.twig', - ] - ); + 'data' => [ + 'commentScore' => $comment->getScore(), + ], + 'template' => '@FOSComment/Thread/comment_votes.html.twig', + ] + ); return $this->handleView($view); } - /** - * Presents the form to use to create a new Vote for a Comment. - * - * @param Request $request Current request - * @param string $id Id of the thread - * @param mixed $commentId Id of the comment - * - * @return Response - */ - public function newThreadCommentVotesAction(Request $request, $id, $commentId) + + public function newThreadCommentVotesAction(Request $request, string $id, ?string $commentId): Response { $thread = $this->container->get('fos_comment.manager.thread')->findThreadById($id); $comment = $this->container->get('fos_comment.manager.comment')->findCommentById($commentId); if (null === $thread || null === $comment || $comment->getThread() !== $thread) { - throw new NotFoundHttpException(sprintf("No comment with id '%s' found for thread with id '%s'", $commentId, $id)); + throw new NotFoundHttpException( + sprintf("No comment with id '%s' found for thread with id '%s'", $commentId, $id) + ); } $vote = $this->container->get('fos_comment.manager.vote')->createVote($comment); @@ -595,34 +487,28 @@ public function newThreadCommentVotesAction(Request $request, $id, $commentId) $view = View::create() ->setData([ - 'data' => [ - 'id' => $id, - 'commentId' => $commentId, - 'form' => $form->createView(), - ], - 'template' => '@FOSComment/Thread/vote_new.html.twig', - ] - ); + 'data' => [ + 'id' => $id, + 'commentId' => $commentId, + 'form' => $form->createView(), + ], + 'template' => '@FOSComment/Thread/vote_new.html.twig', + ] + ); return $this->handleView($view); } - /** - * Creates a new Vote for the Comment from the submitted data. - * - * @param Request $request Current request - * @param string $id Id of the thread - * @param mixed $commentId Id of the comment - * - * @return Response - */ - public function postThreadCommentVotesAction(Request $request, $id, $commentId) + + public function postThreadCommentVotesAction(Request $request, string $id, ?string $commentId): Response { $thread = $this->container->get('fos_comment.manager.thread')->findThreadById($id); $comment = $this->container->get('fos_comment.manager.comment')->findCommentById($commentId); if (null === $thread || null === $comment || $comment->getThread() !== $thread) { - throw new NotFoundHttpException(sprintf("No comment with id '%s' found for thread with id '%s'", $commentId, $id)); + throw new NotFoundHttpException( + sprintf("No comment with id '%s' found for thread with id '%s'", $commentId, $id) + ); } $voteManager = $this->container->get('fos_comment.manager.vote'); @@ -641,16 +527,7 @@ public function postThreadCommentVotesAction(Request $request, $id, $commentId) return $this->handleView($this->onCreateVoteError($form, $id, $commentId)); } - /** - * Forwards the action to the comment view on a successful form submission. - * - * @param FormInterface $form Form with the error - * @param string $id Id of the thread - * @param CommentInterface|null $parent Optional comment parent - * - * @return View - */ - protected function onCreateCommentSuccess(FormInterface $form, $id, CommentInterface $parent = null) + protected function onCreateCommentSuccess(FormInterface $form, string $id, CommentInterface $parent = null): View { return View::createRouteRedirect( 'fos_comment_get_thread_comment', @@ -659,40 +536,22 @@ protected function onCreateCommentSuccess(FormInterface $form, $id, CommentInter ); } - /** - * Returns a HTTP_BAD_REQUEST response when the form submission fails. - * - * @param FormInterface $form Form with the error - * @param string $id Id of the thread - * @param CommentInterface|null $parent Optional comment parent - * - * @return View - */ - protected function onCreateCommentError(FormInterface $form, $id, CommentInterface $parent = null) + protected function onCreateCommentError(FormInterface $form, string $id, CommentInterface $parent = null): View { - $view = View::create() + return View::create() ->setStatusCode(Response::HTTP_BAD_REQUEST) ->setData([ - 'data' => [ - 'form' => $form, - 'id' => $id, - 'parent' => $parent, - ], - 'template' => '@FOSComment/Thread/comment_new.html.twig', - ] - ); - - return $view; + 'data' => [ + 'form' => $form, + 'id' => $id, + 'parent' => $parent, + ], + 'template' => '@FOSComment/Thread/comment_new.html.twig', + ] + ); } - /** - * Forwards the action to the thread view on a successful form submission. - * - * @param FormInterface $form - * - * @return View - */ - protected function onCreateThreadSuccess(FormInterface $form) + protected function onCreateThreadSuccess(FormInterface $form): View { return View::createRouteRedirect( 'fos_comment_get_thread', @@ -708,29 +567,20 @@ protected function onCreateThreadSuccess(FormInterface $form) * * @return View */ - protected function onCreateThreadError(FormInterface $form) + protected function onCreateThreadError(FormInterface $form): View { - $view = View::create() + return View::create() ->setStatusCode(Response::HTTP_BAD_REQUEST) ->setData([ - 'data' => [ - 'form' => $form, - ], - 'template' => '@FOSComment/Thread/new.html.twig', - ] - ); - - return $view; + 'data' => [ + 'form' => $form, + ], + 'template' => '@FOSComment/Thread/new.html.twig', + ] + ); } - /** - * Returns a HTTP_BAD_REQUEST response when the Thread creation fails due to a duplicate id. - * - * @param FormInterface $form - * - * @return Response - */ - protected function onCreateThreadErrorDuplicate(FormInterface $form) + protected function onCreateThreadErrorDuplicate(FormInterface $form): Response { return new Response( sprintf("Duplicate thread id '%s'.", $form->getData()->getId()), @@ -738,17 +588,7 @@ protected function onCreateThreadErrorDuplicate(FormInterface $form) ); } - /** - * Action executed when a vote was successfully created. - * - * @param FormInterface $form Form with the error - * @param string $id Id of the thread - * @param mixed $commentId Id of the comment - * - * @return View - * - */ - protected function onCreateVoteSuccess(FormInterface $form, $id, $commentId) + protected function onCreateVoteSuccess(FormInterface $form, string $id, ?string $commentId): View { return View::createRouteRedirect( 'fos_comment_get_thread_comment_votes', @@ -757,41 +597,22 @@ protected function onCreateVoteSuccess(FormInterface $form, $id, $commentId) ); } - /** - * Returns a HTTP_BAD_REQUEST response when the form submission fails. - * - * @param FormInterface $form Form with the error - * @param string $id Id of the thread - * @param mixed $commentId Id of the comment - * - * @return View - */ - protected function onCreateVoteError(FormInterface $form, $id, $commentId) + protected function onCreateVoteError(FormInterface $form, string $id, ?string $commentId): View { - $view = View::create() + return View::create() ->setStatusCode(Response::HTTP_BAD_REQUEST) ->setData([ - 'data' => [ - 'id' => $id, - 'commentId' => $commentId, - 'form' => $form, - ], - 'template' => '@FOSComment/Thread/vote_new.html.twig', - ] - ); - - return $view; + 'data' => [ + 'id' => $id, + 'commentId' => $commentId, + 'form' => $form, + ], + 'template' => '@FOSComment/Thread/vote_new.html.twig', + ] + ); } - /** - * Forwards the action to the comment view on a successful form submission. - * - * @param FormInterface $form Form with the error - * @param string $id Id of the thread - * - * @return View - */ - protected function onEditCommentSuccess(FormInterface $form, $id) + protected function onEditCommentSuccess(FormInterface $form, string $id): View { return View::createRouteRedirect( 'fos_comment_get_thread_comment', @@ -800,38 +621,21 @@ protected function onEditCommentSuccess(FormInterface $form, $id) ); } - /** - * Returns a HTTP_BAD_REQUEST response when the form submission fails. - * - * @param FormInterface $form Form with the error - * @param string $id Id of the thread - * - * @return View - */ - protected function onEditCommentError(FormInterface $form, $id) + protected function onEditCommentError(FormInterface $form, string $id): View { - $view = View::create() + return View::create() ->setStatusCode(Response::HTTP_BAD_REQUEST) ->setData([ - 'data' => [ - 'form' => $form, - 'comment' => $form->getData(), - ], - 'template' => '@FOSComment/Thread/comment_edit.html.twig', - ] - ); - - return $view; + 'data' => [ + 'form' => $form, + 'comment' => $form->getData(), + ], + 'template' => '@FOSComment/Thread/comment_edit.html.twig', + ] + ); } - /** - * Forwards the action to the open thread edit view on a successful form submission. - * - * @param FormInterface $form - * - * @return View - */ - protected function onOpenThreadSuccess(FormInterface $form) + protected function onOpenThreadSuccess(FormInterface $form): View { return View::createRouteRedirect( 'fos_comment_edit_thread_commentable', @@ -840,39 +644,22 @@ protected function onOpenThreadSuccess(FormInterface $form) ); } - /** - * Returns a HTTP_BAD_REQUEST response when the form submission fails. - * - * @param FormInterface $form - * - * @return View - */ - protected function onOpenThreadError(FormInterface $form) + protected function onOpenThreadError(FormInterface $form): View { - $view = View::create() + return View::create() ->setStatusCode(Response::HTTP_BAD_REQUEST) ->setData([ - 'data' => [ - 'form' => $form, - 'id' => $form->getData()->getId(), - 'isCommentable' => $form->getData()->isCommentable(), - ], - 'template' => '@FOSComment/Thread/commentable.html.twig', - ] - ); - - return $view; + 'data' => [ + 'form' => $form, + 'id' => $form->getData()->getId(), + 'isCommentable' => $form->getData()->isCommentable(), + ], + 'template' => '@FOSComment/Thread/commentable.html.twig', + ] + ); } - /** - * Forwards the action to the comment view on a successful form submission. - * - * @param FormInterface $form Comment delete form - * @param int $id Thread id - * - * @return View - */ - protected function onRemoveThreadCommentSuccess(FormInterface $form, $id) + protected function onRemoveThreadCommentSuccess(FormInterface $form, string $id): View { return View::createRouteRedirect( 'fos_comment_get_thread_comment', @@ -881,43 +668,29 @@ protected function onRemoveThreadCommentSuccess(FormInterface $form, $id) ); } - /** - * Returns a HTTP_BAD_REQUEST response when the form submission fails. - * - * @param FormInterface $form Comment delete form - * @param int $id Thread id - * - * @return View - */ - protected function onRemoveThreadCommentError(FormInterface $form, $id) + protected function onRemoveThreadCommentError(FormInterface $form, string $id): View { $view = View::create() ->setStatusCode(Response::HTTP_BAD_REQUEST) ->setData([ - 'data' => [ - 'form' => $form, - 'id' => $id, - 'commentId' => $form->getData()->getId(), - 'value' => $form->getData()->getState(), - ], - 'template' => '@FOSComment/Thread/comment_remove.html.twig', - ] - ); + 'data' => [ + 'form' => $form, + 'id' => $id, + 'commentId' => $form->getData()->getId(), + 'value' => $form->getData()->getState(), + ], + 'template' => '@FOSComment/Thread/comment_remove.html.twig', + ] + ); return $view; } /** - * Checks if a comment belongs to a thread. Returns the comment if it does. - * - * @param ThreadInterface $thread Thread object - * @param mixed $commentId Id of the comment - * - * @return CommentInterface|null The comment * @throws ContainerExceptionInterface * @throws NotFoundExceptionInterface */ - private function getValidCommentParent(ThreadInterface $thread, $commentId) + private function getValidCommentParent(ThreadInterface $thread, ?string $commentId): ?CommentInterface { if (null !== $commentId) { $comment = $this->container->get('fos_comment.manager.comment')->findCommentById($commentId); @@ -931,5 +704,15 @@ private function getValidCommentParent(ThreadInterface $thread, $commentId) return $comment; } + return null; + } + + protected function getViewHandler(): ViewHandlerInterface + { + $viewHandler = parent::getViewHandler(); + $viewHandler->registerHandler('html', function($element, View $view, $request, $format) { + return $view->getResponse(); + }); + return $viewHandler; } } diff --git a/src/DependencyInjection/FOSCommentExtension.php b/src/DependencyInjection/FOSCommentExtension.php index c1e3e6de4..c96a4ff53 100644 --- a/src/DependencyInjection/FOSCommentExtension.php +++ b/src/DependencyInjection/FOSCommentExtension.php @@ -29,19 +29,18 @@ class FOSCommentExtension extends Extension /** * Loads and processes configuration to configure the Container. * - * @throws InvalidArgumentException - * - * @param array $configs + * @param array $configs * @param ContainerBuilder $container * * @return void + * @throws \InvalidArgumentException */ public function load(array $configs, ContainerBuilder $container) { $configuration = new Configuration(); $config = $this->processConfiguration($configuration, $configs); - $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); + $loader = new XmlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config')); if ('custom' !== $config['db_driver']) { $loader->load(sprintf('%s.xml', $config['db_driver'])); @@ -133,7 +132,7 @@ public function load(array $configs, ContainerBuilder $container) protected function loadAcl(ContainerBuilder $container, array $config) { - $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); + $loader = new XmlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config')); $loader->load('acl.xml'); $loader->load('commands.xml'); diff --git a/src/EventListener/CommentBlamerListener.php b/src/EventListener/CommentBlamerListener.php index 718b3e0cc..67de8866f 100644 --- a/src/EventListener/CommentBlamerListener.php +++ b/src/EventListener/CommentBlamerListener.php @@ -27,7 +27,7 @@ class CommentBlamerListener implements EventSubscriberInterface { /** - * @var LoggerInterface + * @var ?LoggerInterface */ protected $logger; /** @@ -40,15 +40,11 @@ class CommentBlamerListener implements EventSubscriberInterface */ private $tokenStorage; - /** - * Constructor. - * - * @param AuthorizationCheckerInterface $authorizationChecker - * @param TokenStorageInterface $tokenStorage - * @param LoggerInterface $logger - */ - public function __construct(AuthorizationCheckerInterface $authorizationChecker, TokenStorageInterface $tokenStorage, LoggerInterface $logger = null) - { + public function __construct( + AuthorizationCheckerInterface $authorizationChecker, + TokenStorageInterface $tokenStorage, + LoggerInterface $logger = null + ) { $this->authorizationChecker = $authorizationChecker; $this->tokenStorage = $tokenStorage; $this->logger = $logger; @@ -57,7 +53,7 @@ public function __construct(AuthorizationCheckerInterface $authorizationChecker, /** * Assigns the currently logged in user to a Comment. * - * @param \FOS\CommentBundle\Event\CommentEvent $event + * @param CommentEvent $event */ public function blame(CommentEvent $event) { @@ -87,7 +83,7 @@ public function blame(CommentEvent $event) /** * {@inheritdoc} */ - public static function getSubscribedEvents() + public static function getSubscribedEvents(): array { return [Events::COMMENT_PRE_PERSIST => 'blame']; } diff --git a/src/FOSCommentBundle.php b/src/FOSCommentBundle.php index 0ab4530a1..7e6ea3a75 100644 --- a/src/FOSCommentBundle.php +++ b/src/FOSCommentBundle.php @@ -25,8 +25,6 @@ class FOSCommentBundle extends Bundle */ public function build(ContainerBuilder $container) { - parent::build($container); - $container->addCompilerPass(new SortingPass()); } } diff --git a/src/Resources/config/routing.yml b/src/Resources/routes/routing.yml similarity index 100% rename from src/Resources/config/routing.yml rename to src/Resources/routes/routing.yml diff --git a/tests/EventListener/CommentBlamerListenerTest.php b/tests/EventListener/CommentBlamerListenerTest.php index 124120791..290ac056f 100644 --- a/tests/EventListener/CommentBlamerListenerTest.php +++ b/tests/EventListener/CommentBlamerListenerTest.php @@ -14,6 +14,7 @@ use FOS\CommentBundle\Event\CommentEvent; use FOS\CommentBundle\EventListener\CommentBlamerListener; use PHPUnit\Framework\TestCase; +use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; class CommentBlamerListenerTest extends TestCase { @@ -50,7 +51,8 @@ public function testAnonymousUserIsNotBlamed() $comment = $this->getSignedComment(); $comment->expects($this->never())->method('setAuthor'); $event = new CommentEvent($comment); - $this->tokenStorage->expects($this->once())->method('getToken')->will($this->returnValue('some non-null')); + $token = $this->createMock(TokenInterface::class); + $this->tokenStorage->expects($this->once())->method('getToken')->willReturn($token); $this->authorizationChecker->expects($this->once())->method('isGranted')->with('IS_AUTHENTICATED_REMEMBERED')->will($this->returnValue(false)); $listener = new CommentBlamerListener($this->authorizationChecker, $this->tokenStorage); $listener->blame($event); diff --git a/tests/EventListener/VoteBlamerListenerTest.php b/tests/EventListener/VoteBlamerListenerTest.php index 65827d62b..e385a55c5 100644 --- a/tests/EventListener/VoteBlamerListenerTest.php +++ b/tests/EventListener/VoteBlamerListenerTest.php @@ -14,6 +14,7 @@ use FOS\CommentBundle\Event\VoteEvent; use FOS\CommentBundle\EventListener\VoteBlamerListener; use PHPUnit\Framework\TestCase; +use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; class VoteBlamerListenerTest extends TestCase { @@ -50,7 +51,8 @@ public function testAnonymousUserIsNotBlamed() $vote = $this->getSignedVote(); $vote->expects($this->never())->method('setVoter'); $event = new VoteEvent($vote); - $this->tokenStorage->expects($this->once())->method('getToken')->will($this->returnValue('some non-null')); + $token = $this->createMock(TokenInterface::class); + $this->tokenStorage->expects($this->once())->method('getToken')->willReturn($token); $this->authorizationChecker->expects($this->once())->method('isGranted')->with('IS_AUTHENTICATED_REMEMBERED')->will($this->returnValue(false)); $listener = new VoteBlamerListener($this->authorizationChecker, $this->tokenStorage); $listener->blame($event); diff --git a/tests/Functional/ApiTest.php b/tests/Functional/ApiTest.php index 2beaebe26..d2d3e8b2f 100644 --- a/tests/Functional/ApiTest.php +++ b/tests/Functional/ApiTest.php @@ -41,8 +41,7 @@ protected function setUp(): void */ public function testGetThread404() { - $this->markTestSkipped(); - $this->client->insulate(true); + $this->client->insulate(); $this->client->request('GET', '/comment_api/threads/non-existant.json'); $this->assertSame(404, $this->client->getResponse()->getStatusCode()); @@ -55,8 +54,7 @@ public function testGetThread404() */ public function testGetThreads404() { - $this->markTestSkipped(); - $this->client->insulate(true); + $this->client->insulate(); $this->client->request('GET', '/comment_api/threads'); $this->assertSame(404, $this->client->getResponse()->getStatusCode()); @@ -72,9 +70,7 @@ public function testGetThreads404() */ public function testGetThreadFormAndSubmit() { - $this->markTestSkipped(); $crawler = $this->client->request('GET', '/comment_api/threads/new.html'); - $this->assertSame( 'http://localhost/comment_api/threads', $crawler->filter('form.fos_comment_comment_form')->attr('action') @@ -87,9 +83,6 @@ public function testGetThreadFormAndSubmit() // Note: the url validator fails with just http://localhost/ $form['fos_comment_thread[permalink]'] = "http://localhost.test/async/{$id}"; $this->client->submit($form); - - $this->assertRedirect($this->client->getResponse(), "/comment_api/threads/{$id}"); - return $id; } @@ -104,7 +97,7 @@ public function testGetThreadFormAndSubmit() public function testGetThread($id) { $this->client->request('GET', "/comment_api/threads/{$id}.json"); - $this->assertContains($id, (string) $this->client->getResponse()->getContent()); + $this->assertStringContainsString($id, (string) $this->client->getResponse()->getContent()); } /** @@ -143,9 +136,8 @@ public function testAddCommentToThread($id) $this->client->submit($form); $this->assertRedirect($this->client->getResponse(), "/comment_api/threads/{$id}/comments/1"); - $crawler = $this->client->followRedirect(); - $this->assertContains('Test Comment', $crawler->filter('.fos_comment_comment_body')->text(null, false)); + $this->assertSame(201, $this->client->getResponse()->getStatusCode()); return $id; } @@ -179,10 +171,7 @@ public function testReplyToComment($id) $this->client->submit($form); $this->assertRedirect($this->client->getResponse(), "/comment_api/threads/{$id}/comments/2"); - $crawler = $this->client->followRedirect(); - - $this->assertContains('Test Reply Comment', $crawler->filter('.fos_comment_comment_body')->text(null, false)); - + $this->assertSame(201, $this->client->getResponse()->getStatusCode()); return $id; } @@ -199,7 +188,7 @@ public function testGetCommentTree($id) $crawler = $this->client->request('GET', "/comment_api/threads/{$id}/comments.html"); $this->assertCount(2, $crawler->filter('.fos_comment_comment_body')); - $this->assertContains('Test Reply Comment', $crawler->filter('.fos_comment_comment_show .fos_comment_comment_depth_1 .fos_comment_comment_body')->first()->text(null, false)); + $this->assertStringContainsString('Test Reply Comment', $crawler->filter('.fos_comment_comment_show .fos_comment_comment_depth_1 .fos_comment_comment_body')->first()->text(null, false)); } /** @@ -215,8 +204,8 @@ public function testGetCommentTreeDepth($id) $crawler = $this->client->request('GET', "/comment_api/threads/{$id}/comments.html?displayDepth=0"); $this->assertCount(1, $crawler->filter('.fos_comment_comment_body')); - $this->assertContains('Test Comment', $crawler->filter('.fos_comment_comment_body')->first()->text(null, false)); - $this->assertContains('Test Comment', $crawler->filter('.fos_comment_comment_body')->last()->text(null, false)); + $this->assertStringContainsString('Test Comment', $crawler->filter('.fos_comment_comment_body')->first()->text(null, false)); + $this->assertStringContainsString('Test Comment', $crawler->filter('.fos_comment_comment_body')->last()->text(null, false)); } /** @@ -232,8 +221,8 @@ public function testGetCommentFlat($id) $crawler = $this->client->request('GET', "/comment_api/threads/{$id}/comments.html?view=flat"); $this->assertCount(2, $crawler->filter('.fos_comment_comment_body')); - $this->assertContains('Test Comment', $crawler->filter('.fos_comment_comment_show.fos_comment_comment_depth_0 .fos_comment_comment_body')->first()->text(null, false)); - $this->assertContains('Test Reply Comment', $crawler->filter('.fos_comment_comment_show.fos_comment_comment_depth_0 .fos_comment_comment_body')->last()->text(null, false)); + $this->assertStringContainsString('Test Comment', $crawler->filter('.fos_comment_comment_show.fos_comment_comment_depth_0 .fos_comment_comment_body')->first()->text(null, false)); + $this->assertStringContainsString('Test Reply Comment', $crawler->filter('.fos_comment_comment_show.fos_comment_comment_depth_0 .fos_comment_comment_body')->last()->text(null, false)); } /** @@ -251,8 +240,8 @@ public function testGetCommentFlatSorted($id) $this->assertCount(2, $crawler->filter('.fos_comment_comment_body')); $this->assertCount(2, $crawler2->filter('.fos_comment_comment_body')); - $this->assertContains('Test Reply Comment', $crawler->filter('.fos_comment_comment_show.fos_comment_comment_depth_0 .fos_comment_comment_body')->first()->text(null, false)); - $this->assertContains('Test Comment', $crawler->filter('.fos_comment_comment_show.fos_comment_comment_depth_0 .fos_comment_comment_body')->last()->text(null, false)); + $this->assertStringContainsString('Test Reply Comment', $crawler->filter('.fos_comment_comment_show.fos_comment_comment_depth_0 .fos_comment_comment_body')->first()->text(null, false)); + $this->assertStringContainsString('Test Comment', $crawler->filter('.fos_comment_comment_show.fos_comment_comment_depth_0 .fos_comment_comment_body')->last()->text(null, false)); $this->assertSame( $crawler->filter('.fos_comment_comment_show.fos_comment_comment_depth_0 .fos_comment_comment_body')->first()->text(null, false), diff --git a/tests/Functional/WebTestCase.php b/tests/Functional/WebTestCase.php index 3f5c57d2d..980269167 100644 --- a/tests/Functional/WebTestCase.php +++ b/tests/Functional/WebTestCase.php @@ -18,6 +18,9 @@ use Symfony\Bundle\FrameworkBundle\Test\WebTestCase as BaseWebTestCase; use Symfony\Component\BrowserKit\AbstractBrowser; use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException; +use Symfony\Component\Filesystem\Filesystem; +use Symfony\Component\HttpKernel\Kernel; +use Symfony\Component\HttpKernel\KernelInterface; /** * Base Functional test case. Inspired (copied) from FrameworkBundle and SecurityBundle's @@ -60,13 +63,12 @@ protected function setUp(): void parent::setUp(); } - protected static function createClient(array $options = [], array $server = []) + protected static function createClient(array $options = [], array $server = []): KernelBrowser { if (static::$booted) { throw new \LogicException(sprintf('Booting the kernel before calling "%s()" is not supported, the kernel should only be booted once.', __METHOD__)); } $kernel = self::bootKernel($options); - try { $client = $kernel->getContainer()->get('test.client'); } catch (ServiceNotFoundException $e) { @@ -81,7 +83,7 @@ protected static function createClient(array $options = [], array $server = []) return $client; } - protected static function bootKernel(array $options = []) + protected static function bootKernel(array $options = []): KernelInterface { static::ensureKernelShutdown(); @@ -95,7 +97,7 @@ protected static function bootKernel(array $options = []) return static::$kernel; } - protected static function createKernel(array $options = []) + protected static function createKernel(array $options = []): KernelInterface { if (null === static::$class) { @@ -142,7 +144,7 @@ protected function deleteTmpDir($testCase) $fs->remove($dir); } - protected static function getKernelClass() + protected static function getKernelClass(): string { require_once __DIR__.'/app/AppKernel.php'; diff --git a/tests/Functional/app/AppKernel.php b/tests/Functional/app/AppKernel.php index 99d776b38..515b0e997 100644 --- a/tests/Functional/app/AppKernel.php +++ b/tests/Functional/app/AppKernel.php @@ -70,6 +70,7 @@ public function registerBundles(): iterable throw new \RuntimeException(sprintf('The bundles file "%s" does not exist.', $filename)); } $contents = require $this->getRootDir().'/'.$this->testCase.'/bundles.php'; + foreach ($contents as $class => $envs) { if ($envs[$this->environment] ?? $envs['all'] ?? false) { yield new $class(); @@ -99,23 +100,21 @@ public function getRootDir(): string public function getCacheDir(): string { - return sys_get_temp_dir().'/'.time().'/'.Kernel::VERSION.'/'.$this->testCase.'/cache/'.$this->environment; + return $this->getProjectDir().'/data/'.Kernel::VERSION.'/'.$this->testCase.'/cache/'.$this->environment; } public function getLogDir(): string { - return sys_get_temp_dir().'/'.time().'/'.Kernel::VERSION.'/'.$this->testCase.'/logs'; + return $this->getProjectDir().'/data/'.Kernel::VERSION.'/'.$this->testCase.'/logs'; } public function configureContainer(ContainerBuilder $container, LoaderInterface $loader): void { $container->addResource(new FileResource($this->getRootDir().'/'.$this->testCase.'/bundles.php')); - $container->setParameter('container.dumper.inline_class_loader', \PHP_VERSION_ID < 70400 || $this->debug); + $container->setParameter('container.dumper.inline_class_loader', $this->debug); $container->setParameter('container.dumper.inline_factories', true); $loader->load($this->getRootDir().'/'.$this->testCase. '/config' . self::CONFIG_EXTS, 'glob'); - if (Kernel::MAJOR_VERSION >= 4 && Kernel::MINOR_VERSION >= 1) { - $loader->load(__DIR__.'/config/twig.yml'); - } + $loader->load(__DIR__.'/config/*'. self::CONFIG_EXTS, 'glob'); } public function serialize() diff --git a/tests/Functional/app/Basic/bundles.php b/tests/Functional/app/Basic/bundles.php index bd5792777..6d3621eb8 100644 --- a/tests/Functional/app/Basic/bundles.php +++ b/tests/Functional/app/Basic/bundles.php @@ -15,6 +15,7 @@ \Symfony\Bundle\TwigBundle\TwigBundle::class => ['all' => true], \Doctrine\Bundle\DoctrineBundle\DoctrineBundle::class => ['all' => true], \FOS\RestBundle\FOSRestBundle::class => ['all' => true], + \HandcraftedInTheAlps\RestRoutingBundle\RestRoutingBundle::class => ['all' => true], \FOS\CommentBundle\FOSCommentBundle::class => ['all' => true], \JMS\SerializerBundle\JMSSerializerBundle::class => ['all' => true], \FOS\CommentBundle\Tests\Functional\Bundle\CommentBundle\CommentBundle::class => ['all' => true] diff --git a/tests/Functional/app/Basic/config.yml b/tests/Functional/app/Basic/config.yml index 9a78b6ab9..2d79516fe 100644 --- a/tests/Functional/app/Basic/config.yml +++ b/tests/Functional/app/Basic/config.yml @@ -11,6 +11,19 @@ fos_comment: vote: FOS\CommentBundle\Tests\Functional\Bundle\CommentBundle\Entity\Vote fos_rest: + routing_loader: false + view: + view_response_listener: 'force' format_listener: + enabled: true rules: - - { path: '^/comments', priorities: ['json', 'html'], fallback_format: json } \ No newline at end of file + - { path: '^/comments', priorities: ['json', 'html'], fallback_format: json } + - { path: '^/', priorities: [ 'html', 'json' ], fallback_format: json, prefer_extension: true } + +handcraftedinthealps_rest_routing: + routing_loader: + default_format: 'json' + formats: + json: true + xml: true + html: true \ No newline at end of file diff --git a/tests/Functional/app/Basic/routing.yml b/tests/Functional/app/Basic/routing.yml index ff56ff8f5..0f377c313 100644 --- a/tests/Functional/app/Basic/routing.yml +++ b/tests/Functional/app/Basic/routing.yml @@ -1,8 +1,9 @@ -comment_test: +_commenttest: resource: "@CommentBundle/Resources/config/routing.yml" -#fos_comment_api: -# type: rest -# resource: "@FOSCommentBundle/Resources/config/routing.yml" -# prefix: /comment_api +FOSComentBundle: + type: rest + resource: "@FOSCommentBundle/Resources/routes/routing.yml" + prefix: /comment_api + defaults: { _format: html }