From: Jérémy Benoist Date: Wed, 23 Jan 2019 08:19:37 +0000 (+0100) Subject: Merge pull request #3627 from craig0990/feature/add-search-api-endpoint X-Git-Url: https://git.immae.eu/?a=commitdiff_plain;h=refs%2Fheads%2F2.4;hp=a8f4f7665c98753cca15140c283d49e0aa4cd0ab;p=github%2Fwallabag%2Fwallabag.git Merge pull request #3627 from craig0990/feature/add-search-api-endpoint Add a basic Search REST endpoint --- diff --git a/src/Wallabag/ApiBundle/Controller/EntryRestController.php b/src/Wallabag/ApiBundle/Controller/EntryRestController.php index f792aaf2..16d8a40b 100644 --- a/src/Wallabag/ApiBundle/Controller/EntryRestController.php +++ b/src/Wallabag/ApiBundle/Controller/EntryRestController.php @@ -4,14 +4,12 @@ namespace Wallabag\ApiBundle\Controller; use Hateoas\Configuration\Route; use Hateoas\Representation\Factory\PagerfantaFactory; -use JMS\Serializer\SerializationContext; use Nelmio\ApiDocBundle\Annotation\ApiDoc; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; use Symfony\Component\HttpKernel\Exception\HttpException; -use Symfony\Component\Routing\Generator\UrlGeneratorInterface; use Wallabag\CoreBundle\Entity\Entry; use Wallabag\CoreBundle\Entity\Tag; use Wallabag\CoreBundle\Event\EntryDeletedEvent; @@ -141,7 +139,7 @@ class EntryRestController extends WallabagRestController 'tags' => $tags, 'since' => $since, ], - UrlGeneratorInterface::ABSOLUTE_URL + true ) ); @@ -773,24 +771,6 @@ class EntryRestController extends WallabagRestController return $this->sendResponse($results); } - /** - * Shortcut to send data serialized in json. - * - * @param mixed $data - * - * @return JsonResponse - */ - private function sendResponse($data) - { - // https://github.com/schmittjoh/JMSSerializerBundle/issues/293 - $context = new SerializationContext(); - $context->setSerializeNull(true); - - $json = $this->get('jms_serializer')->serialize($data, 'json', $context); - - return (new JsonResponse())->setJson($json); - } - /** * Retrieve value from the request. * Used for POST & PATCH on a an entry. diff --git a/src/Wallabag/ApiBundle/Controller/SearchRestController.php b/src/Wallabag/ApiBundle/Controller/SearchRestController.php new file mode 100644 index 00000000..d9f99844 --- /dev/null +++ b/src/Wallabag/ApiBundle/Controller/SearchRestController.php @@ -0,0 +1,65 @@ +validateAuthentication(); + + $term = $request->query->get('term'); + $page = (int) $request->query->get('page', 1); + $perPage = (int) $request->query->get('perPage', 30); + + $qb = $this->get('wallabag_core.entry_repository') + ->getBuilderForSearchByUser( + $this->getUser()->getId(), + $term, + null + ); + + $pagerAdapter = new DoctrineORMAdapter($qb->getQuery(), true, false); + $pager = new Pagerfanta($pagerAdapter); + + $pager->setMaxPerPage($perPage); + $pager->setCurrentPage($page); + + $pagerfantaFactory = new PagerfantaFactory('page', 'perPage'); + $paginatedCollection = $pagerfantaFactory->createRepresentation( + $pager, + new Route( + 'api_get_search', + [ + 'term' => $term, + 'page' => $page, + 'perPage' => $perPage, + ], + true + ) + ); + + return $this->sendResponse($paginatedCollection); + } +} diff --git a/src/Wallabag/ApiBundle/Controller/WallabagRestController.php b/src/Wallabag/ApiBundle/Controller/WallabagRestController.php index 3c7ad0cf..f18b0910 100644 --- a/src/Wallabag/ApiBundle/Controller/WallabagRestController.php +++ b/src/Wallabag/ApiBundle/Controller/WallabagRestController.php @@ -3,6 +3,7 @@ namespace Wallabag\ApiBundle\Controller; use FOS\RestBundle\Controller\FOSRestController; +use JMS\Serializer\SerializationContext; use Nelmio\ApiDocBundle\Annotation\ApiDoc; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\Security\Core\Exception\AccessDeniedException; @@ -64,4 +65,22 @@ class WallabagRestController extends FOSRestController throw $this->createAccessDeniedException('Access forbidden. Entry user id: ' . $requestUserId . ', logged user id: ' . $user->getId()); } } + + /** + * Shortcut to send data serialized in json. + * + * @param mixed $data + * + * @return JsonResponse + */ + protected function sendResponse($data) + { + // https://github.com/schmittjoh/JMSSerializerBundle/issues/293 + $context = new SerializationContext(); + $context->setSerializeNull(true); + + $json = $this->get('jms_serializer')->serialize($data, 'json', $context); + + return (new JsonResponse())->setJson($json); + } } diff --git a/src/Wallabag/ApiBundle/Resources/config/routing_rest.yml b/src/Wallabag/ApiBundle/Resources/config/routing_rest.yml index c0283e71..06e62c37 100644 --- a/src/Wallabag/ApiBundle/Resources/config/routing_rest.yml +++ b/src/Wallabag/ApiBundle/Resources/config/routing_rest.yml @@ -3,6 +3,11 @@ entry: resource: "WallabagApiBundle:EntryRest" name_prefix: api_ +search: + type: rest + resource: "WallabagApiBundle:SearchRest" + name_prefix: api_ + tag: type: rest resource: "WallabagApiBundle:TagRest" diff --git a/tests/Wallabag/ApiBundle/Controller/SearchRestControllerTest.php b/tests/Wallabag/ApiBundle/Controller/SearchRestControllerTest.php new file mode 100644 index 00000000..fd524639 --- /dev/null +++ b/tests/Wallabag/ApiBundle/Controller/SearchRestControllerTest.php @@ -0,0 +1,69 @@ +client->request('GET', '/api/search', [ + 'page' => 1, + 'perPage' => 2, + 'term' => 'entry', // 6 results + ]); + + $this->assertSame(200, $this->client->getResponse()->getStatusCode()); + + $content = json_decode($this->client->getResponse()->getContent(), true); + + $this->assertGreaterThanOrEqual(1, \count($content)); + $this->assertArrayHasKey('items', $content['_embedded']); + $this->assertGreaterThanOrEqual(0, $content['total']); + $this->assertSame(1, $content['page']); + $this->assertSame(2, $content['limit']); + $this->assertGreaterThanOrEqual(1, $content['pages']); + + $this->assertArrayHasKey('_links', $content); + $this->assertArrayHasKey('self', $content['_links']); + $this->assertArrayHasKey('first', $content['_links']); + $this->assertArrayHasKey('last', $content['_links']); + + foreach (['self', 'first', 'last'] as $link) { + $this->assertArrayHasKey('href', $content['_links'][$link]); + $this->assertContains('term=entry', $content['_links'][$link]['href']); + } + + $this->assertSame('application/json', $this->client->getResponse()->headers->get('Content-Type')); + } + + public function testGetSearchWithNoLimit() + { + $this->client->request('GET', '/api/search', [ + 'term' => 'entry', + ]); + + $this->assertSame(200, $this->client->getResponse()->getStatusCode()); + + $content = json_decode($this->client->getResponse()->getContent(), true); + + $this->assertGreaterThanOrEqual(1, \count($content)); + $this->assertArrayHasKey('items', $content['_embedded']); + $this->assertGreaterThanOrEqual(0, $content['total']); + $this->assertSame(1, $content['page']); + $this->assertGreaterThanOrEqual(1, $content['pages']); + + $this->assertArrayHasKey('_links', $content); + $this->assertArrayHasKey('self', $content['_links']); + $this->assertArrayHasKey('first', $content['_links']); + $this->assertArrayHasKey('last', $content['_links']); + + foreach (['self', 'first', 'last'] as $link) { + $this->assertArrayHasKey('href', $content['_links'][$link]); + $this->assertContains('term=entry', $content['_links'][$link]['href']); + } + + $this->assertSame('application/json', $this->client->getResponse()->headers->get('Content-Type')); + } +}