Skip to content

Commit 1789149

Browse files
committed
feat(graphql): Collection cache keys are now segmented by private field data if those are set.
1 parent a42fe1a commit 1789149

File tree

2 files changed

+70
-19
lines changed

2 files changed

+70
-19
lines changed

src/GraphQl/Subscription/SubscriptionManager.php

Lines changed: 47 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -42,28 +42,33 @@ public function __construct(private readonly CacheItemPoolInterface $subscriptio
4242

4343
public function retrieveSubscriptionId(array $context, ?array $result, ?Operation $operation = null): ?string
4444
{
45-
/** @var ResolveInfo $info */
46-
$info = $context['info'];
47-
$fields = $info->getFieldSelection(\PHP_INT_MAX);
48-
$this->arrayRecursiveSort($fields, 'ksort');
4945
$iri = $operation ? $this->getIdentifierFromOperation($operation, $context['args'] ?? []) : $this->getIdentifierFromContext($context);
5046
if (empty($iri)) {
5147
return null;
5248
}
5349

50+
/** @var ResolveInfo $info */
51+
$info = $context['info'];
52+
$fields = $info->getFieldSelection(\PHP_INT_MAX);
53+
$this->arrayRecursiveSort($fields, 'ksort');
54+
5455
$options = $operation ? ($operation->getMercure() ?? false) : false;
5556
$private = $options['private'] ?? false;
5657
$privateFields = $options['private_fields'] ?? [];
5758
$previousObject = $context['graphql_context']['previous_object'] ?? null;
59+
$privateFieldData = [];
5860
if ($private && $privateFields && $previousObject) {
5961
foreach ($options['private_fields'] as $privateField) {
60-
$fields['__private_field_'.$privateField] = $this->getResourceId($privateField, $previousObject);
62+
$fieldData = $this->getResourceId($privateField, $previousObject);
63+
$fields['__private_field_'.$privateField] = $fieldData;
64+
$privateFieldData[] = $fieldData;
6165
}
6266
}
6367
if ($operation instanceof Subscription && $operation->isCollection()) {
6468
$subscriptionId = $this->updateSubscriptionCollectionCacheData(
6569
$iri,
6670
$fields,
71+
$privateFieldData
6772
);
6873
} else {
6974
$subscriptionId = $this->updateSubscriptionItemCacheData(
@@ -93,9 +98,15 @@ public function getPushPayloads(object $object, string $type): array
9398
/**
9499
* @return array<array>
95100
*/
96-
private function getSubscriptionsFromIri(string $iri): array
101+
private function getSubscriptionsFromIri(string $iri, array $fields = []): array
97102
{
98-
$subscriptionsCacheItem = $this->subscriptionsCache->getItem($this->encodeIriToCacheKey($iri));
103+
$subscriptionsCacheItem = $this->subscriptionsCache->getItem(
104+
$this->generatePrivateCacheKeyPart(
105+
$this->encodeIriToCacheKey($iri),
106+
$fields
107+
)
108+
109+
);
99110

100111
if ($subscriptionsCacheItem->isHit()) {
101112
return $subscriptionsCacheItem->get();
@@ -134,13 +145,6 @@ private function getCollectionIri(string $iri): string
134145

135146
private function getCreatedOrUpdatedPayloads(object $object): array
136147
{
137-
$iri = $this->iriConverter->getIriFromResource($object);
138-
// Add collection subscriptions
139-
$subscriptions = array_merge(
140-
$this->getSubscriptionsFromIri($this->getCollectionIri($iri)),
141-
$this->getSubscriptionsFromIri($iri)
142-
);
143-
144148
$resourceClass = $this->getObjectClass($object);
145149
$resourceMetadata = $this->resourceMetadataCollectionFactory->create($resourceClass);
146150
$shortName = $resourceMetadata->getOperation()->getShortName();
@@ -155,6 +159,13 @@ private function getCreatedOrUpdatedPayloads(object $object): array
155159
}
156160
}
157161

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+
158169
$payloads = [];
159170
foreach ($subscriptions as [$subscriptionId, $subscriptionFields, $subscriptionResult]) {
160171
if ($privateFieldData) {
@@ -182,12 +193,13 @@ private function getDeletePushPayloads(object $object): array
182193
$iri = $object->id;
183194
$subscriptions = array_merge(
184195
$this->getSubscriptionsFromIri($iri),
185-
$this->getSubscriptionsFromIri($this->getCollectionIri($iri))
196+
$this->getSubscriptionsFromIri($this->getCollectionIri($iri), $object->private),
186197
);
187198

188199
$payloads = [];
200+
$payload = ['type' => 'delete', 'payload' => ['id' => $object->id, 'iri' => $object->iri, 'type' => $object->type]];
189201
foreach ($subscriptions as [$subscriptionId, $subscriptionFields, $subscriptionResult]) {
190-
$payloads[] = [$subscriptionId, ['type' => 'delete', 'payload' => $object]];
202+
$payloads[] = [$subscriptionId, $payload];
191203
}
192204
$this->removeItemFromSubscriptionCache($iri);
193205

@@ -216,12 +228,14 @@ private function updateSubscriptionItemCacheData(
216228
}
217229
}
218230

219-
$subscriptionId = $this->subscriptionIdentifierGenerator->generateSubscriptionIdentifier($fields);
220231
unset($result['clientSubscriptionId']);
221232
if ($private && $privateFields && $previousObject) {
233+
$subscriptionId = $this->subscriptionIdentifierGenerator->generateSubscriptionIdentifier($fields);
222234
foreach ($privateFields as $privateField) {
223235
unset($result['__private_field_'.$privateField]);
224236
}
237+
} else {
238+
$subscriptionId = $this->subscriptionIdentifierGenerator->generateSubscriptionIdentifier($fields);
225239
}
226240
$subscriptions[] = [$subscriptionId, $fields, $result];
227241
$subscriptionsCacheItem->set($subscriptions);
@@ -232,10 +246,15 @@ private function updateSubscriptionItemCacheData(
232246

233247
private function updateSubscriptionCollectionCacheData(
234248
string $iri,
235-
array $fields,
249+
array $fields,
250+
array $privateFieldData,
236251
): string {
252+
237253
$subscriptionCollectionCacheItem = $this->subscriptionsCache->getItem(
238-
$this->encodeIriToCacheKey($this->getCollectionIri($iri)),
254+
$this->generatePrivateCacheKeyPart(
255+
$this->encodeIriToCacheKey($this->getCollectionIri($iri)),
256+
$privateFieldData
257+
),
239258
);
240259
$collectionSubscriptions = [];
241260
if ($subscriptionCollectionCacheItem->isHit()) {
@@ -253,4 +272,13 @@ private function updateSubscriptionCollectionCacheData(
253272

254273
return $subscriptionId;
255274
}
275+
276+
private function generatePrivateCacheKeyPart(string $iriKey, array $fields = []): string
277+
{
278+
if (empty($fields)) {
279+
return $iriKey;
280+
}
281+
return $iriKey.'_'.implode('_', $fields);
282+
}
283+
256284
}

src/Symfony/Doctrine/EventListener/PublishMercureUpdatesListener.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,10 +218,23 @@ private function storeObjectToPublish(object $object, string $property): void
218218
// We need to evaluate it here, because in publishUpdate() the resource would be already deleted
219219
$this->evaluateTopics($options, $object);
220220

221+
$privateData = [];
222+
$mercureOptions = $operation ? ($operation->getMercure() ?? false) : false;
223+
$private = $mercureOptions['private'] ?? false;
224+
$privateFields = $mercureOptions['private_fields'] ?? [];
225+
if ($private && $privateFields) {
226+
foreach ($privateFields as $privateField) {
227+
if (property_exists($object, $privateField)) {
228+
$privateData[$privateField] = $this->getResourceId($privateField, $object);
229+
}
230+
}
231+
}
232+
221233
$this->deletedObjects[(object) [
222234
'id' => $this->iriConverter->getIriFromResource($object),
223235
'iri' => $this->iriConverter->getIriFromResource($object, UrlGeneratorInterface::ABS_URL),
224236
'type' => 1 === \count($types) ? $types[0] : $types,
237+
'private' => $privateData,
225238
]] = $options;
226239

227240
return;
@@ -319,4 +332,14 @@ private function buildUpdate(string|array $iri, string $data, array $options): U
319332
{
320333
return new Update($iri, $data, $options['private'] ?? false, $options['id'] ?? null, $options['type'] ?? null, $options['retry'] ?? null);
321334
}
335+
336+
private function getResourceId(string $privateField, object $object): string
337+
{
338+
$id = $object->{'get'.ucfirst($privateField)}()->getId();
339+
if ($id instanceof \Stringable) {
340+
return (string) $id;
341+
}
342+
343+
return $id;
344+
}
322345
}

0 commit comments

Comments
 (0)