mirror of
https://github.com/Thavarshan/fetch-php.git
synced 2025-03-15 04:29:45 +01:00
Replace symfony/http-foundation with guzzlehttp/psr7
This commit is contained in:
parent
e95b135011
commit
fabf4cfc98
12
README.md
12
README.md
@ -31,7 +31,7 @@ FetchPHP provides three main functions:
|
||||
|
||||
### **Custom Guzzle Client Usage**
|
||||
|
||||
By default, FetchPHP uses a single instance of the Guzzle client shared across all requests. However, you can provide your own Guzzle client through the `options` parameter of both `fetch` and `fetch_async`. This gives you full control over the client configuration, including base URI, headers, timeouts, and more.
|
||||
By default, FetchPHP uses a singleton instance of the Guzzle client shared across all requests. However, you can provide your own Guzzle client through the `options` parameter of both `fetch` and `fetch_async`. This gives you full control over the client configuration, including base URI, headers, timeouts, and more.
|
||||
|
||||
### **How to Provide a Custom Guzzle Client**
|
||||
|
||||
@ -92,6 +92,8 @@ echo $response->statusText();
|
||||
|
||||
#### **Available Response Methods**
|
||||
|
||||
The `Response` class, now based on Guzzle’s `Psr7\Response`, provides various methods to interact with the response data:
|
||||
|
||||
- **`json(bool $assoc = true)`**: Decodes the response body as JSON. If `$assoc` is `true`, it returns an associative array. If `false`, it returns an object.
|
||||
- **`text()`**: Returns the response body as plain text.
|
||||
- **`blob()`**: Returns the response body as a PHP stream resource (like a "blob").
|
||||
@ -238,7 +240,9 @@ echo $response->text(); // Outputs error message
|
||||
|
||||
$promise = fetch_async('https://nonexistent-url.com');
|
||||
|
||||
$promise->then(function ($response) {
|
||||
$promise->then(function ($
|
||||
|
||||
response) {
|
||||
echo $response->text();
|
||||
}, function ($exception) {
|
||||
echo "Request failed: " . $exception->getMessage();
|
||||
@ -281,9 +285,7 @@ echo $response->statusText();
|
||||
|
||||
---
|
||||
|
||||
### **Working
|
||||
|
||||
with the Response Object**
|
||||
### **Working with the Response Object**
|
||||
|
||||
The `Response` class provides convenient methods for interacting with the response body, headers, and status codes.
|
||||
|
||||
|
@ -26,8 +26,8 @@
|
||||
"require": {
|
||||
"php": "^8.2",
|
||||
"guzzlehttp/guzzle": "^7.8",
|
||||
"psr/http-message": "^1.0 || ^2.0",
|
||||
"symfony/http-foundation": "^6.0 || ^7.1"
|
||||
"guzzlehttp/psr7": "^2.7",
|
||||
"psr/http-message": "^1.0 || ^2.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"friendsofphp/php-cs-fixer": "^3.64",
|
||||
|
44
src/Http.php
44
src/Http.php
@ -7,9 +7,7 @@ use GuzzleHttp\Cookie\CookieJar;
|
||||
use GuzzleHttp\Exception\RequestException;
|
||||
use GuzzleHttp\Promise\PromiseInterface;
|
||||
use GuzzleHttp\Psr7\MultipartStream;
|
||||
use GuzzleHttp\Psr7\Response as GuzzleResponse;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Symfony\Component\HttpFoundation\Response as SymfonyResponse;
|
||||
|
||||
class Http
|
||||
{
|
||||
@ -48,6 +46,16 @@ class Http
|
||||
self::$client = $client;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the Guzzle client instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function resetClient(): void
|
||||
{
|
||||
self::$client = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to perform HTTP requests using Guzzle.
|
||||
*
|
||||
@ -97,7 +105,13 @@ class Http
|
||||
|
||||
if ($async) {
|
||||
return $client->requestAsync($method, $url, $requestOptions)->then(
|
||||
fn (ResponseInterface $response) => new Response($response),
|
||||
fn (ResponseInterface $response) => new Response(
|
||||
$response->getStatusCode(),
|
||||
$response->getHeaders(),
|
||||
(string) $response->getBody(),
|
||||
$response->getProtocolVersion(),
|
||||
$response->getReasonPhrase()
|
||||
),
|
||||
fn (RequestException $e) => self::handleRequestException($e)
|
||||
);
|
||||
}
|
||||
@ -105,7 +119,13 @@ class Http
|
||||
try {
|
||||
$response = $client->request($method, $url, $requestOptions);
|
||||
|
||||
return new Response($response);
|
||||
return new Response(
|
||||
$response->getStatusCode(),
|
||||
$response->getHeaders(),
|
||||
(string) $response->getBody(),
|
||||
$response->getProtocolVersion(),
|
||||
$response->getReasonPhrase()
|
||||
);
|
||||
} catch (RequestException $e) {
|
||||
return self::handleRequestException($e);
|
||||
}
|
||||
@ -123,9 +143,17 @@ class Http
|
||||
$response = $e->getResponse();
|
||||
|
||||
if ($response) {
|
||||
return new Response($response);
|
||||
return new Response(
|
||||
$response->getStatusCode(),
|
||||
$response->getHeaders(),
|
||||
(string) $response->getBody(),
|
||||
$response->getProtocolVersion(),
|
||||
$response->getReasonPhrase()
|
||||
);
|
||||
}
|
||||
|
||||
error_log('HTTP Error: ' . $e->getMessage());
|
||||
|
||||
return self::createErrorResponse($e);
|
||||
}
|
||||
|
||||
@ -138,12 +166,10 @@ class Http
|
||||
*/
|
||||
protected static function createErrorResponse(RequestException $e): Response
|
||||
{
|
||||
$mockResponse = new GuzzleResponse(
|
||||
SymfonyResponse::HTTP_INTERNAL_SERVER_ERROR,
|
||||
return new Response(
|
||||
500,
|
||||
[],
|
||||
$e->getMessage()
|
||||
);
|
||||
|
||||
return new Response($mockResponse);
|
||||
}
|
||||
}
|
||||
|
@ -2,11 +2,10 @@
|
||||
|
||||
namespace Fetch;
|
||||
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use GuzzleHttp\Psr7\Response as BaseResponse;
|
||||
use RuntimeException;
|
||||
use Symfony\Component\HttpFoundation\Response as SymfonyResponse;
|
||||
|
||||
class Response extends SymfonyResponse
|
||||
class Response extends BaseResponse
|
||||
{
|
||||
/**
|
||||
* The buffered content of the body.
|
||||
@ -18,20 +17,21 @@ class Response extends SymfonyResponse
|
||||
/**
|
||||
* Create new response instance.
|
||||
*
|
||||
* @param \Psr\Http\Message\ResponseInterface $guzzleResponse
|
||||
*
|
||||
* @return void
|
||||
* @param int $status
|
||||
* @param array $headers
|
||||
* @param string $body
|
||||
* @param string $version
|
||||
* @param string $reason
|
||||
*/
|
||||
public function __construct(protected ResponseInterface $guzzleResponse)
|
||||
{
|
||||
// Buffer the body contents to allow multiple reads
|
||||
$this->bodyContents = (string) $guzzleResponse->getBody();
|
||||
|
||||
parent::__construct(
|
||||
$this->bodyContents,
|
||||
$guzzleResponse->getStatusCode(),
|
||||
$guzzleResponse->getHeaders()
|
||||
);
|
||||
public function __construct(
|
||||
int $status = 200,
|
||||
array $headers = [],
|
||||
string $body = '',
|
||||
string $version = '1.1',
|
||||
string $reason = null
|
||||
) {
|
||||
parent::__construct($status, $headers, $body, $version, $reason);
|
||||
$this->bodyContents = (string) $this->getBody();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -41,14 +41,20 @@ class Response extends SymfonyResponse
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function json(bool $assoc = true)
|
||||
public function json(bool $assoc = true, bool $throwOnError = true)
|
||||
{
|
||||
$decoded = json_decode($this->bodyContents, $assoc);
|
||||
if (json_last_error() !== \JSON_ERROR_NONE) {
|
||||
$jsonError = json_last_error();
|
||||
|
||||
if ($jsonError === \JSON_ERROR_NONE) {
|
||||
return $decoded;
|
||||
}
|
||||
|
||||
if ($throwOnError) {
|
||||
throw new RuntimeException('Failed to decode JSON: ' . json_last_error_msg());
|
||||
}
|
||||
|
||||
return $decoded;
|
||||
return null; // or return an empty array/object depending on your needs.
|
||||
}
|
||||
|
||||
/**
|
||||
@ -95,8 +101,7 @@ class Response extends SymfonyResponse
|
||||
*/
|
||||
public function statusText(): string
|
||||
{
|
||||
return $this->statusText
|
||||
?? SymfonyResponse::$statusTexts[$this->getStatusCode()];
|
||||
return $this->getReasonPhrase() ?: 'No reason phrase available';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -5,7 +5,13 @@ use GuzzleHttp\Psr7\Response as GuzzleResponse;
|
||||
|
||||
test('Response::json() correctly decodes JSON', function () {
|
||||
$guzzleResponse = new GuzzleResponse(200, ['Content-Type' => 'application/json'], '{"key":"value"}');
|
||||
$response = new Response($guzzleResponse);
|
||||
$response = new Response(
|
||||
$guzzleResponse->getStatusCode(),
|
||||
$guzzleResponse->getHeaders(),
|
||||
(string) $guzzleResponse->getBody(),
|
||||
$guzzleResponse->getProtocolVersion(),
|
||||
$guzzleResponse->getReasonPhrase()
|
||||
);
|
||||
|
||||
$json = $response->json();
|
||||
expect($json)->toMatchArray(['key' => 'value']);
|
||||
@ -13,14 +19,26 @@ test('Response::json() correctly decodes JSON', function () {
|
||||
|
||||
test('Response::text() correctly retrieves plain text', function () {
|
||||
$guzzleResponse = new GuzzleResponse(200, [], 'Plain text content');
|
||||
$response = new Response($guzzleResponse);
|
||||
$response = new Response(
|
||||
$guzzleResponse->getStatusCode(),
|
||||
$guzzleResponse->getHeaders(),
|
||||
(string) $guzzleResponse->getBody(),
|
||||
$guzzleResponse->getProtocolVersion(),
|
||||
$guzzleResponse->getReasonPhrase()
|
||||
);
|
||||
|
||||
expect($response->text())->toBe('Plain text content');
|
||||
});
|
||||
|
||||
test('Response::blob() correctly retrieves blob (stream)', function () {
|
||||
$guzzleResponse = new GuzzleResponse(200, [], 'Binary data');
|
||||
$response = new Response($guzzleResponse);
|
||||
$response = new Response(
|
||||
$guzzleResponse->getStatusCode(),
|
||||
$guzzleResponse->getHeaders(),
|
||||
(string) $guzzleResponse->getBody(),
|
||||
$guzzleResponse->getProtocolVersion(),
|
||||
$guzzleResponse->getReasonPhrase()
|
||||
);
|
||||
|
||||
$blob = $response->blob();
|
||||
expect(is_resource($blob))->toBeTrue();
|
||||
@ -28,24 +46,36 @@ test('Response::blob() correctly retrieves blob (stream)', function () {
|
||||
|
||||
test('Response::arrayBuffer() correctly retrieves binary data as string', function () {
|
||||
$guzzleResponse = new GuzzleResponse(200, [], 'Binary data');
|
||||
$response = new Response($guzzleResponse);
|
||||
$response = new Response(
|
||||
$guzzleResponse->getStatusCode(),
|
||||
$guzzleResponse->getHeaders(),
|
||||
(string) $guzzleResponse->getBody(),
|
||||
$guzzleResponse->getProtocolVersion(),
|
||||
$guzzleResponse->getReasonPhrase()
|
||||
);
|
||||
|
||||
expect($response->arrayBuffer())->toBe('Binary data');
|
||||
});
|
||||
|
||||
test('Response::statusText() correctly retrieves status text', function () {
|
||||
$guzzleResponse = new GuzzleResponse(200);
|
||||
$response = new Response($guzzleResponse);
|
||||
$response = new Response(
|
||||
$guzzleResponse->getStatusCode(),
|
||||
$guzzleResponse->getHeaders(),
|
||||
(string) $guzzleResponse->getBody(),
|
||||
$guzzleResponse->getProtocolVersion(),
|
||||
$guzzleResponse->getReasonPhrase()
|
||||
);
|
||||
|
||||
expect($response->statusText())->toBe('OK');
|
||||
});
|
||||
|
||||
test('Response status helper methods work correctly', function () {
|
||||
$informationalResponse = new Response(new GuzzleResponse(100));
|
||||
$successfulResponse = new Response(new GuzzleResponse(200));
|
||||
$redirectionResponse = new Response(new GuzzleResponse(301));
|
||||
$clientErrorResponse = new Response(new GuzzleResponse(404));
|
||||
$serverErrorResponse = new Response(new GuzzleResponse(500));
|
||||
$informationalResponse = new Response(100);
|
||||
$successfulResponse = new Response(200);
|
||||
$redirectionResponse = new Response(301);
|
||||
$clientErrorResponse = new Response(404);
|
||||
$serverErrorResponse = new Response(500);
|
||||
|
||||
expect($informationalResponse->isInformational())->toBeTrue();
|
||||
expect($successfulResponse->ok())->toBeTrue();
|
||||
@ -57,7 +87,13 @@ test('Response status helper methods work correctly', function () {
|
||||
test('Response handles error gracefully', function () {
|
||||
$errorMessage = 'Something went wrong';
|
||||
$guzzleResponse = new GuzzleResponse(500, [], $errorMessage);
|
||||
$response = new Response($guzzleResponse);
|
||||
$response = new Response(
|
||||
$guzzleResponse->getStatusCode(),
|
||||
$guzzleResponse->getHeaders(),
|
||||
(string) $guzzleResponse->getBody(),
|
||||
$guzzleResponse->getProtocolVersion(),
|
||||
$guzzleResponse->getReasonPhrase()
|
||||
);
|
||||
|
||||
expect($response->getStatusCode())->toBe(500);
|
||||
expect($response->text())->toBe($errorMessage);
|
||||
|
Loading…
x
Reference in New Issue
Block a user