Skip to content

Commit cea37ca

Browse files
committed
feat(graphql): Handle multiple subscriptions per resource and issue updates to them all
1 parent 9536ec9 commit cea37ca

File tree

3 files changed

+54
-32
lines changed

3 files changed

+54
-32
lines changed

src/GraphQl/State/Processor/SubscriptionProcessor.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ public function __construct(private readonly ProcessorInterface $decorated, priv
3333
public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = [])
3434
{
3535
$data = $this->decorated->process($data, $operation, $uriVariables, $context);
36-
if (!$operation instanceof GraphQlOperation || !($mercure = $operation->getMercure())) {
36+
if (!$operation instanceof Subscription || !($mercure = $operation->getMercure())) {
3737
return $data;
3838
}
3939

src/GraphQl/Subscription/SubscriptionManager.php

Lines changed: 52 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ private function encodeIriToCacheKey(string $iri): string
131131
private function getResourceId(mixed $privateField, object $previousObject): string
132132
{
133133
$id = $previousObject->{'get'.ucfirst($privateField)}()->getId();
134-
if ($id instanceof \Stringable) {
134+
if ($id instanceof \Stringable || is_numeric($id)) {
135135
return (string) $id;
136136
}
137137

@@ -149,39 +149,61 @@ private function getCreatedOrUpdatedPayloads(object $object): array
149149
$resourceMetadata = $this->resourceMetadataCollectionFactory->create($resourceClass);
150150
$shortName = $resourceMetadata->getOperation()->getShortName();
151151

152-
$mercure = $resourceMetadata->getOperation()->getMercure() ?? false;
153-
$private = $mercure['private'] ?? false;
154-
$privateFieldsConfig = $mercure['private_fields'] ?? [];
155-
$privateFieldData = [];
156-
if ($private && $privateFieldsConfig) {
157-
foreach ($privateFieldsConfig as $privateField) {
158-
$privateFieldData['__private_field_'.$privateField] = $this->getResourceId($privateField, $object);
159-
}
160-
}
161-
162-
$iri = $this->iriConverter->getIriFromResource($object);
163-
// Add collection subscriptions
164-
$subscriptions = array_merge(
165-
$this->getSubscriptionsFromIri($this->getCollectionIri($iri), $privateFieldData),
166-
$this->getSubscriptionsFromIri($iri)
167-
);
168-
169152
$payloads = [];
170-
foreach ($subscriptions as [$subscriptionId, $subscriptionFields, $subscriptionResult]) {
171-
if ($privateFieldData) {
172-
$fieldDiff = array_intersect_assoc($subscriptionFields, $privateFieldData);
173-
if ($fieldDiff !== $privateFieldData) {
153+
foreach ($resourceMetadata as $apiResource) {
154+
foreach ($apiResource->getGraphQlOperations() as $operation) {
155+
if (!$operation instanceof Subscription) {
174156
continue;
175157
}
176-
}
177-
$resolverContext = ['fields' => $subscriptionFields, 'is_collection' => false, 'is_mutation' => false, 'is_subscription' => true];
178-
$operation = (new Subscription())->withName('mercure_subscription')->withShortName($shortName);
179-
$data = $this->normalizeProcessor->process($object, $operation, [], $resolverContext);
180-
181-
unset($data['clientSubscriptionId']);
158+
$mercure = $resourceMetadata->getOperation()->getMercure() ?? false;
159+
$operationMercure = $operation->getMercure() ?? false;
160+
if ($mercure !== false && $operationMercure !== false) {
161+
/** @noinspection SlowArrayOperationsInLoopInspection */
162+
$mercure = array_merge($mercure, $operationMercure);
163+
}
164+
$private = $mercure['private'] ?? false;
165+
$privateFieldsConfig = $mercure['private_fields'] ?? [];
166+
$privateFieldData = [];
167+
if ($private && $privateFieldsConfig) {
168+
foreach ($privateFieldsConfig as $privateField) {
169+
$privateFieldData['__private_field_' . $privateField] = $this->getResourceId(
170+
$privateField,
171+
$object
172+
);
173+
}
174+
}
182175

183-
if ($data !== $subscriptionResult) {
184-
$payloads[] = [$subscriptionId, $data];
176+
$iri = $this->iriConverter->getIriFromResource($object);
177+
// Add collection subscriptions
178+
$subscriptions = array_merge(
179+
$this->getSubscriptionsFromIri($this->getCollectionIri($iri), $privateFieldData),
180+
$this->getSubscriptionsFromIri($iri)
181+
);
182+
183+
foreach ($subscriptions as [$subscriptionId, $subscriptionFields, $subscriptionResult]) {
184+
if ($privateFieldData) {
185+
$fieldDiff = array_intersect_assoc($subscriptionFields, $privateFieldData);
186+
if ($fieldDiff !== $privateFieldData) {
187+
continue;
188+
}
189+
}
190+
$resolverContext = [
191+
'fields' => $subscriptionFields,
192+
'is_collection' => false,
193+
'is_mutation' => false,
194+
'is_subscription' => true
195+
];
196+
$subscriptionOperation = (new Subscription())->withName('mercure_subscription')->withShortName(
197+
$shortName
198+
);
199+
$data = $this->normalizeProcessor->process($object, $subscriptionOperation, [], $resolverContext);
200+
201+
unset($data['clientSubscriptionId']);
202+
203+
if ($data !== $subscriptionResult) {
204+
$payloads[] = [$subscriptionId, $data];
205+
}
206+
}
185207
}
186208
}
187209

src/Symfony/Doctrine/EventListener/PublishMercureUpdatesListener.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,7 @@ private function buildUpdate(string|array $iri, string $data, array $options): U
336336
private function getResourceId(string $privateField, object $object): string
337337
{
338338
$id = $object->{'get'.ucfirst($privateField)}()->getId();
339-
if ($id instanceof \Stringable) {
339+
if ($id instanceof \Stringable || is_numeric($id)) {
340340
return (string) $id;
341341
}
342342

0 commit comments

Comments
 (0)