From 771193019a6444f696de74d3ab90e954cb96b5e8 Mon Sep 17 00:00:00 2001 From: admirsaheta Date: Thu, 29 Aug 2024 10:50:42 +0200 Subject: [PATCH 1/5] extend:webhook-deliveries --- src/Webhooks/DeliveryMethod.php | 26 +++++++++++++++----------- src/Webhooks/Registry.php | 16 ++++++++++++---- tests/Clients/GraphqlTest.php | 7 ++++--- 3 files changed, 31 insertions(+), 18 deletions(-) diff --git a/src/Webhooks/DeliveryMethod.php b/src/Webhooks/DeliveryMethod.php index 89b3becb..ca485d8c 100644 --- a/src/Webhooks/DeliveryMethod.php +++ b/src/Webhooks/DeliveryMethod.php @@ -56,18 +56,21 @@ abstract public function parseCheckQueryResult(array $body): array; * * @return string */ - public function buildRegisterQuery( - string $topic, - string $callbackAddress, - ?string $webhookId = null - ): string { - $mutationName = $this->getMutationName($webhookId); - $identifier = $webhookId ? "id: \"$webhookId\"" : "topic: $topic"; - $webhookSubscriptionArgs = $this->queryEndpoint($callbackAddress); + public function buildRegisterQuery(string $topic, string $callbackAddress, ?string $webhookId, array $fields = [], array $metafieldNamespaces = []): string + { + $fieldsQuery = !empty($fields) ? 'fields: [' . implode(',', $fields) . ']' : ''; + $metafieldNamespacesQuery = !empty($metafieldNamespaces) ? 'metafieldNamespaces: [' . implode(',', $metafieldNamespaces) . ']' : ''; return <<isSuccess($body, $webhookId); } @@ -228,10 +232,14 @@ private static function sendRegisterRequest( string $topic, string $callbackAddress, DeliveryMethod $deliveryMethod, - ?string $webhookId + ?string $webhookId, + array $fields = [], + array $metafieldNamespaces = [] ): array { + $registerQuery = $deliveryMethod->buildRegisterQuery($topic, $callbackAddress, $webhookId, $fields, $metafieldNamespaces); + $registerResponse = $client->query( - data: $deliveryMethod->buildRegisterQuery($topic, $callbackAddress, $webhookId), + data: $registerQuery, ); $statusCode = $registerResponse->getStatusCode(); diff --git a/tests/Clients/GraphqlTest.php b/tests/Clients/GraphqlTest.php index f31b2b5f..62e6d7c4 100644 --- a/tests/Clients/GraphqlTest.php +++ b/tests/Clients/GraphqlTest.php @@ -201,11 +201,12 @@ public function testCanQueryWithExtraHeaders() public function testProxyForwardsBodyAsJsonType() { $queryToProxy = << 'hear_all_about_it']; $client = new Graphql($this->domain, 'token'); From be465e5f18bcd2736ff17df4f1528a06be268d1b Mon Sep 17 00:00:00 2001 From: admirsaheta Date: Wed, 11 Sep 2024 13:41:42 +0200 Subject: [PATCH 2/5] fix:pending-issues --- src/Webhooks/DeliveryMethod.php | 81 +++++++++++++++++++++++---------- src/Webhooks/Registry.php | 16 ++++--- 2 files changed, 66 insertions(+), 31 deletions(-) diff --git a/src/Webhooks/DeliveryMethod.php b/src/Webhooks/DeliveryMethod.php index ca485d8c..d51d0d0c 100644 --- a/src/Webhooks/DeliveryMethod.php +++ b/src/Webhooks/DeliveryMethod.php @@ -15,6 +15,9 @@ abstract public function getCallbackAddress(string $path): string; /** * Builds the mutation name to be used depending on the delivery method and webhook id. + * + * If the $webhookId is null, it is assumed that the mutation name is for creating a new subscription. + * Otherwise, it is for updating an existing subscription. * * @param string|null $webhookId * @@ -23,48 +26,77 @@ abstract public function getCallbackAddress(string $path): string; abstract protected function getMutationName(?string $webhookId): string; /** - * Assembles a GraphQL query for registering a webhook. + * Assembles the webhook subscription arguments based on the callback address. + * This allows you to customize the structure of the webhook's subscription data. * - * @param string $address + * @param string $address The callback address for the webhook. * - * @return string + * @return string GraphQL formatted string for the webhook subscription arguments. */ abstract protected function queryEndpoint(string $address): string; /** * Builds a GraphQL query to check whether this topic is already registered for the shop. + * + * This query checks for existing webhook subscriptions for a specific topic. * - * @param string $topic + * @param string $topic The topic to check. * - * @return string + * @return string GraphQL query string to check if a topic is already registered. */ abstract public function buildCheckQuery(string $topic): string; /** - * @param array $body + * Parses the result of the check query and returns the webhookId and current delivery address. + * + * This method interprets the response to extract meaningful data, like the webhook ID and its delivery address. + * + * @param array $body The response body from the GraphQL query. * - * @return array Array of the webhookId and current delivery address + * @return array Array containing the webhookId and current delivery address. */ abstract public function parseCheckQueryResult(array $body): array; /** - * Assembles a GraphQL query for registering a webhook. + * Assembles a GraphQL query for registering or updating a webhook subscription. + * + * This method now supports adding additional optional fields and metafield namespaces, + * which allows further customization of the webhook subscription. + * + * The operation (create/update) is determined by the webhookId. * - * @param string $topic - * @param string $callbackAddress - * @param string|null $webhookId + * @param string $topic The topic for the webhook subscription. + * @param string $callbackAddress The callback URL for the webhook. + * @param string|null $webhookId Optional webhook ID for updating an existing subscription. + * @param array $fields Optional fields to include in the webhook subscription. + * @param array $metafieldNamespaces Optional metafield namespaces to include. * - * @return string + * @return string The GraphQL query to register or update the webhook. */ - public function buildRegisterQuery(string $topic, string $callbackAddress, ?string $webhookId, array $fields = [], array $metafieldNamespaces = []): string - { + public function buildRegisterQuery( + string $topic, + string $callbackAddress, + ?string $webhookId = null, + array $fields = [], + array $metafieldNamespaces = [] + ): string { + // Use the mutation name based on the presence of the webhookId + $mutationName = $this->getMutationName($webhookId); + + // If updating, use the webhookId; if creating, use the topic + $identifier = $webhookId ? "id: \"$webhookId\"" : "topic: \"$topic\""; + + // Prepare optional fields and metafield namespaces $fieldsQuery = !empty($fields) ? 'fields: [' . implode(',', $fields) . ']' : ''; $metafieldNamespacesQuery = !empty($metafieldNamespaces) ? 'metafieldNamespaces: [' . implode(',', $metafieldNamespaces) . ']' : ''; + // Assemble the webhook subscription arguments + $webhookSubscriptionArgs = $this->queryEndpoint($callbackAddress); + return <<getMutationName($webhookId)]['webhookSubscription']); } -} +} \ No newline at end of file diff --git a/src/Webhooks/Registry.php b/src/Webhooks/Registry.php index e68ae1ce..8d4bb6bd 100644 --- a/src/Webhooks/Registry.php +++ b/src/Webhooks/Registry.php @@ -59,12 +59,14 @@ public static function getHandler(string $topic): ?Handler /** * Registers a new webhook for this app with Shopify. * - * @param string $path The URL path for the callback. If using EventBridge, this is the full - * resource address - * @param string $topic The topic to subscribe to. May be a string or a value from the Topics class - * @param string $shop The shop to use for requests - * @param string $accessToken The access token to use for requests - * @param string|null $deliveryMethod The delivery method for this webhook. Defaults to HTTP + * @param string $path The URL path for the callback. If using EventBridge, this is the full + * resource address + * @param string $topic The topic to subscribe to. May be a string or a value from the Topics class + * @param string $shop The shop to use for requests + * @param string $accessToken The access token to use for requests + * @param string|null $deliveryMethod The delivery method for this webhook. Defaults to HTTP + * @param array $fields The fields to request in the webhook + * @param array $metafieldNamespaces The metafield namespaces to request in the webhook * * @return RegisterResponse * @throws ClientExceptionInterface @@ -236,7 +238,7 @@ private static function sendRegisterRequest( array $fields = [], array $metafieldNamespaces = [] ): array { - $registerQuery = $deliveryMethod->buildRegisterQuery($topic, $callbackAddress, $webhookId, $fields, $metafieldNamespaces); + $registerQuery = $deliveryMethod->buildRegisterQuery($topic, $callbackAddress, $webhookId, $fields, metafieldNamespaces: $metafieldNamespaces); $registerResponse = $client->query( data: $registerQuery, From 7652b169df6c55027324995940fb2c94f0bc1e5a Mon Sep 17 00:00:00 2001 From: Mahix Date: Wed, 2 Oct 2024 12:31:30 +0200 Subject: [PATCH 3/5] extend/webhooks - Make qurey endpoint work with optinal fields and metafield namespaces --- src/Webhooks/Delivery/EventBridge.php | 2 +- src/Webhooks/Delivery/HttpDelivery.php | 2 +- src/Webhooks/Delivery/PubSub.php | 2 +- src/Webhooks/DeliveryMethod.php | 26 ++++++++++---------------- 4 files changed, 13 insertions(+), 19 deletions(-) diff --git a/src/Webhooks/Delivery/EventBridge.php b/src/Webhooks/Delivery/EventBridge.php index 37c105a1..1dedac22 100644 --- a/src/Webhooks/Delivery/EventBridge.php +++ b/src/Webhooks/Delivery/EventBridge.php @@ -83,6 +83,6 @@ protected function getMutationName(?string $webhookId): string */ protected function queryEndpoint(string $address): string { - return "{arn: \"$address\"}"; + return "arn: \"$address\""; } } diff --git a/src/Webhooks/Delivery/HttpDelivery.php b/src/Webhooks/Delivery/HttpDelivery.php index 13319f39..99406428 100644 --- a/src/Webhooks/Delivery/HttpDelivery.php +++ b/src/Webhooks/Delivery/HttpDelivery.php @@ -94,6 +94,6 @@ protected function getMutationName(?string $webhookId): string */ protected function queryEndpoint(string $address): string { - return "{callbackUrl: \"$address\"}"; + return "callbackUrl: \"$address\""; } } diff --git a/src/Webhooks/Delivery/PubSub.php b/src/Webhooks/Delivery/PubSub.php index 5cacec28..ffc350fd 100644 --- a/src/Webhooks/Delivery/PubSub.php +++ b/src/Webhooks/Delivery/PubSub.php @@ -87,6 +87,6 @@ protected function queryEndpoint(string $address): string { $addressWithoutProtocol = explode("//", $address); list($project, $topic) = explode(":", $addressWithoutProtocol[1]); - return "{pubSubProject: \"$project\", pubSubTopic: \"$topic\"}"; + return "pubSubProject: \"$project\", pubSubTopic: \"$topic\""; } } diff --git a/src/Webhooks/DeliveryMethod.php b/src/Webhooks/DeliveryMethod.php index d51d0d0c..96d9bac3 100644 --- a/src/Webhooks/DeliveryMethod.php +++ b/src/Webhooks/DeliveryMethod.php @@ -80,29 +80,23 @@ public function buildRegisterQuery( array $fields = [], array $metafieldNamespaces = [] ): string { - // Use the mutation name based on the presence of the webhookId $mutationName = $this->getMutationName($webhookId); + $identifier = $webhookId ? "id: \"$webhookId\"" : "topic: $topic"; + $webhookSubscriptionArgs = $this->queryEndpoint($callbackAddress); - // If updating, use the webhookId; if creating, use the topic - $identifier = $webhookId ? "id: \"$webhookId\"" : "topic: \"$topic\""; + $query = "$identifier, webhookSubscription: {{$webhookSubscriptionArgs}}"; - // Prepare optional fields and metafield namespaces - $fieldsQuery = !empty($fields) ? 'fields: [' . implode(',', $fields) . ']' : ''; - $metafieldNamespacesQuery = !empty($metafieldNamespaces) ? 'metafieldNamespaces: [' . implode(',', $metafieldNamespaces) . ']' : ''; + if (!empty($fields)) { + $query .= ', fields: [' . implode(',', $fields) . ']'; + } - // Assemble the webhook subscription arguments - $webhookSubscriptionArgs = $this->queryEndpoint($callbackAddress); + if (!empty($metafieldNamespaces)) { + $query .= ', metafieldNamespaces: [' . implode(',', $metafieldNamespaces) . ']'; + } return << Date: Sat, 5 Oct 2024 02:32:18 +0200 Subject: [PATCH 4/5] extend/webhook - fixed lint issues and webhook subscription optional args graphql syntax --- src/Webhooks/DeliveryMethod.php | 12 ++++-------- src/Webhooks/Registry.php | 13 ++++++++++--- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/Webhooks/DeliveryMethod.php b/src/Webhooks/DeliveryMethod.php index 96d9bac3..eb0bd581 100644 --- a/src/Webhooks/DeliveryMethod.php +++ b/src/Webhooks/DeliveryMethod.php @@ -15,7 +15,6 @@ abstract public function getCallbackAddress(string $path): string; /** * Builds the mutation name to be used depending on the delivery method and webhook id. - * * If the $webhookId is null, it is assumed that the mutation name is for creating a new subscription. * Otherwise, it is for updating an existing subscription. * @@ -37,7 +36,6 @@ abstract protected function queryEndpoint(string $address): string; /** * Builds a GraphQL query to check whether this topic is already registered for the shop. - * * This query checks for existing webhook subscriptions for a specific topic. * * @param string $topic The topic to check. @@ -48,7 +46,6 @@ abstract public function buildCheckQuery(string $topic): string; /** * Parses the result of the check query and returns the webhookId and current delivery address. - * * This method interprets the response to extract meaningful data, like the webhook ID and its delivery address. * * @param array $body The response body from the GraphQL query. @@ -59,10 +56,8 @@ abstract public function parseCheckQueryResult(array $body): array; /** * Assembles a GraphQL query for registering or updating a webhook subscription. - * * This method now supports adding additional optional fields and metafield namespaces, * which allows further customization of the webhook subscription. - * * The operation (create/update) is determined by the webhookId. * * @param string $topic The topic for the webhook subscription. @@ -84,7 +79,7 @@ public function buildRegisterQuery( $identifier = $webhookId ? "id: \"$webhookId\"" : "topic: $topic"; $webhookSubscriptionArgs = $this->queryEndpoint($callbackAddress); - $query = "$identifier, webhookSubscription: {{$webhookSubscriptionArgs}}"; + $query = "$identifier, webhookSubscription: {{$webhookSubscriptionArgs}"; if (!empty($fields)) { $query .= ', fields: [' . implode(',', $fields) . ']'; @@ -94,6 +89,8 @@ public function buildRegisterQuery( $query .= ', metafieldNamespaces: [' . implode(',', $metafieldNamespaces) . ']'; } + $query .= "}"; + return <<getMutationName($webhookId)]['webhookSubscription']); } -} \ No newline at end of file +} diff --git a/src/Webhooks/Registry.php b/src/Webhooks/Registry.php index 8d4bb6bd..fe6ff7ba 100644 --- a/src/Webhooks/Registry.php +++ b/src/Webhooks/Registry.php @@ -59,9 +59,10 @@ public static function getHandler(string $topic): ?Handler /** * Registers a new webhook for this app with Shopify. * - * @param string $path The URL path for the callback. If using EventBridge, this is the full + * @param string $path The URL path for the callback. If using EventBridge, this is the full * resource address - * @param string $topic The topic to subscribe to. May be a string or a value from the Topics class + * @param string $topic The topic to subscribe to. Can be a string or a value from + * the Topics class * @param string $shop The shop to use for requests * @param string $accessToken The access token to use for requests * @param string|null $deliveryMethod The delivery method for this webhook. Defaults to HTTP @@ -238,7 +239,13 @@ private static function sendRegisterRequest( array $fields = [], array $metafieldNamespaces = [] ): array { - $registerQuery = $deliveryMethod->buildRegisterQuery($topic, $callbackAddress, $webhookId, $fields, metafieldNamespaces: $metafieldNamespaces); + $registerQuery = $deliveryMethod->buildRegisterQuery( + $topic, + $callbackAddress, + $webhookId, + $fields, + $metafieldNamespaces + ); $registerResponse = $client->query( data: $registerQuery, From e7f0c45647caa4c93430177c060bc48f465b7300 Mon Sep 17 00:00:00 2001 From: Mahix Date: Sat, 5 Oct 2024 02:34:48 +0200 Subject: [PATCH 5/5] extend/webhooks - fixed webhook subscription optional args graphql syntax --- src/Webhooks/DeliveryMethod.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Webhooks/DeliveryMethod.php b/src/Webhooks/DeliveryMethod.php index eb0bd581..65fdf6a7 100644 --- a/src/Webhooks/DeliveryMethod.php +++ b/src/Webhooks/DeliveryMethod.php @@ -82,11 +82,11 @@ public function buildRegisterQuery( $query = "$identifier, webhookSubscription: {{$webhookSubscriptionArgs}"; if (!empty($fields)) { - $query .= ', fields: [' . implode(',', $fields) . ']'; + $query .= ' fields: [' . implode(',', $fields) . ']'; } if (!empty($metafieldNamespaces)) { - $query .= ', metafieldNamespaces: [' . implode(',', $metafieldNamespaces) . ']'; + $query .= ' metafieldNamespaces: [' . implode(',', $metafieldNamespaces) . ']'; } $query .= "}";