diff --git a/README.md b/README.md index ed4a6124e..dcff6f728 100644 --- a/README.md +++ b/README.md @@ -599,6 +599,7 @@ Lodata supports many sections of the OData specification, these are the major ar * Declared and navigation properties * Referential constraints * Entity singletons +* Passing query options in the [request body](https://docs.oasis-open.org/odata/odata/v4.01/os/part2-url-conventions/odata-v4.01-os-part2-url-conventions.html#sec_PassingQueryOptionsintheRequestBody) * Database [transactions](https://docs.oasis-open.org/odata/odata/v4.01/os/part1-protocol/odata-v4.01-os-part1-protocol.html#sec_ClientErrorResponses) * Requesting [entity references](https://docs.oasis-open.org/odata/odata-json-format/v4.01/odata-json-format-v4.01.html#sec_EntityReference) * [IEEE754](https://docs.oasis-open.org/odata/odata-json-format/v4.01/odata-json-format-v4.01.html#sec_ControllingtheRepresentationofNumber) number-as-string support diff --git a/src/Controller/Transaction.php b/src/Controller/Transaction.php index c31dc7a25..4c32386a2 100644 --- a/src/Controller/Transaction.php +++ b/src/Controller/Transaction.php @@ -228,6 +228,7 @@ class Transaction implements ArgumentInterface PathSegment\Value::class, PathSegment\Count::class, PathSegment\Filter::class, + PathSegment\Query::class, PathSegment\Reference::class, Operation::class, Singleton::class, @@ -1115,6 +1116,7 @@ public function process(): ResponseInterface break; case '$count': + case '$query': $requiredType = MediaType::factory()->parse('text/plain'); break; } diff --git a/src/PathSegment/Query.php b/src/PathSegment/Query.php new file mode 100644 index 000000000..78fbc6a30 --- /dev/null +++ b/src/PathSegment/Query.php @@ -0,0 +1,44 @@ +assertMethod(Request::METHOD_POST); + + if (!$argument instanceof ResponseInterface) { + throw new BadRequestException('bad_argument', 'The provided argument could not provide a response'); + } + + parse_str($transaction->getBody(), $query); + $request = $transaction->getRequest(); + $request->query->replace($query); + $request->setContent(''); + $request->setMethod(Request::METHOD_GET); + $transaction->initialize($request); + + return $argument; + } +} diff --git a/tests/Unit/Protocol/QueryBodyTest.php b/tests/Unit/Protocol/QueryBodyTest.php new file mode 100644 index 000000000..c02c3b6ad --- /dev/null +++ b/tests/Unit/Protocol/QueryBodyTest.php @@ -0,0 +1,48 @@ +withFlightModel(); + } + + public function test_wrong_content_type() + { + $this->assertNotAcceptable( + Request::factory() + ->path('flights/$query') + ->post() + ); + } + + public function test_wrong_method() + { + $this->assertMethodNotAllowed( + Request::factory() + ->text() + ->path('flights/$query') + ); + } + + public function test_query() + { + $this->assertJsonResponse( + Request::factory() + ->path('flights/$query') + ->post() + ->text() + ->body(http_build_query([ + '$count' => 'true', + '$filter' => "destination eq 'lax'", + ])) + ); + } +} \ No newline at end of file diff --git a/tests/Unit/Protocol/__snapshots__/QueryBodyTest__test_query__1.json b/tests/Unit/Protocol/__snapshots__/QueryBodyTest__test_query__1.json new file mode 100644 index 000000000..5dd37666c --- /dev/null +++ b/tests/Unit/Protocol/__snapshots__/QueryBodyTest__test_query__1.json @@ -0,0 +1,20 @@ +{ + "@context": "http://localhost/odata/$metadata#flights", + "value": [ + { + "id": 1, + "origin": "lhr", + "destination": "lax", + "gate": null, + "duration": "PT11H25M0S" + }, + { + "id": 3, + "origin": "sfo", + "destination": "lax", + "gate": null, + "duration": "PT35M33S" + } + ], + "@count": 2 +} diff --git a/tests/Unit/Protocol/__snapshots__/QueryBodyTest__test_wrong_content_type__1.json b/tests/Unit/Protocol/__snapshots__/QueryBodyTest__test_wrong_content_type__1.json new file mode 100644 index 000000000..848af8774 --- /dev/null +++ b/tests/Unit/Protocol/__snapshots__/QueryBodyTest__test_wrong_content_type__1.json @@ -0,0 +1,4 @@ +{ + "code": "unsupported_content_type", + "message": "This route does not support the requested content type, unsupported parameters may have been supplied" +} diff --git a/tests/Unit/Protocol/__snapshots__/QueryBodyTest__test_wrong_method__1.json b/tests/Unit/Protocol/__snapshots__/QueryBodyTest__test_wrong_method__1.json new file mode 100644 index 000000000..809cfbd71 --- /dev/null +++ b/tests/Unit/Protocol/__snapshots__/QueryBodyTest__test_wrong_method__1.json @@ -0,0 +1,4 @@ +{ + "code": "method_not_allowed", + "message": "The GET method is not allowed" +}