chore: complete update
This commit is contained in:
378
src/Infrastructure/Api/ShopifyClient.php
Normal file
378
src/Infrastructure/Api/ShopifyClient.php
Normal file
@@ -0,0 +1,378 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Infrastructure\Api;
|
||||
|
||||
use App\Framework\Api\ApiException;
|
||||
use App\Framework\Api\ApiRequestTrait;
|
||||
use App\Framework\Http\Method;
|
||||
use App\Framework\HttpClient\AuthConfig;
|
||||
use App\Framework\HttpClient\ClientOptions;
|
||||
use App\Framework\HttpClient\ClientResponse;
|
||||
use App\Framework\HttpClient\CurlHttpClient;
|
||||
use App\Framework\HttpClient\HttpClient;
|
||||
|
||||
final class ShopifyClient
|
||||
{
|
||||
use ApiRequestTrait;
|
||||
|
||||
private string $apiVersion;
|
||||
|
||||
/**
|
||||
* Erstellt einen neuen Shopify API-Client
|
||||
*
|
||||
* @param string $shopDomain Die Shopify-Domain (z.B. 'my-store.myshopify.com')
|
||||
* @param string $accessToken Das Zugriffstoken für die API
|
||||
* @param string $apiVersion Die API-Version (z.B. '2023-10')
|
||||
* @param HttpClient|null $httpClient Ein optionaler HTTP-Client
|
||||
*/
|
||||
public function __construct(
|
||||
string $shopDomain,
|
||||
string $accessToken,
|
||||
string $apiVersion = '2024-04',
|
||||
?HttpClient $httpClient = null
|
||||
) {
|
||||
$this->baseUrl = "https://{$shopDomain}/admin/api/{$apiVersion}";
|
||||
$this->apiVersion = $apiVersion;
|
||||
|
||||
$this->defaultOptions = new ClientOptions(
|
||||
auth: AuthConfig::custom([
|
||||
'headers' => ['X-Shopify-Access-Token' => $accessToken]
|
||||
])
|
||||
);
|
||||
|
||||
$this->httpClient = $httpClient ?? new CurlHttpClient();
|
||||
}
|
||||
|
||||
/**
|
||||
* Ruft eine Liste aller Produkte ab
|
||||
*
|
||||
* @param array $options Optionale Parameter (limit, since_id, usw.)
|
||||
* @return array Die Produktliste
|
||||
*/
|
||||
public function getProducts(array $options = []): array
|
||||
{
|
||||
$queryParams = $this->buildQueryParams($options);
|
||||
$endpoint = 'products.json' . $queryParams;
|
||||
|
||||
$response = $this->sendRequest(
|
||||
method: Method::GET,
|
||||
endpoint: $endpoint
|
||||
);
|
||||
|
||||
return $this->decodeJson($response)['products'] ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Ruft ein einzelnes Produkt ab
|
||||
*
|
||||
* @param int $productId Die Produkt-ID
|
||||
* @return array Die Produktdaten
|
||||
*/
|
||||
public function getProduct(int $productId): array
|
||||
{
|
||||
$response = $this->sendRequest(
|
||||
method: Method::GET,
|
||||
endpoint: "products/{$productId}.json"
|
||||
);
|
||||
|
||||
return $this->decodeJson($response)['product'] ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Erstellt ein neues Produkt
|
||||
*
|
||||
* @param array $productData Die Produktdaten
|
||||
* @return array Das erstellte Produkt
|
||||
*/
|
||||
public function createProduct(array $productData): array
|
||||
{
|
||||
$response = $this->sendRequest(
|
||||
method: Method::POST,
|
||||
endpoint: 'products.json',
|
||||
data: ['product' => $productData]
|
||||
);
|
||||
|
||||
return $this->decodeJson($response)['product'] ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Aktualisiert ein bestehendes Produkt
|
||||
*
|
||||
* @param int $productId Die Produkt-ID
|
||||
* @param array $productData Die zu aktualisierenden Produktdaten
|
||||
* @return array Das aktualisierte Produkt
|
||||
*/
|
||||
public function updateProduct(int $productId, array $productData): array
|
||||
{
|
||||
$response = $this->sendRequest(
|
||||
method: Method::PUT,
|
||||
endpoint: "products/{$productId}.json",
|
||||
data: ['product' => $productData]
|
||||
);
|
||||
|
||||
return $this->decodeJson($response)['product'] ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Löscht ein Produkt
|
||||
*
|
||||
* @param int $productId Die Produkt-ID
|
||||
* @return bool Erfolg oder Misserfolg
|
||||
*/
|
||||
public function deleteProduct(int $productId): bool
|
||||
{
|
||||
$response = $this->sendRequest(
|
||||
method: Method::DELETE,
|
||||
endpoint: "products/{$productId}.json"
|
||||
);
|
||||
|
||||
return $response->status->value === 200;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ruft eine Liste aller Bestellungen ab
|
||||
*
|
||||
* @param array $options Optionale Parameter (limit, status, usw.)
|
||||
* @return array Die Bestellungsliste
|
||||
*/
|
||||
public function getOrders(array $options = []): array
|
||||
{
|
||||
$queryParams = $this->buildQueryParams($options);
|
||||
$endpoint = 'orders.json' . $queryParams;
|
||||
|
||||
$response = $this->sendRequest(
|
||||
method: Method::GET,
|
||||
endpoint: $endpoint
|
||||
);
|
||||
|
||||
return $this->decodeJson($response)['orders'] ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Ruft eine einzelne Bestellung ab
|
||||
*
|
||||
* @param int $orderId Die Bestellungs-ID
|
||||
* @return array Die Bestellungsdaten
|
||||
*/
|
||||
public function getOrder(int $orderId): array
|
||||
{
|
||||
$response = $this->sendRequest(
|
||||
method: Method::GET,
|
||||
endpoint: "orders/{$orderId}.json"
|
||||
);
|
||||
|
||||
return $this->decodeJson($response)['order'] ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Erstellt eine neue Bestellung
|
||||
*
|
||||
* @param array $orderData Die Bestellungsdaten
|
||||
* @return array Die erstellte Bestellung
|
||||
*/
|
||||
public function createOrder(array $orderData): array
|
||||
{
|
||||
$response = $this->sendRequest(
|
||||
method: Method::POST,
|
||||
endpoint: 'orders.json',
|
||||
data: ['order' => $orderData]
|
||||
);
|
||||
|
||||
return $this->decodeJson($response)['order'] ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Ruft Informationen über den Shop ab
|
||||
*
|
||||
* @return array Die Shop-Informationen
|
||||
*/
|
||||
public function getShopInfo(): array
|
||||
{
|
||||
$response = $this->sendRequest(
|
||||
method: Method::GET,
|
||||
endpoint: 'shop.json'
|
||||
);
|
||||
|
||||
return $this->decodeJson($response)['shop'] ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Ruft eine Liste aller Kunden ab
|
||||
*
|
||||
* @param array $options Optionale Parameter (limit, since_id, usw.)
|
||||
* @return array Die Kundenliste
|
||||
*/
|
||||
public function getCustomers(array $options = []): array
|
||||
{
|
||||
$queryParams = $this->buildQueryParams($options);
|
||||
$endpoint = 'customers.json' . $queryParams;
|
||||
|
||||
$response = $this->sendRequest(
|
||||
method: Method::GET,
|
||||
endpoint: $endpoint
|
||||
);
|
||||
|
||||
return $this->decodeJson($response)['customers'] ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Erstellt einen neuen Kunden
|
||||
*
|
||||
* @param array $customerData Die Kundendaten
|
||||
* @return array Der erstellte Kunde
|
||||
*/
|
||||
public function createCustomer(array $customerData): array
|
||||
{
|
||||
$response = $this->sendRequest(
|
||||
method: Method::POST,
|
||||
endpoint: 'customers.json',
|
||||
data: ['customer' => $customerData]
|
||||
);
|
||||
|
||||
return $this->decodeJson($response)['customer'] ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Ruft einen einzelnen Kunden ab
|
||||
*
|
||||
* @param int $customerId Die Kunden-ID
|
||||
* @return array Die Kundendaten
|
||||
*/
|
||||
public function getCustomer(int $customerId): array
|
||||
{
|
||||
$response = $this->sendRequest(
|
||||
method: Method::GET,
|
||||
endpoint: "customers/{$customerId}.json"
|
||||
);
|
||||
|
||||
return $this->decodeJson($response)['customer'] ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Erstellt einen neuen Webhook
|
||||
*
|
||||
* @param string $topic Das Webhook-Thema (z.B. 'orders/create')
|
||||
* @param string $address Die URL, die aufgerufen werden soll
|
||||
* @param string $format Das Format (JSON oder XML)
|
||||
* @return array Die Webhook-Daten
|
||||
*/
|
||||
public function createWebhook(string $topic, string $address, string $format = 'json'): array
|
||||
{
|
||||
$response = $this->sendRequest(
|
||||
method: Method::POST,
|
||||
endpoint: 'webhooks.json',
|
||||
data: [
|
||||
'webhook' => [
|
||||
'topic' => $topic,
|
||||
'address' => $address,
|
||||
'format' => $format
|
||||
]
|
||||
]
|
||||
);
|
||||
|
||||
return $this->decodeJson($response)['webhook'] ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Ruft alle Webhooks ab
|
||||
*
|
||||
* @return array Die Liste der Webhooks
|
||||
*/
|
||||
public function getWebhooks(): array
|
||||
{
|
||||
$response = $this->sendRequest(
|
||||
method: Method::GET,
|
||||
endpoint: 'webhooks.json'
|
||||
);
|
||||
|
||||
return $this->decodeJson($response)['webhooks'] ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sucht Produkte anhand von Suchkriterien
|
||||
*
|
||||
* @param string $query Die Suchanfrage
|
||||
* @param array $options Zusätzliche Optionen
|
||||
* @return array Die gefundenen Produkte
|
||||
*/
|
||||
public function searchProducts(string $query, array $options = []): array
|
||||
{
|
||||
$options = array_merge($options, ['query' => $query]);
|
||||
$queryParams = $this->buildQueryParams($options);
|
||||
|
||||
$response = $this->sendRequest(
|
||||
method: Method::GET,
|
||||
endpoint: 'products/search.json' . $queryParams
|
||||
);
|
||||
|
||||
return $this->decodeJson($response)['products'] ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Ruft Metafields für eine Ressource ab
|
||||
*
|
||||
* @param string $resourceType Der Ressourcentyp (product, customer, usw.)
|
||||
* @param int $resourceId Die Ressourcen-ID
|
||||
* @return array Die Metafields
|
||||
*/
|
||||
public function getMetafields(string $resourceType, int $resourceId): array
|
||||
{
|
||||
$response = $this->sendRequest(
|
||||
method: Method::GET,
|
||||
endpoint: "{$resourceType}s/{$resourceId}/metafields.json"
|
||||
);
|
||||
|
||||
return $this->decodeJson($response)['metafields'] ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Verarbeitet Rate-Limiting-Informationen aus den Headern
|
||||
*
|
||||
* @param ClientResponse $response Die API-Antwort
|
||||
* @return array Rate-Limiting-Informationen
|
||||
*/
|
||||
public function getRateLimitInfo(ClientResponse $response): array
|
||||
{
|
||||
$headers = $response->headers->all();
|
||||
|
||||
return [
|
||||
'limit' => (int)($headers['X-Shopify-Shop-Api-Call-Limit'][0] ?? 0),
|
||||
'remaining' => isset($headers['X-Shopify-Shop-Api-Call-Limit'][0])
|
||||
? $this->parseRemainingCalls($headers['X-Shopify-Shop-Api-Call-Limit'][0])
|
||||
: null,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Baut Query-Parameter aus einem Options-Array
|
||||
*
|
||||
* @param array $options Die Optionen
|
||||
* @return string Die Query-Parameter als String
|
||||
*/
|
||||
private function buildQueryParams(array $options): string
|
||||
{
|
||||
if (empty($options)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return '?' . http_build_query($options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parst die verbleibenden API-Aufrufe aus dem Header
|
||||
*
|
||||
* @param string $limitHeader Der Header-Wert
|
||||
* @return int|null Die verbleibenden Aufrufe
|
||||
*/
|
||||
private function parseRemainingCalls(string $limitHeader): ?int
|
||||
{
|
||||
if (preg_match('/^(\d+)\/(\d+)$/', $limitHeader, $matches)) {
|
||||
$current = (int)$matches[1];
|
||||
$limit = (int)$matches[2];
|
||||
return $limit - $current;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user