diff --git a/src/Controller/AbstractRestfulController.php b/src/Controller/AbstractRestfulController.php index 454b55ed3..b1bd53050 100644 --- a/src/Controller/AbstractRestfulController.php +++ b/src/Controller/AbstractRestfulController.php @@ -593,10 +593,13 @@ protected function processBodyContent($request) parse_str($content, $parsedParams); - // If parse_str fails to decode, or we have a single element with empty value - if (! is_array($parsedParams) || empty($parsedParams) - || (1 == count($parsedParams) && '' === reset($parsedParams)) - ) { + // If parse_str fails to decode + if (! is_array($parsedParams) || empty($parsedParams)) { + return $content; + } + + // If we have a single element with empty value + if (count($parsedParams) === 1 && reset($parsedParams) === '' && substr($content, -1) !== '=') { return $content; } diff --git a/test/Controller/RestfulControllerTest.php b/test/Controller/RestfulControllerTest.php index 18fdf6833..4e4c1336b 100644 --- a/test/Controller/RestfulControllerTest.php +++ b/test/Controller/RestfulControllerTest.php @@ -100,22 +100,6 @@ public function testDispatchInvokesCreateMethodWhenNoActionPresentAndPostInvoked $this->assertEquals('create', $this->routeMatch->getParam('action')); } - public function testCanReceiveStringAsRequestContent() - { - $string = "any content"; - $this->request->setMethod('PUT'); - $this->request->setContent($string); - $this->routeMatch->setParam('id', $id = 1); - - $controller = new RestfulContentTypeTestController(); - $controller->setEvent($this->event); - $result = $controller->dispatch($this->request, $this->response); - - $this->assertEquals($id, $result['id']); - $this->assertEquals($string, $result['data']); - $this->assertEquals('update', $this->routeMatch->getParam('action')); - } - public function testDispatchInvokesUpdateMethodWhenNoActionPresentAndPutInvokedWithIdentifier() { $entity = ['name' => __FUNCTION__]; @@ -561,4 +545,44 @@ public function providerNotImplementedMethodSets504HttpCodeProvider() ['PUT', json_encode(['foo' => 1]), []], // AbstractRestfulController::replaceList() ]; } + + /** + * @dataProvider nonJsonRequestContent + * + * @param string $action + * @param string $method + * @param string $content + * @param array|string $expectedResult + */ + public function testParseNonJsonRequestContent($action, $method, $content, $expectedResult) + { + $this->request->setMethod($method); + $this->request->setContent($content); + $this->routeMatch->setParam('id', $id = 1); + + $controller = new RestfulContentTypeTestController(); + $controller->setEvent($this->event); + $result = $controller->dispatch($this->request, $this->response); + + $this->assertSame($id, $result['id']); + $this->assertSame($expectedResult, $result['data']); + $this->assertSame($action, $this->routeMatch->getParam('action')); + } + + /** + * @return string[]|mixed[] + */ + public function nonJsonRequestContent() + { + yield ['update', 'PUT', 'foo=', ['foo' => '']]; + yield ['update', 'PUT', 'foo', 'foo']; + yield ['patch', 'PATCH', 'foo=', ['foo' => '']]; + yield ['patch', 'PATCH', 'foo', 'foo']; + yield ['update', 'PUT', 'foo&bar', ['foo' => '', 'bar' => '']]; + yield ['patch', 'PATCH', 'foo&bar', ['foo' => '', 'bar' => '']]; + yield ['update', 'PUT', 'foo=bar', ['foo' => 'bar']]; + yield ['patch', 'PATCH', 'foo=bar', ['foo' => 'bar']]; + yield ['update', 'PUT', 'any content', 'any content']; + yield ['patch', 'PATCH', 'any content', 'any content']; + } } diff --git a/test/Controller/TestAsset/RestfulContentTypeTestController.php b/test/Controller/TestAsset/RestfulContentTypeTestController.php index 1def9dcd2..b415eff91 100644 --- a/test/Controller/TestAsset/RestfulContentTypeTestController.php +++ b/test/Controller/TestAsset/RestfulContentTypeTestController.php @@ -27,4 +27,19 @@ public function update($id, $data) 'data' => $data, ]; } + + /** + * Patch an existing resource + * + * @param mixed $id + * @param mixed $data + * @return array + */ + public function patch($id, $data) + { + return [ + 'id' => $id, + 'data' => $data, + ]; + } }