From 8687a7d91583f4185444e68e3c682edec22d0f47 Mon Sep 17 00:00:00 2001 From: "Nek (Maxime Veber)" Date: Tue, 18 Aug 2020 21:29:51 +0200 Subject: [PATCH] feat(response): add collection response Until now when returning a collection it was not standardized. This is fixed. This fix #12 --- CHANGELOG.md | 1 + features/custom_responses.feature | 30 +++++++++++++++++++ src/Response/Model/Collection.php | 12 ++++++++ .../Json/OkContentNormalizer.php | 16 ++++++++++ .../Json/OkContentNormalizerTest.php | 30 +++++++++++++++++++ tests/TestApplication/config/config.yaml | 3 ++ tests/TestApplication/config/routing.yaml | 5 ++++ .../src/Controller/TodoContainsAction.php | 26 ++++++++++++++++ 8 files changed, 123 insertions(+) create mode 100644 features/custom_responses.feature create mode 100644 src/Response/Model/Collection.php create mode 100644 tests/TestApplication/src/Controller/TodoContainsAction.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 5b26095..dc2782b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Support of more kind of FormError - Removed the requirement to have CSRF protection enabled #25 - Behat test suite. Melodiia is officially battle tested! +- Add Collection model to render easily standard output with collections #12 ### Changed - Huge BC Break on namespaces. You need to rename all classes used to SwagIndustries instead of Biig diff --git a/features/custom_responses.feature b/features/custom_responses.feature new file mode 100644 index 0000000..1aa3ed0 --- /dev/null +++ b/features/custom_responses.feature @@ -0,0 +1,30 @@ +Feature: + As a developer + I should be able to render custom response easily with Melodiia + + Scenario: return array of object for a response + Given there are some todos + And I make a GET request on "/todos/contains/foo" + Then the last response contains: + """ + { + "meta": { + "totalPages": 1, + "totalResults": 1, + "currentPage": 1, + "maxPerPage": 1 + }, + "links": { + "prev": null, + "next": null, + "last": "http://localhost/todos/contains/foo", + "first": "http://localhost/todos/contains/foo" + }, + "data": [ + { + "id": 1, + "content": "foo" + } + ] + } + """ diff --git a/src/Response/Model/Collection.php b/src/Response/Model/Collection.php new file mode 100644 index 0000000..4667ce6 --- /dev/null +++ b/src/Response/Model/Collection.php @@ -0,0 +1,12 @@ + \preg_replace('/([?&])page=(\d+)/', '$1page=1', $uri), ]; } + if ($content instanceof Collection) { + $uri = $this->requestStack->getMasterRequest()->getUri(); + $result['meta'] = [ + 'totalPages' => 1, + 'totalResults' => count($content), + 'currentPage' => 1, + 'maxPerPage' => count($content), + ]; + $result['links'] = [ + 'prev' => null, + 'next' => null, + 'last' => $uri, + 'first' => $uri, + ]; + } $result['data'] = []; foreach ($content as $item) { diff --git a/tests/Melodiia/Serialization/Json/OkContentNormalizerTest.php b/tests/Melodiia/Serialization/Json/OkContentNormalizerTest.php index 88049a5..1dcc93f 100644 --- a/tests/Melodiia/Serialization/Json/OkContentNormalizerTest.php +++ b/tests/Melodiia/Serialization/Json/OkContentNormalizerTest.php @@ -7,6 +7,7 @@ use PHPUnit\Framework\TestCase; use Prophecy\Argument; use Prophecy\Prophecy\ObjectProphecy; +use SwagIndustries\Melodiia\Response\Model\Collection; use SwagIndustries\Melodiia\Response\OkContent; use SwagIndustries\Melodiia\Serialization\Json\OkContentNormalizer; use Symfony\Component\HttpFoundation\Request; @@ -131,4 +132,33 @@ public function testItSerializePager() ], ], $res); } + + public function testItSerializeCollection() + { + $collection = new Collection([['acme' => 'foo'], ['acme' => 'bar']]); + $this->mainNormalizer->normalize(['acme' => 'foo'], Argument::cetera())->willReturn(['acme' => 'foo'])->shouldBeCalled(); + $this->mainNormalizer->normalize(['acme' => 'bar'], Argument::cetera())->willReturn(['acme' => 'bar'])->shouldBeCalled(); + $this->request->getUri()->willReturn('http://foo.com/bar'); + + $res = $this->okContentNormalizer->normalize(new OkContent($collection)); + + $this->assertEquals([ + 'data' => [ + ['acme' => 'foo'], + ['acme' => 'bar'], + ], + 'meta' => [ + 'totalPages' => 1, + 'totalResults' => 2, + 'currentPage' => 1, + 'maxPerPage' => 2, + ], + 'links' => [ + 'prev' => null, + 'next' => null, + 'last' => 'http://foo.com/bar', + 'first' => 'http://foo.com/bar', + ], + ], $res); + } } diff --git a/tests/TestApplication/config/config.yaml b/tests/TestApplication/config/config.yaml index e29d9d7..869b704 100644 --- a/tests/TestApplication/config/config.yaml +++ b/tests/TestApplication/config/config.yaml @@ -32,3 +32,6 @@ services: SwagIndustries\Melodiia\Tests\Behat\: resource: '../../Behat/*' + + TestApplication\Controller\TodoContainsAction: + tags: ['controller.service_arguments'] diff --git a/tests/TestApplication/config/routing.yaml b/tests/TestApplication/config/routing.yaml index 8ef5fa6..6a6ddbf 100644 --- a/tests/TestApplication/config/routing.yaml +++ b/tests/TestApplication/config/routing.yaml @@ -5,6 +5,11 @@ get_todos: defaults: melodiia_model: TestApplication\Entity\Todo +get_todo_contains: + path: /todos/contains/{word} + methods: GET + controller: 'TestApplication\Controller\TodoContainsAction' + get_todo: path: /todos/{id} controller: 'melodiia.crud.controller.get' diff --git a/tests/TestApplication/src/Controller/TodoContainsAction.php b/tests/TestApplication/src/Controller/TodoContainsAction.php new file mode 100644 index 0000000..6ee9ce3 --- /dev/null +++ b/tests/TestApplication/src/Controller/TodoContainsAction.php @@ -0,0 +1,26 @@ +getRepository(Todo::class)->findAll(), function (Todo $todo) use ($word) { + $str = new UnicodeString($todo->getContent()); + + return $str->containsAny($word); + }); + + return new OkContent(new Collection($todos)); + } +}