Add Client class
Move Request::request() to Client::request()
This commit is contained in:
parent
ad1e5a1782
commit
1a21b2b7d0
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Encoding" useUTFGuessing="true" native2AsciiForPropertiesFiles="false" />
|
||||
</project>
|
||||
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectRootManager" version="2" />
|
||||
</project>
|
||||
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/wellrested.iml" filepath="$PROJECT_DIR$/.idea/wellrested.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="WEB_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
|
||||
17
README.md
17
README.md
|
|
@ -180,7 +180,11 @@ if ($rqst->getMethod() === 'PUT') {
|
|||
}
|
||||
```
|
||||
|
||||
The Request class can also make a request to another server and provide the response as a Response object. (This feature requires [PHP cURL](http://php.net/manual/en/book.curl.php).)
|
||||
### HTTP Client
|
||||
|
||||
You can also use the `Client` class to make a request using cURL.
|
||||
|
||||
(This feature requires [PHP cURL](http://php.net/manual/en/book.curl.php).)
|
||||
|
||||
```php
|
||||
// Prepare a request.
|
||||
|
|
@ -189,8 +193,9 @@ $rqst->setUri('http://my.api.local/resources/');
|
|||
$rqst->setMethod('POST');
|
||||
$rqst->setBody(json_encode($newResource));
|
||||
|
||||
// Make the request.
|
||||
$resp = $rqst->request();
|
||||
// Use a Client to get a Response.
|
||||
$client = new Client();
|
||||
$resp = $client->request($rqst);
|
||||
|
||||
// Read the response.
|
||||
if ($resp->getStatusCode() === 201) {
|
||||
|
|
@ -200,12 +205,6 @@ if ($resp->getStatusCode() === 201) {
|
|||
```
|
||||
|
||||
|
||||
More Examples
|
||||
---------------
|
||||
|
||||
For more examples, see the project [pjdietz/wellrested-samples](https://github.com/pjdietz/wellrested-samples). **Not yet updated for version 2.0**
|
||||
|
||||
|
||||
Copyright and License
|
||||
---------------------
|
||||
Copyright © 2014 by PJ Dietz
|
||||
|
|
|
|||
|
|
@ -0,0 +1,122 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* pjdietz\WellRESTed\Client
|
||||
*
|
||||
* @author PJ Dietz <pj@pjdietz.com>
|
||||
* @copyright Copyright 2014 by PJ Dietz
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
namespace pjdietz\WellRESTed;
|
||||
|
||||
use pjdietz\WellRESTed\Exceptions\CurlException;
|
||||
use pjdietz\WellRESTed\Interfaces\RequestInterface;
|
||||
use pjdietz\WellRESTed\Interfaces\ResponseInterface;
|
||||
|
||||
/**
|
||||
* Class for making HTTP requests using cURL.
|
||||
*/
|
||||
class Client
|
||||
{
|
||||
/** @var array cURL options */
|
||||
private $curlOpts;
|
||||
|
||||
public function __construct(array $curlOpts = null) {
|
||||
if (is_array($curlOpts)) {
|
||||
$this->curlOpts = $curlOpts;
|
||||
} else {
|
||||
$this->curlOpts = array();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Make an HTTP request and return a Response.
|
||||
*
|
||||
* @param RequestInterface $rqst
|
||||
* @param array $curlOpts Option array of cURL options
|
||||
* @throws \pjdietz\WellRESTed\Exceptions\CurlException
|
||||
* @return ResponseInterface
|
||||
*/
|
||||
public function request(RequestInterface $rqst, $curlOpts = null)
|
||||
{
|
||||
$ch = curl_init();
|
||||
|
||||
$headers = array();
|
||||
foreach ($rqst->getHeaders() as $field => $value) {
|
||||
$lines[] = sprintf('%s: %s', $field, $value);
|
||||
}
|
||||
|
||||
$options = $this->curlOpts;
|
||||
$options[CURLOPT_URL] = $rqst->getUri();
|
||||
$options[CURLOPT_PORT] = $rqst->getPort();
|
||||
$options[CURLOPT_HEADER] = 1;
|
||||
$options[CURLOPT_RETURNTRANSFER] = 1;
|
||||
$options[CURLOPT_HTTPHEADER] = $headers;
|
||||
|
||||
// Set the method. Include the body, if needed.
|
||||
switch ($rqst->getMethod()) {
|
||||
case 'GET':
|
||||
$options[CURLOPT_HTTPGET] = 1;
|
||||
break;
|
||||
case 'POST':
|
||||
$options[CURLOPT_POST] = 1;
|
||||
$options[CURLOPT_POSTFIELDS] = $rqst->getBody();
|
||||
break;
|
||||
case 'PUT':
|
||||
$options[CURLOPT_CUSTOMREQUEST] = 'PUT';
|
||||
$options[CURLOPT_POSTFIELDS] = $rqst->getBody();
|
||||
break;
|
||||
default:
|
||||
$options[CURLOPT_CUSTOMREQUEST] = $rqst->getMethod();
|
||||
$options[CURLOPT_POSTFIELDS] = $rqst->getBody();
|
||||
break;
|
||||
}
|
||||
|
||||
// Override cURL options with the user options passed in.
|
||||
if ($curlOpts) {
|
||||
foreach ($curlOpts as $optKey => $optValue) {
|
||||
$options[$optKey] = $optValue;
|
||||
}
|
||||
}
|
||||
|
||||
// Set the cURL options.
|
||||
curl_setopt_array($ch, $options);
|
||||
|
||||
// Make the cURL request.
|
||||
$result = curl_exec($ch);
|
||||
|
||||
// Throw an exception in the event of a cURL error.
|
||||
if ($result === false) {
|
||||
$error = curl_error($ch);
|
||||
$errno = curl_errno($ch);
|
||||
curl_close($ch);
|
||||
throw new CurlException($error, $errno);
|
||||
}
|
||||
|
||||
// Make a reponse to populate and return with data obtained via cURL.
|
||||
$resp = new Response();
|
||||
|
||||
$resp->setStatusCode(curl_getinfo($ch, CURLINFO_HTTP_CODE));
|
||||
|
||||
// Split the result into headers and body.
|
||||
$headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
|
||||
$headers = substr($result, 0, $headerSize);
|
||||
$body = substr($result, $headerSize);
|
||||
|
||||
// Set the body. Do not auto-add the Content-length header.
|
||||
$resp->setBody($body, false);
|
||||
|
||||
// Iterate over the headers line by line and add each one.
|
||||
foreach (explode("\r\n", $headers) as $header) {
|
||||
if (strpos($header, ':')) {
|
||||
list ($headerName, $headerValue) = explode(':', $header, 2);
|
||||
$resp->setHeader($headerName, ltrim($headerValue));
|
||||
}
|
||||
}
|
||||
|
||||
curl_close($ch);
|
||||
|
||||
return $resp;
|
||||
}
|
||||
}
|
||||
|
|
@ -22,6 +22,20 @@ interface RequestInterface
|
|||
*/
|
||||
public function getMethod();
|
||||
|
||||
/**
|
||||
* Return the full URI for the request.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUri();
|
||||
|
||||
/**
|
||||
* Return the hostname portion of the URI
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getHostname();
|
||||
|
||||
/**
|
||||
* Return path component of the request URI.
|
||||
*
|
||||
|
|
@ -29,6 +43,13 @@ interface RequestInterface
|
|||
*/
|
||||
public function getPath();
|
||||
|
||||
/**
|
||||
* Return the HTTP port
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getPort();
|
||||
|
||||
/**
|
||||
* Return an associative array of query paramters.
|
||||
*
|
||||
|
|
@ -47,6 +68,13 @@ interface RequestInterface
|
|||
*/
|
||||
public function getHeader($headerName);
|
||||
|
||||
/**
|
||||
* Return an associative array of headers.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getHeaders();
|
||||
|
||||
/**
|
||||
* Return the body of the request.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -72,20 +72,6 @@ abstract class Message
|
|||
return $this->headers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array containing one string for each header as "field: value"
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getHeaderLines()
|
||||
{
|
||||
$lines = array();
|
||||
foreach ($this->headers as $field => $value) {
|
||||
$lines[] = sprintf('%s: %s', $field, $value);
|
||||
}
|
||||
return $lines;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the value of a given header, or false if it does not exist.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -336,91 +336,6 @@ class Request extends Message implements RequestInterface
|
|||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Make a cURL request out of the instance and return a Response.
|
||||
*
|
||||
* @param array|null $curlOpts Associative array of options to set using curl_setopt_array before making the request.
|
||||
* @throws Exceptions\CurlException
|
||||
* @return Response
|
||||
*/
|
||||
public function request($curlOpts = null)
|
||||
{
|
||||
$ch = curl_init();
|
||||
|
||||
$options = array(
|
||||
CURLOPT_URL => $this->getUri(),
|
||||
CURLOPT_PORT => $this->port,
|
||||
CURLOPT_HEADER => 1,
|
||||
CURLOPT_RETURNTRANSFER => 1,
|
||||
CURLOPT_HTTPHEADER => $this->getHeaderLines()
|
||||
);
|
||||
|
||||
// Set the method. Include the body, if needed.
|
||||
switch ($this->method) {
|
||||
case 'GET':
|
||||
$options[CURLOPT_HTTPGET] = 1;
|
||||
break;
|
||||
case 'POST':
|
||||
$options[CURLOPT_POST] = 1;
|
||||
$options[CURLOPT_POSTFIELDS] = $this->body;
|
||||
break;
|
||||
case 'PUT':
|
||||
$options[CURLOPT_CUSTOMREQUEST] = 'PUT';
|
||||
$options[CURLOPT_POSTFIELDS] = $this->body;
|
||||
break;
|
||||
default:
|
||||
$options[CURLOPT_CUSTOMREQUEST] = $this->method;
|
||||
$options[CURLOPT_POSTFIELDS] = $this->body;
|
||||
break;
|
||||
}
|
||||
|
||||
// Override cURL options with the user options passed in.
|
||||
if ($curlOpts) {
|
||||
foreach ($curlOpts as $optKey => $optValue) {
|
||||
$options[$optKey] = $optValue;
|
||||
}
|
||||
}
|
||||
|
||||
// Set the cURL options.
|
||||
curl_setopt_array($ch, $options);
|
||||
|
||||
// Make the cURL request.
|
||||
$result = curl_exec($ch);
|
||||
|
||||
// Throw an exception in the event of a cURL error.
|
||||
if ($result === false) {
|
||||
$error = curl_error($ch);
|
||||
$errno = curl_errno($ch);
|
||||
curl_close($ch);
|
||||
throw new CurlException($error, $errno);
|
||||
}
|
||||
|
||||
// Make a reponse to populate and return with data obtained via cURL.
|
||||
$resp = new Response();
|
||||
|
||||
$resp->setStatusCode(curl_getinfo($ch, CURLINFO_HTTP_CODE));
|
||||
|
||||
// Split the result into headers and body.
|
||||
$headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
|
||||
$headers = substr($result, 0, $headerSize);
|
||||
$body = substr($result, $headerSize);
|
||||
|
||||
// Set the body. Do not auto-add the Content-length header.
|
||||
$resp->setBody($body, false);
|
||||
|
||||
// Iterate over the headers line by line and add each one.
|
||||
foreach (explode("\r\n", $headers) as $header) {
|
||||
if (strpos($header, ':')) {
|
||||
list ($headerName, $headerValue) = explode(':', $header, 2);
|
||||
$resp->setHeader($headerName, ltrim($headerValue));
|
||||
}
|
||||
}
|
||||
|
||||
curl_close($ch);
|
||||
|
||||
return $resp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the default port for the currently set scheme.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -0,0 +1,82 @@
|
|||
<?php
|
||||
|
||||
use pjdietz\WellRESTed\Client;
|
||||
use pjdietz\WellRESTed\Request;
|
||||
use pjdietz\WellRESTed\Test;
|
||||
|
||||
class ClientTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testFake()
|
||||
{
|
||||
$this->assertTrue(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider curlProvider
|
||||
*/
|
||||
public function testCurl($method, $uri, $opts, $code)
|
||||
{
|
||||
$rqst = $this->getMockBuilder('pjdietz\WellRESTed\Request')->getMock();
|
||||
$rqst->expects($this->any())
|
||||
->method("getUri")
|
||||
->will($this->returnValue($uri));
|
||||
$rqst->expects($this->any())
|
||||
->method("getMethod")
|
||||
->will($this->returnValue($method));
|
||||
$rqst->expects($this->any())
|
||||
->method("getPort")
|
||||
->will($this->returnValue(80));
|
||||
$rqst->expects($this->any())
|
||||
->method("getHeaders")
|
||||
->will($this->returnValue(array(
|
||||
"Cache-control" => "max-age=0"
|
||||
)));
|
||||
|
||||
$client = new Client(array(CURLOPT_HTTPHEADER => array("Cache-control" => "max-age=0")));
|
||||
$resp = $client->request($rqst, $opts);
|
||||
$this->assertEquals($code, $resp->getStatusCode());
|
||||
}
|
||||
|
||||
public function curlProvider()
|
||||
{
|
||||
return [
|
||||
["GET", "http://icanhasip.com", [
|
||||
[CURLOPT_MAXREDIRS => 2]
|
||||
], 200],
|
||||
["POST", "http://icanhasip.com", [], 200],
|
||||
["PUT", "http://icanhasip.com", [], 405],
|
||||
["DELETE", "http://icanhasip.com", [], 405]
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider curlErrorProvider
|
||||
* @expectedException \pjdietz\WellRESTed\Exceptions\CurlException
|
||||
*/
|
||||
public function testErrorCurl($uri, $opts)
|
||||
{
|
||||
$rqst = $this->getMockBuilder('pjdietz\WellRESTed\Request')->getMock();
|
||||
$rqst->expects($this->any())
|
||||
->method("getUri")
|
||||
->will($this->returnValue($uri));
|
||||
$rqst->expects($this->any())
|
||||
->method("getHeaders")
|
||||
->will($this->returnValue(array(
|
||||
"Cache-control" => "max-age=0"
|
||||
)));
|
||||
|
||||
$rqst = new Request($uri);
|
||||
$client = new Client();
|
||||
$client->request($rqst, $opts);
|
||||
}
|
||||
|
||||
public function curlErrorProvider()
|
||||
{
|
||||
return [
|
||||
["http://localhost:9991", [
|
||||
CURLOPT_FAILONERROR, true,
|
||||
CURLOPT_TIMEOUT_MS, 10
|
||||
]],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -45,15 +45,6 @@ class RequestBuilderTest extends \PHPUnit_Framework_TestCase
|
|||
$this->assertEquals(3, count($this->request->getHeaders()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider headerProvider
|
||||
*/
|
||||
public function testHeaderLines($name, $value, $testName)
|
||||
{
|
||||
$line = "$name: $value";
|
||||
$this->assertTrue(in_array($line, $this->request->getHeaderLines()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider headerProvider
|
||||
*/
|
||||
|
|
@ -498,46 +489,4 @@ class RequestBuilderTest extends \PHPUnit_Framework_TestCase
|
|||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider curlProvider
|
||||
*/
|
||||
public function testCurl($method, $uri, $opts, $code)
|
||||
{
|
||||
$rqst = new Request($uri);
|
||||
$rqst->setMethod($method);
|
||||
$resp = $rqst->request($opts);
|
||||
$this->assertEquals($code, $resp->getStatusCode());
|
||||
}
|
||||
|
||||
public function curlProvider()
|
||||
{
|
||||
return [
|
||||
["GET", "http://icanhasip.com", [
|
||||
[CURLOPT_MAXREDIRS => 2]
|
||||
], 200],
|
||||
["POST", "http://icanhasip.com", [], 200],
|
||||
["PUT", "http://icanhasip.com", [], 405],
|
||||
["DELETE", "http://icanhasip.com", [], 405]
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider curlErrorProvider
|
||||
* @expectedException \pjdietz\WellRESTed\Exceptions\CurlException
|
||||
*/
|
||||
public function testErrorCurl($uri, $opts)
|
||||
{
|
||||
$rqst = new Request($uri);
|
||||
$resp = $rqst->request($opts);
|
||||
}
|
||||
|
||||
public function curlErrorProvider()
|
||||
{
|
||||
return [
|
||||
["http://localhost:9991", [
|
||||
CURLOPT_FAILONERROR, true,
|
||||
CURLOPT_TIMEOUT_MS, 10
|
||||
]],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -173,6 +173,4 @@ class ResponseBuilderTest extends \PHPUnit_Framework_TestCase
|
|||
$this->assertEquals($body, $captured);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue