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; } }