Commit 1b82381e authored by TheBigB's avatar TheBigB
Browse files

Consistency fixes

parent 75266b18
Pipeline #127580020 passed with stage
in 2 minutes and 21 seconds
.idea
vendor
ci/.phpunit*
......@@ -12,21 +12,32 @@ To execute requests you may provide a URL and HTTP method, but you may also prov
```php
<?php
use OneOfZero\Curly\Curly;
$curly = new Curly();
// Using PSR-7 RequestInterface implementation
$request = (new Request)
->withMethod(Curly::HTTP_POST)
->withUri(new Uri('http://example.com'))
$request = (new Laminas\Diactoros\Request)
->withMethod('POST')
->withUri(new Laminas\Diactoros\Uri('https://example.com'))
->withHeader('Accepts', 'application/json');
$response = $curly->request($request);
// Using plain URL and method
$response = $curly->requestByUrl('http://example.com', Curly::HTTP_DELETE);
$response = $curly->requestByUrl('https://example.com', 'DELETE');
// Using ExtendedServerRequest
$request = (new \OneOfZero\Curly\ExtendedServerRequest)
->withUriString('https://example.com', 'resource', '1337')
->withMethod('POST')
->withUrlEncodedForm(['foo' => 'bar'])
->withHeader('Accepts', 'application/json');
$response = $curly->request($request);
```
By default the `requestByUrl()` and `request()` methods will return a `ResponseInterface`. To process the response
By default, the `requestByUrl()` and `request()` methods will return a `ResponseInterface`. To process the response
manually, you may configure callbacks or configure a custom handler (which under water will configure callbacks, but
provides a cleaner programming interface).
......@@ -47,3 +58,7 @@ routed to the handler, which in turn invokes the callback to determine whether t
The `StreamHandler` decorates the `CancellableHandler` and is an example of a handler that hooks into cURL's read and
write callbacks. It probably isn't very useful since setting the `inputStream` and `outputStream` options in the
`CurlyOptions` object would achieve more or less the same, but helps demonstrate the usage of the callbacks.
The power of the streams is that it allows you to read/write downloads and
uploads in chunks. Combined with streams you can prevent memory exhaustion
when handling large amounts of data.
<?php
/** @noinspection PhpComposerExtensionStubsInspection */
namespace OneOfZero\Curly;
use Psr\Http\Message\StreamInterface;
......
......@@ -3,7 +3,7 @@
namespace OneOfZero\Curly;
use OneOfZero\Curly\Exceptions\CurlException;
use OneOfZero\Curly\Handlers\AbstractHandler;
use OneOfZero\Curly\Handlers\HandlerInterface;
use OneOfZero\Streams\SharedStreamInterface;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
......@@ -29,7 +29,7 @@ class Curly implements HttpClientInterface
/**
* Holds the configured handler (if any).
*
* @var AbstractHandler;
* @var HandlerInterface;
*/
private $customHandler;
......@@ -236,8 +236,6 @@ class Curly implements HttpClientInterface
return $headers;
}
#region // Generic getters and setters
/**
* Gets the CurlyOptions for this instance.
*
......@@ -264,9 +262,9 @@ class Curly implements HttpClientInterface
/**
* Gets the custom handler for this instance (if any).
*
* @return AbstractHandler
* @return HandlerInterface
*/
public function getCustomHandler(): ?AbstractHandler
public function getCustomHandler(): ?HandlerInterface
{
return $this->customHandler;
}
......@@ -274,12 +272,10 @@ class Curly implements HttpClientInterface
/**
* Sets the custom handler for this instance.
*
* @param AbstractHandler $customHandler
* @param HandlerInterface $customHandler
*/
public function setCustomHandler(AbstractHandler $customHandler): void
public function setCustomHandler(HandlerInterface $customHandler): void
{
$this->customHandler = $customHandler;
}
#endregion
}
<?php
/** @noinspection PhpUnused */
namespace OneOfZero\Curly;
use ReflectionClass;
......@@ -408,7 +410,7 @@ class CurlyOptions
/**
* CURLOPT_STDERR (resource)
* @link http://curl.haxx.se/libcurl/c/CURLOPT_STDERR.html
* @var Resource $errorStream
* @var resource $errorStream
*/
public $errorStream;
......@@ -539,21 +541,21 @@ class CurlyOptions
/**
* CURLOPT_FILE (resource)
* @link http://curl.haxx.se/libcurl/c/CURLOPT_FILE.html
* @var Resource $outputStream
* @var resource $outputStream
*/
public $outputStream;
/**
* CURLOPT_INFILE (resource)
* @link http://curl.haxx.se/libcurl/c/CURLOPT_INFILE.html
* @var Resource $inputStream
* @var resource $inputStream
*/
public $inputStream;
/**
* CURLOPT_WRITEHEADER (resource)
* @link http://curl.haxx.se/libcurl/c/CURLOPT_WRITEHEADER.html
* @var Resource $outputHeaderStream
* @var resource $outputHeaderStream
*/
public $outputHeaderStream;
......@@ -682,16 +684,6 @@ class CurlyOptions
}
}
/**
* Creates and returns a clone of this object.
*
* @return CurlyOptions
*/
public function __clone()
{
return new CurlyOptions($this->toArray(false));
}
/**
* Converts the options configured in this object to an array that is compatible with curl_setopt_array().
*
......
<?php
namespace OneOfZero\Curly\Exceptions;
use Exception;
class NotSupportedException extends Exception
{
}
......@@ -21,9 +21,11 @@ class ExtendedServerRequest extends ServerRequest
public function withUriString(...$pieces): self
{
// TODO: Fix this properly - https://tools.ietf.org/html/rfc3986#section-5.2
$pieces = array_map(function($item) { return trim($item, '/'); }, $pieces);
$pieces = array_map(static function($item) { return trim($item, '/'); }, $pieces);
return $this->withUri(new Uri(implode('/', $pieces)));
/** @var self $request */
$request = $this->withUri(new Uri(implode('/', $pieces)));
return $request;
}
/**
......
......@@ -10,35 +10,10 @@ use OneOfZero\Curly\CurlyOptions;
*
* Defines an abstract handler for cURL callback functions.
*/
abstract class AbstractHandler
abstract class AbstractHandler implements HandlerInterface
{
public const ON_HEADER = 'onHeader';
public const ON_PROGRESS = 'onProgress';
public const ON_READ = 'onRead';
public const ON_WRITE = 'onWrite';
protected const VALID_EVENTS = [
self::ON_HEADER,
self::ON_PROGRESS,
self::ON_READ,
self::ON_WRITE
];
/**
* Should return an array with the function names of the events that are implemented. The only supported events are:
* 'onHeader', 'onProgress', 'onRead', and 'onWrite'.
*
* @return string[]
*/
abstract public function getImplemented(): array;
/**
* Registers the functions specified by getImplemented() as callback functions in the provided CurlyOptions
* instance.
*
* This method is for internal use only and should never be used.
*
* @param CurlyOptions $options
* {@inheritDoc}
*/
public function registerCallbacks(CurlyOptions $options): void
{
......@@ -56,19 +31,7 @@ abstract class AbstractHandler
}
/**
* Fired when a header is received from the server.
*
* The provided header data yields a single line of the received header each time that it is called.
*
* The return value must be the size of the header data in bytes. To return this be sure to call the parent, or
* manually return the size (it's advisable to use BinarySafe::strlen).
*
* @see http://curl.haxx.se/libcurl/c/CURLOPT_HEADERFUNCTION.html
*
* @param resource $channel
* @param string $headerData
*
* @return int
* {@inheritDoc}
*/
public function onHeader($channel, string $headerData): int
{
......@@ -76,20 +39,7 @@ abstract class AbstractHandler
}
/**
* Fired frequently during transfer.
*
* Provides upload and download statistics from the request.
*
* Returning non-zero from this method will abort the transfer.
*
* @see http://curl.haxx.se/libcurl/c/CURLOPT_PROGRESSFUNCTION.html
*
* @param resource $channel
* @param int $downloadBytesTotal
* @param int $downloadedBytes
* @param int $uploadBytesTotal
* @param int $uploadedBytes
* @return int
* {@inheritDoc}
*/
public function onProgress(
$channel,
......@@ -102,21 +52,7 @@ abstract class AbstractHandler
}
/**
* Fired when the library is ready to transfer data to the server.
*
* Provides the configured stream, and the size of the buffer.
*
* The return value must yield the data to be transferred. Note that the size of the return value may not exceed
* the provided buffer size. Returning 0 will abort the transfer, but note that sending less than the server is
* expecting, may cause the connection to hang.
*
* @see http://curl.haxx.se/libcurl/c/CURLOPT_READFUNCTION.html
*
* @param resource $channel
* @param resource $stream
* @param int $bufferSize
*
* @return string
* {@inheritDoc}
*/
public function onRead($channel, $stream, int $bufferSize): string
{
......@@ -124,18 +60,7 @@ abstract class AbstractHandler
}
/**
* Fired when data is received from the server.
*
* Provides the received data.
*
* The return value must be the size of the received data in bytes. To return this be sure to call the parent, or
* manually return the size (it's advisable to use BinarySafe::strlen)
*
* @see http://curl.haxx.se/libcurl/c/CURLOPT_WRITEFUNCTION.html
*
* @param resource $channel
* @param string $data
* @return int
* {@inheritDoc}
*/
public function onWrite($channel, string $data): int
{
......
<?php
namespace OneOfZero\Curly\Handlers;
use OneOfZero\Curly\CurlyOptions;
interface HandlerInterface
{
public const ON_HEADER = 'onHeader';
public const ON_PROGRESS = 'onProgress';
public const ON_READ = 'onRead';
public const ON_WRITE = 'onWrite';
public const VALID_EVENTS = [
self::ON_HEADER,
self::ON_PROGRESS,
self::ON_READ,
self::ON_WRITE
];
/**
* Should return an array with the function names of the events that are implemented. The only supported events are:
* 'onHeader', 'onProgress', 'onRead', and 'onWrite'.
*
* @return string[]
*/
public function getImplemented(): array;
/**
* Registers the functions specified by getImplemented() as callback functions in the provided CurlyOptions
* instance.
*
* This method is for internal use only and should never be used.
*
* @param CurlyOptions $options
*/
public function registerCallbacks(CurlyOptions $options): void;
/**
* Fired when a header is received from the server.
*
* The provided header data yields a single line of the received header each time that it is called.
*
* The return value must be the size of the header data in bytes. To return this be sure to call the parent, or
* manually return the size (it's advisable to use BinarySafe::strlen).
*
* @see http://curl.haxx.se/libcurl/c/CURLOPT_HEADERFUNCTION.html
*
* @param resource $channel
* @param string $headerData
*
* @return int
*/
public function onHeader($channel, string $headerData): int;
/**
* Fired frequently during transfer.
*
* Provides upload and download statistics from the request.
*
* Returning non-zero from this method will abort the transfer.
*
* @see http://curl.haxx.se/libcurl/c/CURLOPT_PROGRESSFUNCTION.html
*
* @param resource $channel
* @param int $downloadBytesTotal
* @param int $downloadedBytes
* @param int $uploadBytesTotal
* @param int $uploadedBytes
* @return int
*/
public function onProgress(
$channel,
int $downloadBytesTotal,
int $downloadedBytes,
int $uploadBytesTotal,
int $uploadedBytes
): int;
/**
* Fired when the library is ready to transfer data to the server.
*
* Provides the configured stream, and the size of the buffer.
*
* The return value must yield the data to be transferred. Note that the size of the return value may not exceed
* the provided buffer size. Returning 0 will abort the transfer, but note that sending less than the server is
* expecting, may cause the connection to hang.
*
* @see http://curl.haxx.se/libcurl/c/CURLOPT_READFUNCTION.html
*
* @param resource $channel
* @param resource $stream
* @param int $bufferSize
*
* @return string
*/
public function onRead($channel, $stream, int $bufferSize): string;
/**
* Fired when data is received from the server.
*
* Provides the received data.
*
* The return value must be the size of the received data in bytes. To return this be sure to call the parent, or
* manually return the size (it's advisable to use BinarySafe::strlen)
*
* @see http://curl.haxx.se/libcurl/c/CURLOPT_WRITEFUNCTION.html
*
* @param resource $channel
* @param string $data
* @return int
*/
public function onWrite($channel, string $data): int;
}
......@@ -4,6 +4,7 @@ namespace OneOfZero\Curly\Tests;
use OneOfZero\Curly\Curly;
use OneOfZero\Curly\Handlers\AbstractHandler;
use OneOfZero\Curly\Handlers\HandlerInterface;
use OneOfZero\Curly\SharedStream;
use OneOfZero\Curly\Tests\Fixtures\LoggingHandler;
......@@ -32,12 +33,12 @@ class HandlerTest extends AbstractTestCase
$this->assertNotEmpty($log, 'The handler did not process any data');
$events = array_map(function($entry) { return $entry['event']; }, $log);
$events = array_map(static function($entry) { return $entry['event']; }, $log);
$this->assertContains(AbstractHandler::ON_PROGRESS, $events, 'The handler did not handle any progress events');
$this->assertContains(AbstractHandler::ON_HEADER, $events, 'The handler did not handle any header events');
$this->assertContains(AbstractHandler::ON_READ, $events, 'The handler did not handle any read events');
$this->assertContains(AbstractHandler::ON_WRITE, $events, 'The handler did not handle any write events');
$this->assertContains(HandlerInterface::ON_PROGRESS, $events, 'The handler did not handle any progress events');
$this->assertContains(HandlerInterface::ON_HEADER, $events, 'The handler did not handle any header events');
$this->assertContains(HandlerInterface::ON_READ, $events, 'The handler did not handle any read events');
$this->assertContains(HandlerInterface::ON_WRITE, $events, 'The handler did not handle any write events');
$headersCounted = 0;
$writesCounted = 0;
......@@ -45,7 +46,7 @@ class HandlerTest extends AbstractTestCase
foreach ($events as $event) {
switch ($event) {
case AbstractHandler::ON_HEADER:
case HandlerInterface::ON_HEADER:
$headersCounted++;
if ($writesCounted) {
......@@ -54,11 +55,11 @@ class HandlerTest extends AbstractTestCase
}
break;
case AbstractHandler::ON_WRITE:
case HandlerInterface::ON_WRITE:
$writesCounted++;
break;
case AbstractHandler::ON_READ:
case HandlerInterface::ON_READ:
$readsCounted++;
if ($headersCounted !== 2) {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment