Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 15 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,15 @@ To get started, just extend the base `Core/Client` and create your first endpoin
# OpenMeteoClient.php
<?php

namespace Kubinyete\ExampleSdkPhp;
namespace Teamipag\Sdk;

use Kubinyete\ExampleSdkPhp\Endpoint\ForecastEndpoint;
use Kubinyete\ExampleSdkPhp\Exception\OpenMeteoException;
use Kubinyete\ExampleSdkPhp\Client;
use Kubinyete\ExampleSdkPhp\Exception\HttpException;
use Kubinyete\ExampleSdkPhp\Http\Client\GuzzleHttpClient;
use Kubinyete\ExampleSdkPhp\Http\Response;
use Kubinyete\ExampleSdkPhp\IO\JsonSerializer;
use Teamipag\Sdk\Endpoint\ForecastEndpoint;
use Teamipag\Sdk\Exception\OpenMeteoException;
use Teamipag\Sdk\Client;
use Teamipag\Sdk\Exception\HttpException;
use Teamipag\Sdk\Http\Client\GuzzleHttpClient;
use Teamipag\Sdk\Http\Response;
use Teamipag\Sdk\IO\JsonSerializer;

class OpenMeteoClient extends Client
{
Expand Down Expand Up @@ -69,11 +69,11 @@ class OpenMeteoClient extends Client
# ForecastEndpoint.php
<?php

namespace Kubinyete\ExampleSdkPhp\Endpoint;
namespace Teamipag\Sdk\Endpoint;

use Kubinyete\ExampleSdkPhp\Model\Forecast;
use Kubinyete\ExampleSdkPhp\Model\ForecastSettings;
use Kubinyete\ExampleSdkPhp\Core\Endpoint;
use Teamipag\Sdk\Model\Forecast;
use Teamipag\Sdk\Model\ForecastSettings;
use Teamipag\Sdk\Core\Endpoint;

class ForecastEndpoint extends Endpoint
{
Expand All @@ -94,9 +94,9 @@ class ForecastEndpoint extends Endpoint

require_once __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . 'autoload.php';

use Kubinyete\ExampleSdkPhp\Model\ForecastSettings;
use Kubinyete\ExampleSdkPhp\OpenMeteoClient;
use Kubinyete\ExampleSdkPhp\Exception\HttpClientException;
use Teamipag\Sdk\Model\ForecastSettings;
use Teamipag\Sdk\OpenMeteoClient;
use Teamipag\Sdk\Exception\HttpClientException;

$client = new OpenMeteoClient();

Expand Down
18 changes: 10 additions & 8 deletions composer.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"name": "kubinyete/template-sdk-php",
"description": "Base template for generating highly optimized webservice SDKs",
"type": "project",
"name": "teamipag/template-sdk-php",
"description": "Template SDK PHP",
"type": "library",
"autoload": {
"psr-4": {
"Kubinyete\\TemplateSdkPhp\\": "src/"
"Teamipag\\Sdk\\": "src/"
}
},
"authors": [
Expand All @@ -15,18 +15,20 @@
],
"autoload-dev": {
"psr-4": {
"Kubinyete\\TemplateSdkPhp\\Tests\\": "tests/"
"Teamipag\\Sdk\\Tests\\": "tests/"
}
},
"require": {
"guzzlehttp/guzzle": ">=6.0",
"psr/log": "^1.1",
"psr/log": ">=1.1",
"symfony/polyfill-php81": "^1.28",
"symfony/polyfill-php80": "^1.28"
"symfony/polyfill-php80": "^1.28",
"ipagdevs/schema-builder": "^1.0"
},
"require-dev": {
"symfony/var-dumper": "^5.4",
"fakerphp/faker": "^1.23",
"phpunit/phpunit": "^9.6"
"phpunit/phpunit": "^9.6",
"phpstan/phpstan": "^2.1"
}
}
11 changes: 11 additions & 0 deletions phpstan.neon.dist
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
parameters:
level: max
paths:
- src

excludePaths:
- vendor

treatPhpDocTypesAsCertain: false
reportUnmatchedIgnoredErrors: true
inferPrivatePropertyTypeFromConstructor: true
121 changes: 96 additions & 25 deletions src/Core/Client.php
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
<?php

namespace Kubinyete\TemplateSdkPhp\Core;
namespace Teamipag\Sdk\Core;

use Throwable;
use JsonSerializable;
use Psr\Log\NullLogger;
use Psr\Log\LoggerInterface;
use Kubinyete\TemplateSdkPhp\Http\Response;
use Kubinyete\TemplateSdkPhp\IO\SerializerInterface;
use Kubinyete\TemplateSdkPhp\Exception\HttpException;
use Kubinyete\TemplateSdkPhp\Http\Client\BaseHttpClient;
use Kubinyete\TemplateSdkPhp\Path\CompositePathInterface;
use Teamipag\Sdk\Http\Response;
use Teamipag\Sdk\IO\SerializerInterface;
use Teamipag\Sdk\Exception\HttpException;
use Teamipag\Sdk\Http\Client\BaseHttpClient;
use Teamipag\Sdk\Path\CompositePathInterface;

abstract class Client implements CompositePathInterface
{
private static $requestCounter = 0;
private static int $requestCounter = 0;

protected Environment $environment;
protected BaseHttpClient $httpClient;
Expand All @@ -38,27 +38,34 @@ public function getEnvironment(): Environment

//

protected function serialize($body, ?SerializerInterface $serializer = null): ?string
/**
* Serializes the given body using the provided serializer, or the default serializer if none is provided. If no serializer is available, returns the body as-is.
*
* @param mixed $body
* @param SerializerInterface|null $serializer
* @return string|null
*/
protected function serialize(mixed $body, ?SerializerInterface $serializer = null): ?string
{
$serializer ??= $this->defaultSerializer;

if (!$serializer) {
return $body;
return null;
}

if ($body instanceof JsonSerializable) {
$body = $body->jsonSerialize();
}

if (is_array($body) && $serializer) {
if (is_array($body)) {
$body = $serializer->serialize($body);
}

if (is_object($body) && $serializer) {
if (is_object($body)) {
$body = $serializer->serialize(get_object_vars($body));
}

return $body;
return is_string($body) ? $body : null;
}

//
Expand All @@ -75,40 +82,104 @@ protected function exceptionThrown(Throwable $e): void

//

/**
* Performs an HTTP request to the given URL with the specified method, body, query parameters, and headers. It also handles serialization of the request body and deserialization of the response body using the provided serializers. If an HTTP error occurs, it throws an HttpException with the response details.
*
* @param string $path
* @param array<array-key,mixed> $query
* @param array<array-key,mixed> $header
* @return Response
*/
protected function get(string $path, array $query = [], array $header = []): Response
{
return $this->request(__FUNCTION__, $this->joinPath($path), null, $query, $header);
}

protected function post(string $path, $body, array $query = [], array $header = []): Response
/**
* Performs a POST request to the given URL with the specified body, query parameters, and headers. It also handles serialization of the request body and deserialization of the response body using the provided serializers. If an HTTP error occurs, it throws an HttpException with the response details.
*
* @param string $path
* @param mixed $body
* @param array<array-key,mixed> $query
* @param array<array-key,mixed> $header
* @return Response
*/
protected function post(string $path, mixed $body, array $query = [], array $header = []): Response
{
return $this->request(__FUNCTION__, $this->joinPath($path), $body, $query, $header);
}

protected function put(string $path, $body, array $query = [], array $header = []): Response
/**
* Performs a PUT request to the given URL with the specified body, query parameters, and headers. It also handles serialization of the request body and deserialization of the response body using the provided serializers. If an HTTP error occurs, it throws an HttpException with the response details.
*
* @param string $path
* @param mixed $body
* @param array<array-key,mixed> $query
* @param array<array-key,mixed> $header
* @return Response
*/
protected function put(string $path, mixed $body, array $query = [], array $header = []): Response
{
return $this->request(__FUNCTION__, $this->joinPath($path), $body, $query, $header);
}

protected function patch(string $path, $body, array $query = [], array $header = []): Response
/**
* Performs a PATCH request to the given URL with the specified body, query parameters, and headers. It also handles serialization of the request body and deserialization of the response body using the provided serializers. If an HTTP error occurs, it throws an HttpException with the response details.
*
* @param string $path
* @param mixed $body
* @param array<array-key,mixed> $query
* @param array<array-key,mixed> $header
* @return Response
*/
protected function patch(string $path, mixed $body, array $query = [], array $header = []): Response
{
return $this->request(__FUNCTION__, $this->joinPath($path), $body, $query, $header);
}

protected function delete(string $path, $body, array $query = [], array $header = []): Response
/**
* Performs a DELETE request to the given URL with the specified body, query parameters, and headers. It also handles serialization of the request body and deserialization of the response body using the provided serializers. If an HTTP error occurs, it throws an HttpException with the response details.
*
* @param string $path
* @param mixed $body
* @param array<array-key,mixed> $query
* @param array<array-key,mixed> $header
* @return Response
*/
protected function delete(string $path, mixed $body, array $query = [], array $header = []): Response
{
return $this->request(__FUNCTION__, $this->joinPath($path), $body, $query, $header);
}

/**
* Performs a HEAD request to the given URL with the specified body, query parameters, and headers. It also handles serialization of the request body and deserialization of the response body using the provided serializers. If an HTTP error occurs, it throws an HttpException with the response details.
*
* @param string $path
* @param array<array-key,mixed> $query
* @param array<array-key,mixed> $header
* @return Response
*/
protected function head(string $path, array $query = [], array $header = []): Response
{
return $this->request(__FUNCTION__, $this->joinPath($path), null, $query, $header);
}

/**
* Performs a request to the given URL with the specified method, body, query parameters, and headers. It also handles serialization of the request body and deserialization of the response body using the provided serializers. If an HTTP error occurs, it throws an HttpException with the response details.
*
* @param string $method
* @param string $url
* @param mixed $body
* @param array<array-key,mixed> $query
* @param array<array-key,mixed> $header
* @param SerializerInterface|null $inputSerializer
* @param SerializerInterface|null $outputSerializer
* @return Response
*/
public function request(
string $method,
string $url,
$body,
mixed $body,
array $query = [],
array $header = [],
?SerializerInterface $inputSerializer = null,
Expand All @@ -127,7 +198,7 @@ public function request(
$header['Accept'] = $header['Accept'] ?? $outputSerializer->getContentType();
}

$this->logger->debug("({$requestId}) {$method} {$url} : Sending request", ['body' => $body, 'query' => $query, 'header' => $header]);
$this->logger?->debug("({$requestId}) {$method} {$url} : Sending request", ['body' => $body, 'query' => $query, 'header' => $header]);

try {
$response = $this->httpClient->request(
Expand All @@ -147,20 +218,20 @@ public function request(
$response = Response::from($response);
$response->setSerializer($outputSerializer);

$this->logger->debug("({$requestId}) {$method} {$url} : Read successful", ['response' => $response->getBody()]);
return $this->responseReceived($response) ?? $response;
$this->logger?->debug("({$requestId}) {$method} {$url} : Read successful", ['response' => $response->getBody()]);
return $this->responseReceived($response);
} catch (HttpException $e) {
$response = $e->getResponse();
$this->logger->error("({$requestId}) {$method} {$url} : Read failed with status code {$e->getStatusCode()} {$e->getStatusMessage()}", ['exception' => strval($e), 'response' => $response ? $response->getBody() : null]);
$this->logger?->debug("({$requestId}) {$method} {$url} : Read failed with status code {$e->getStatusCode()} {$e->getStatusMessage()}", ['exception' => strval($e), 'response' => $response ? $response->getBody() : null]);

if ($response) {
$response->setSerializer($outputSerializer);
$e->getResponse()?->setSerializer($outputSerializer);
}

$this->exceptionThrown($e);
throw $e;
} catch (Throwable $e) {
$this->logger->error("({$requestId}) {$method} {$url} : Read failed with unhandled exception", ['exception' => strval($e)]);
$this->exceptionThrown($e);
$this->logger?->debug("({$requestId}) {$method} {$url} : Read failed with unhandled exception", ['exception' => strval($e)]);
throw $e;
}
}

Expand Down
Loading