diff --git a/src/Request.php b/src/Request.php index fc4967f..f9db93c 100644 --- a/src/Request.php +++ b/src/Request.php @@ -99,6 +99,13 @@ class Request */ private $encoding = Request::ENCODING_QUERY; + /** + * Cache of encoded data. + * + * @var string|null + */ + private $encodedData = null; + /** * @param cURL $curl */ @@ -120,7 +127,7 @@ public function setMethod($method) throw new \InvalidArgumentException("Method [$method] not a valid HTTP method."); } - if ($this->data && !static::$methods[$method]) { + if ($this->data && !$this->allowsData()) { throw new \LogicException('Request has POST data, but tried changing HTTP method to one that does not allow POST data'); } @@ -314,6 +321,16 @@ public function formatHeaders() return $headers; } + /** + * Detemine if a request allows data to be set. + * + * @return bool + */ + public function allowsData() + { + return static::$methods[$this->method]; + } + /** * Set the POST data to be sent with the request. * @@ -321,11 +338,12 @@ public function formatHeaders() */ public function setData($data) { - if ($data && !static::$methods[$this->method]) { + if ($data !== null && !$this->allowsData()) { throw new \InvalidArgumentException("HTTP method [$this->method] does not allow POST data."); } $this->data = $data; + $this->encodedData = null; return $this; } @@ -337,7 +355,7 @@ public function setData($data) */ public function hasData() { - return (bool) $this->data; + return (bool) $this->getEncodedData(); } /** @@ -372,6 +390,7 @@ public function setEncoding($encoding) } $this->encoding = $encoding; + $this->encodedData = null; return $this; } @@ -393,6 +412,10 @@ public function getEncoding() */ public function encodeData() { + if ($this->data === null) { + return ''; + } + switch ($this->encoding) { case static::ENCODING_JSON: return json_encode($this->data); @@ -405,6 +428,19 @@ public function encodeData() } } + /** + * Get the encoded POST data as a string. + * + * @return string + */ + public function getEncodedData() + { + if ($this->encodedData === null) { + $this->encodedData = $this->encodeData(); + } + return $this->encodedData; + } + /** * Set a specific curl option for the request. * diff --git a/src/cURL.php b/src/cURL.php index ae72c41..24c0b7e 100644 --- a/src/cURL.php +++ b/src/cURL.php @@ -185,7 +185,7 @@ public function buildUrl($url, array $query) * * @return Request */ - public function newRequest($method, $url, $data = array(), $encoding = Request::ENCODING_QUERY) + public function newRequest($method, $url, $data = null, $encoding = Request::ENCODING_QUERY) { $class = $this->requestClass; $request = new $class($this); @@ -264,7 +264,7 @@ public function prepareRequest(Request $request) curl_setopt($this->ch, CURLOPT_HTTPHEADER, $request->formatHeaders()); if ($request->hasData()) { - curl_setopt($this->ch, CURLOPT_POSTFIELDS, $request->encodeData()); + curl_setopt($this->ch, CURLOPT_POSTFIELDS, $request->getEncodedData()); } if ($method === 'head') { diff --git a/tests/unit/RequestTest.php b/tests/unit/RequestTest.php index b477e0e..95aee91 100644 --- a/tests/unit/RequestTest.php +++ b/tests/unit/RequestTest.php @@ -50,6 +50,50 @@ public function encodeData() $this->assertEquals('ArbitraryValue', $r->encodeData()); } + /** @test */ + public function encodeJsonData() + { + $r = $this->makeRequest(); + $r->setMethod('post'); + $r->setEncoding(Request::ENCODING_JSON); + + $r->setData([]); + $this->assertEquals('[]', $r->encodeData()); + + $r->setData(new \stdClass); + $this->assertEquals('{}', $r->encodeData()); + } + + /** @test */ + public function changeDataUpdatesEncodedData() + { + $r = $this->makeRequest(); + $r->setMethod('post'); + $r->setEncoding(Request::ENCODING_JSON); + + $r->setData(['foo' => 'bar']); + $data1 = $r->getEncodedData(); + $r->setData(['bar' => 'qux']); + $data2 = $r->getEncodedData(); + + $this->assertNotEquals($data1, $data2); + } + + /** @test */ + public function changeEncodingUpdatesEncodedData() + { + $r = $this->makeRequest(); + $r->setMethod('post'); + $r->setData(['foo' => 'bar']); + + $r->setEncoding(Request::ENCODING_JSON); + $jsonData = $r->getEncodedData(); + $r->setEncoding(Request::ENCODING_QUERY); + $queryData = $r->getEncodedData(); + + $this->assertNotEquals($jsonData, $queryData); + } + /** @test */ public function formatHeaders() {