diff --git a/src/Cache/ArrayCache.php b/src/Cache/ArrayCache.php index 43f5486..c52170e 100644 --- a/src/Cache/ArrayCache.php +++ b/src/Cache/ArrayCache.php @@ -2,17 +2,26 @@ namespace OpenApi\Cache; +/** + * In-memory cache implementation + * Data is stored in PHP arrays and cleared at end of script execution + */ class ArrayCache implements CacheInterface { private array $cache = []; private array $expiry = []; + /** + * Retrieve value from cache + * Returns null if key doesn't exist or has expired + */ public function get(string $key): mixed { if (!isset($this->cache[$key])) { return null; } + // Check if expired if (isset($this->expiry[$key]) && time() > $this->expiry[$key]) { $this->delete($key); return null; @@ -21,26 +30,35 @@ public function get(string $key): mixed return $this->cache[$key]; } + /** + * Save value to cache with expiration + */ public function save(string $key, mixed $value, int $ttl = 3600): bool { $this->cache[$key] = $value; $this->expiry[$key] = time() + $ttl; - + return true; } + /** + * Delete value from cache + */ public function delete(string $key): bool { unset($this->cache[$key], $this->expiry[$key]); - + return true; } + /** + * Clear all cached values + */ public function clear(): bool { $this->cache = []; $this->expiry = []; - + return true; } } \ No newline at end of file diff --git a/src/Cache/CacheInterface.php b/src/Cache/CacheInterface.php index e9c253f..e1172d6 100644 --- a/src/Cache/CacheInterface.php +++ b/src/Cache/CacheInterface.php @@ -2,10 +2,32 @@ namespace OpenApi\Cache; +/** + * Cache interface for SDK implementations + */ interface CacheInterface { + /** + * Retrieve value from cache + */ public function get(string $key): mixed; + + /** + * Save value to cache with TTL + * + * @param string $key Cache key + * @param mixed $value Value to store + * @param int $ttl Time-to-live in seconds (default: 3600) + */ public function save(string $key, mixed $value, int $ttl = 3600): bool; + + /** + * Delete value from cache + */ public function delete(string $key): bool; + + /** + * Clear all cached values + */ public function clear(): bool; } \ No newline at end of file diff --git a/src/Client.php b/src/Client.php index c3edf21..6f7a80f 100644 --- a/src/Client.php +++ b/src/Client.php @@ -2,23 +2,40 @@ namespace OpenApi; -class Client +/** + * Generic HTTP client for OpenAPI services + * Handles REST operations with Bearer token authentication + */ +class Client { private string $token; + /** + * Initialize client with Bearer token + */ public function __construct(string $token) { $this->token = $token; } + /** + * Execute HTTP request + * + * @param string $method HTTP method (GET, POST, PUT, DELETE, PATCH) + * @param string $url Target URL + * @param mixed $payload Request body (for POST/PUT/PATCH) + * @param array|null $params Query parameters (for GET) or form data (for other methods) + * @return string Response body + */ public function request(string $method, string $url, mixed $payload = null, ?array $params = null): string { + // Append query parameters for GET requests if ($params && $method === 'GET') { $url .= '?' . http_build_query($params); } $ch = curl_init(); - + curl_setopt_array($ch, [ CURLOPT_URL => $url, CURLOPT_RETURNTRANSFER => true, @@ -30,12 +47,14 @@ public function request(string $method, string $url, mixed $payload = null, ?arr ] ]); + // Add JSON payload for POST/PUT/PATCH requests if ($payload && in_array($method, ['POST', 'PUT', 'PATCH'])) { curl_setopt($ch, CURLOPT_POSTFIELDS, is_string($payload) ? $payload : json_encode($payload)); } + // Add form data for non-GET requests if ($params && $method !== 'GET') { - curl_setopt($ch, CURLOPT_POSTFIELDS, + curl_setopt($ch, CURLOPT_POSTFIELDS, is_string($params) ? $params : http_build_query($params)); } @@ -44,10 +63,12 @@ public function request(string $method, string $url, mixed $payload = null, ?arr $error = curl_error($ch); curl_close($ch); + // TODO: Provide more graceful error message with connection context (timeout, DNS, SSL, etc.) if ($response === false) { throw new Exception("cURL Error: " . $error); } + // TODO: Parse response body and provide structured error details (error code, message, request ID) if ($httpCode >= 400) { throw new Exception("HTTP Error {$httpCode}: " . $response); } @@ -55,26 +76,41 @@ public function request(string $method, string $url, mixed $payload = null, ?arr return $response; } + /** + * Perform GET request + */ public function get(string $url, ?array $params = null): string { return $this->request('GET', $url, null, $params); } + /** + * Perform POST request + */ public function post(string $url, mixed $payload = null): string { return $this->request('POST', $url, $payload); } + /** + * Perform PUT request + */ public function put(string $url, mixed $payload = null): string { return $this->request('PUT', $url, $payload); } + /** + * Perform DELETE request + */ public function delete(string $url): string { return $this->request('DELETE', $url); } + /** + * Perform PATCH request + */ public function patch(string $url, mixed $payload = null): string { return $this->request('PATCH', $url, $payload); diff --git a/src/Exception.php b/src/Exception.php index e154439..74650d1 100644 --- a/src/Exception.php +++ b/src/Exception.php @@ -2,6 +2,10 @@ namespace OpenApi; +/** + * Custom exception for OpenAPI SDK + * Stores HTTP response details for better error handling + */ class Exception extends \Exception { private mixed $serverResponse = null; @@ -9,6 +13,15 @@ class Exception extends \Exception private mixed $rawResponse = null; private ?int $httpCode = null; + /** + * Store server response details + * TODO: Utilize this method in Client and OauthClient to provide structured error context + * + * @param mixed $response Parsed server response + * @param mixed $headers Response headers + * @param mixed $rawResponse Raw response body + * @param int|null $httpCode HTTP status code + */ public function setServerResponse(mixed $response, mixed $headers = null, mixed $rawResponse = null, ?int $httpCode = null): void { $this->serverResponse = $response; @@ -17,21 +30,33 @@ public function setServerResponse(mixed $response, mixed $headers = null, mixed $this->httpCode = $httpCode; } + /** + * Get parsed server response + */ public function getServerResponse(): mixed { return $this->serverResponse; } + /** + * Get response headers + */ public function getHeaders(): mixed { return $this->headers; } + /** + * Get raw response body + */ public function getRawResponse(): mixed { return $this->rawResponse; } + /** + * Get HTTP status code + */ public function getHttpCode(): ?int { return $this->httpCode; diff --git a/src/OauthClient.php b/src/OauthClient.php index 24ae031..387a9c1 100644 --- a/src/OauthClient.php +++ b/src/OauthClient.php @@ -2,7 +2,11 @@ namespace OpenApi; -class OauthClient +/** + * OAuth client for OpenAPI authentication + * Handles token management using Basic Auth (username:apikey) + */ +class OauthClient { private string $url; private string $username; @@ -11,6 +15,13 @@ class OauthClient const OAUTH_BASE_URL = 'https://oauth.openapi.it'; const TEST_OAUTH_BASE_URL = 'https://test.oauth.openapi.it'; + /** + * Initialize OAuth client + * + * @param string $username API username + * @param string $apikey API key + * @param bool $test Use test environment if true + */ public function __construct(string $username, string $apikey, bool $test = false) { $this->username = $username; @@ -18,46 +29,81 @@ public function __construct(string $username, string $apikey, bool $test = false $this->url = $test ? self::TEST_OAUTH_BASE_URL : self::OAUTH_BASE_URL; } + /** + * Retrieve available scopes + * + * @param bool $limit Limit results if true + * @return string JSON response with scopes + */ public function getScopes(bool $limit = false): string { $params = ['limit' => $limit ? 1 : 0]; $url = $this->url . '/scopes?' . http_build_query($params); - + return $this->request('GET', $url); } + /** + * Create new access token + * + * @param array $scopes List of requested scopes + * @param int $ttl Token time-to-live in seconds (default: 3600) + * @return string JSON response with token details + */ public function createToken(array $scopes, int $ttl = 3600): string { $body = [ 'scopes' => $scopes, 'ttl' => $ttl ]; - + return $this->request('POST', $this->url . '/token', $body); } + /** + * Get tokens for specific scope + * + * @param string $scope Scope filter + * @return string JSON response with matching tokens + */ public function getTokens(string $scope): string { $params = ['scope' => $scope]; $url = $this->url . '/token?' . http_build_query($params); - + return $this->request('GET', $url); } + /** + * Delete token by ID + * + * @param string $id Token ID to delete + * @return string JSON response + */ public function deleteToken(string $id): string { return $this->request('DELETE', $this->url . '/token/' . $id); } + /** + * Get usage counters + * + * @param string $period Time period (e.g., 'daily', 'monthly') + * @param string $date Date in format YYYY-MM-DD + * @return string JSON response with counter data + */ public function getCounters(string $period, string $date): string { return $this->request('GET', $this->url . '/counters/' . $period . '/' . $date); } + /** + * Execute HTTP request with Basic Auth + */ private function request(string $method, string $url, array $body = null): string { $ch = curl_init(); - + curl_setopt_array($ch, [ CURLOPT_URL => $url, CURLOPT_RETURNTRANSFER => true, @@ -78,10 +124,12 @@ private function request(string $method, string $url, array $body = null): strin $error = curl_error($ch); curl_close($ch); + // TODO: Provide more graceful error message with connection context (timeout, DNS, SSL, etc.) if ($response === false) { throw new Exception("cURL Error: " . $error); } + // TODO: Parse response body and provide structured error details with auth-specific hints (invalid credentials, expired key, etc.) if ($httpCode >= 400) { throw new Exception("HTTP Error {$httpCode}: " . $response); }