Skip to content

feat(graphql): added support for graphql subscriptions to work for actions #6904

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
43 changes: 43 additions & 0 deletions src/GraphQl/Serializer/ItemNormalizer.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
use ApiPlatform\GraphQl\State\Provider\NoopProvider;
use ApiPlatform\Metadata\ApiProperty;
use ApiPlatform\Metadata\GraphQl\Query;
use ApiPlatform\Metadata\GraphQl\QueryCollection;
use ApiPlatform\Metadata\IdentifiersExtractorInterface;
use ApiPlatform\Metadata\IriConverterInterface;
use ApiPlatform\Metadata\Property\Factory\PropertyMetadataFactoryInterface;
Expand All @@ -26,6 +27,7 @@
use ApiPlatform\Metadata\Util\ClassInfoTrait;
use ApiPlatform\Serializer\CacheKeyTrait;
use ApiPlatform\Serializer\ItemNormalizer as BaseItemNormalizer;
use Doctrine\Common\Collections\Collection;
use Psr\Log\LoggerInterface;
use Psr\Log\NullLogger;
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
Expand Down Expand Up @@ -106,6 +108,11 @@
$data[self::ITEM_IDENTIFIERS_KEY] = $this->identifiersExtractor->getIdentifiersFromItem($object, $context['operation'] ?? null);
}

if (isset($context['graphql_operation_name']) && 'mercure_subscription' === $context['graphql_operation_name'] && \is_object($object) && isset($data['id']) && !isset($data['_id'])) {
$data['_id'] = $data['id'];
$data['id'] = $this->iriConverter->getIriFromResource($object);

Check warning on line 113 in src/GraphQl/Serializer/ItemNormalizer.php

View check run for this annotation

Codecov / codecov/patch

src/GraphQl/Serializer/ItemNormalizer.php#L112-L113

Added lines #L112 - L113 were not covered by tests
}

return $data;
}

Expand All @@ -120,10 +127,46 @@
return [...$attributeValue];
}

// Handle relationships for mercure subscriptions
if ($operation instanceof QueryCollection && 'mercure_subscription' === $context['graphql_operation_name'] && $attributeValue instanceof Collection && !$attributeValue->isEmpty()) {
$relationContext = $context;

Check warning on line 132 in src/GraphQl/Serializer/ItemNormalizer.php

View check run for this annotation

Codecov / codecov/patch

src/GraphQl/Serializer/ItemNormalizer.php#L131-L132

Added lines #L131 - L132 were not covered by tests
// Grab collection attributes
$relationContext['attributes'] = $context['attributes']['collection'];

Check warning on line 134 in src/GraphQl/Serializer/ItemNormalizer.php

View check run for this annotation

Codecov / codecov/patch

src/GraphQl/Serializer/ItemNormalizer.php#L134

Added line #L134 was not covered by tests
// Iterate over the collection and normalize each item
$data['collection'] = $attributeValue
->map(fn ($item) => $this->normalize($item, $format, $relationContext))
// Convert the collection to an array
->toArray();

Check warning on line 139 in src/GraphQl/Serializer/ItemNormalizer.php

View check run for this annotation

Codecov / codecov/patch

src/GraphQl/Serializer/ItemNormalizer.php#L136-L139

Added lines #L136 - L139 were not covered by tests

// Handle pagination if it's enabled in the query
return $this->addPagination($attributeValue, $data, $context);

Check warning on line 142 in src/GraphQl/Serializer/ItemNormalizer.php

View check run for this annotation

Codecov / codecov/patch

src/GraphQl/Serializer/ItemNormalizer.php#L142

Added line #L142 was not covered by tests
}

// to-many are handled directly by the GraphQL resolver
return [];
}

private function addPagination(Collection $collection, array $data, array $context): array

Check warning on line 149 in src/GraphQl/Serializer/ItemNormalizer.php

View check run for this annotation

Codecov / codecov/patch

src/GraphQl/Serializer/ItemNormalizer.php#L149

Added line #L149 was not covered by tests
{
if ($context['attributes']['paginationInfo'] ?? false) {
$data['paginationInfo'] = [];
if (\array_key_exists('hasNextPage', $context['attributes']['paginationInfo'])) {
$data['paginationInfo']['hasNextPage'] = $collection->count() > ($context['pagination']['itemsPerPage'] ?? 10);

Check warning on line 154 in src/GraphQl/Serializer/ItemNormalizer.php

View check run for this annotation

Codecov / codecov/patch

src/GraphQl/Serializer/ItemNormalizer.php#L151-L154

Added lines #L151 - L154 were not covered by tests
}
if (\array_key_exists('itemsPerPage', $context['attributes']['paginationInfo'])) {
$data['paginationInfo']['itemsPerPage'] = $context['pagination']['itemsPerPage'] ?? 10;

Check warning on line 157 in src/GraphQl/Serializer/ItemNormalizer.php

View check run for this annotation

Codecov / codecov/patch

src/GraphQl/Serializer/ItemNormalizer.php#L156-L157

Added lines #L156 - L157 were not covered by tests
}
if (\array_key_exists('lastPage', $context['attributes']['paginationInfo'])) {
$data['paginationInfo']['lastPage'] = (int) ceil($collection->count() / ($context['pagination']['itemsPerPage'] ?? 10));

Check warning on line 160 in src/GraphQl/Serializer/ItemNormalizer.php

View check run for this annotation

Codecov / codecov/patch

src/GraphQl/Serializer/ItemNormalizer.php#L159-L160

Added lines #L159 - L160 were not covered by tests
}
if (\array_key_exists('totalCount', $context['attributes']['paginationInfo'])) {
$data['paginationInfo']['totalCount'] = $collection->count();

Check warning on line 163 in src/GraphQl/Serializer/ItemNormalizer.php

View check run for this annotation

Codecov / codecov/patch

src/GraphQl/Serializer/ItemNormalizer.php#L162-L163

Added lines #L162 - L163 were not covered by tests
}
}

return $data;

Check warning on line 167 in src/GraphQl/Serializer/ItemNormalizer.php

View check run for this annotation

Codecov / codecov/patch

src/GraphQl/Serializer/ItemNormalizer.php#L167

Added line #L167 was not covered by tests
}

/**
* {@inheritdoc}
*/
Expand Down
4 changes: 4 additions & 0 deletions src/GraphQl/State/Processor/SubscriptionProcessor.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
use ApiPlatform\GraphQl\Subscription\OperationAwareSubscriptionManagerInterface;
use ApiPlatform\GraphQl\Subscription\SubscriptionManagerInterface;
use ApiPlatform\Metadata\GraphQl\Operation as GraphQlOperation;
use ApiPlatform\Metadata\GraphQl\Subscription;
use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProcessorInterface;

Expand Down Expand Up @@ -49,6 +50,9 @@

$hub = \is_array($mercure) ? ($mercure['hub'] ?? null) : null;
$data['mercureUrl'] = $this->mercureSubscriptionIriGenerator->generateMercureUrl($subscriptionId, $hub);
if ($operation instanceof Subscription) {
$data['isCollection'] = $operation->isCollection();

Check warning on line 54 in src/GraphQl/State/Processor/SubscriptionProcessor.php

View check run for this annotation

Codecov / codecov/patch

src/GraphQl/State/Processor/SubscriptionProcessor.php#L53-L54

Added lines #L53 - L54 were not covered by tests
}
}

return $data;
Expand Down
14 changes: 14 additions & 0 deletions src/GraphQl/Subscription/SubscriptionIdentifierGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,21 @@
public function generateSubscriptionIdentifier(array $fields): string
{
unset($fields['mercureUrl'], $fields['clientSubscriptionId']);
$fields = $this->removeTypename($fields);

Check warning on line 26 in src/GraphQl/Subscription/SubscriptionIdentifierGenerator.php

View check run for this annotation

Codecov / codecov/patch

src/GraphQl/Subscription/SubscriptionIdentifierGenerator.php#L26

Added line #L26 was not covered by tests
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is this needed?

Copy link
Contributor Author

@psihius psihius Jan 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When executing a subscription GraphQL query, the __typename key is not present in fields in the SubscriptionProcessor, but when you get fields in doctrine subscriber to publish updates, the __typename is present in the fields. That results in different sha256 hashes as subscription id, which breaks publishing.


return hash('sha256', print_r($fields, true));
}

private function removeTypename(array $data): array

Check warning on line 31 in src/GraphQl/Subscription/SubscriptionIdentifierGenerator.php

View check run for this annotation

Codecov / codecov/patch

src/GraphQl/Subscription/SubscriptionIdentifierGenerator.php#L31

Added line #L31 was not covered by tests
{
foreach ($data as $key => $value) {
if ('__typename' === $key) {
unset($data[$key]);
} elseif (\is_array($value)) {
$data[$key] = $this->removeTypename($value);

Check warning on line 37 in src/GraphQl/Subscription/SubscriptionIdentifierGenerator.php

View check run for this annotation

Codecov / codecov/patch

src/GraphQl/Subscription/SubscriptionIdentifierGenerator.php#L33-L37

Added lines #L33 - L37 were not covered by tests
}
}

return $data;

Check warning on line 41 in src/GraphQl/Subscription/SubscriptionIdentifierGenerator.php

View check run for this annotation

Codecov / codecov/patch

src/GraphQl/Subscription/SubscriptionIdentifierGenerator.php#L41

Added line #L41 was not covered by tests
}
}
229 changes: 198 additions & 31 deletions src/GraphQl/Subscription/SubscriptionManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,48 +42,140 @@

public function retrieveSubscriptionId(array $context, ?array $result, ?Operation $operation = null): ?string
{
$iri = $operation ? $this->getIdentifierFromOperation($operation, $context['args'] ?? []) : $this->getIdentifierFromContext($context);
if (empty($iri)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's avoid a function call here if this can return an empty array we should fix the return type of the above functions.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It also returns an empty string if you provide a value, but it's not a valid URI. That's why I made empty call instead of doing null === $iri || '' === $iri || [] === $iri.
Those 2 methods called above are part of a IdentifierTrait trait, means all call sides will need modification.

return null;

Check warning on line 47 in src/GraphQl/Subscription/SubscriptionManager.php

View check run for this annotation

Codecov / codecov/patch

src/GraphQl/Subscription/SubscriptionManager.php#L45-L47

Added lines #L45 - L47 were not covered by tests
}

/** @var ResolveInfo $info */
$info = $context['info'];
$fields = $info->getFieldSelection(\PHP_INT_MAX);
$this->arrayRecursiveSort($fields, 'ksort');
$iri = $operation ? $this->getIdentifierFromOperation($operation, $context['args'] ?? []) : $this->getIdentifierFromContext($context);
if (null === $iri) {
return null;

$options = $operation ? ($operation->getMercure() ?? false) : false;
$private = $options['private'] ?? false;
$privateFields = $options['private_fields'] ?? [];
$previousObject = $context['graphql_context']['previous_object'] ?? null;
$privateFieldData = [];
if ($private && $privateFields && $previousObject) {
foreach ($options['private_fields'] as $privateField) {
$fieldData = $this->getResourceId($privateField, $previousObject);
$fields['__private_field_'.$privateField] = $fieldData;
$privateFieldData[] = $fieldData;

Check warning on line 64 in src/GraphQl/Subscription/SubscriptionManager.php

View check run for this annotation

Codecov / codecov/patch

src/GraphQl/Subscription/SubscriptionManager.php#L55-L64

Added lines #L55 - L64 were not covered by tests
}
}
$subscriptionsCacheItem = $this->subscriptionsCache->getItem($this->encodeIriToCacheKey($iri));
$subscriptions = [];
if ($operation instanceof Subscription && $operation->isCollection()) {
$subscriptionId = $this->updateSubscriptionCollectionCacheData(
$iri,
$fields,
$privateFieldData
);

Check warning on line 72 in src/GraphQl/Subscription/SubscriptionManager.php

View check run for this annotation

Codecov / codecov/patch

src/GraphQl/Subscription/SubscriptionManager.php#L67-L72

Added lines #L67 - L72 were not covered by tests
} else {
$subscriptionId = $this->updateSubscriptionItemCacheData(
$iri,
$fields,
$result,
$private,
$privateFields,
$previousObject
);

Check warning on line 81 in src/GraphQl/Subscription/SubscriptionManager.php

View check run for this annotation

Codecov / codecov/patch

src/GraphQl/Subscription/SubscriptionManager.php#L74-L81

Added lines #L74 - L81 were not covered by tests
}

return $subscriptionId;

Check warning on line 84 in src/GraphQl/Subscription/SubscriptionManager.php

View check run for this annotation

Codecov / codecov/patch

src/GraphQl/Subscription/SubscriptionManager.php#L84

Added line #L84 was not covered by tests
}

public function getPushPayloads(object $object, string $type): array

Check warning on line 87 in src/GraphQl/Subscription/SubscriptionManager.php

View check run for this annotation

Codecov / codecov/patch

src/GraphQl/Subscription/SubscriptionManager.php#L87

Added line #L87 was not covered by tests
{
if ('delete' === $type) {
$payloads = $this->getDeletePushPayloads($object);

Check warning on line 90 in src/GraphQl/Subscription/SubscriptionManager.php

View check run for this annotation

Codecov / codecov/patch

src/GraphQl/Subscription/SubscriptionManager.php#L89-L90

Added lines #L89 - L90 were not covered by tests
} else {
$payloads = $this->getCreatedOrUpdatedPayloads($object);

Check warning on line 92 in src/GraphQl/Subscription/SubscriptionManager.php

View check run for this annotation

Codecov / codecov/patch

src/GraphQl/Subscription/SubscriptionManager.php#L92

Added line #L92 was not covered by tests
}

return $payloads;

Check warning on line 95 in src/GraphQl/Subscription/SubscriptionManager.php

View check run for this annotation

Codecov / codecov/patch

src/GraphQl/Subscription/SubscriptionManager.php#L95

Added line #L95 was not covered by tests
}

/**
* @return array<array>
*/
private function getSubscriptionsFromIri(string $iri, array $fields = []): array

Check warning on line 101 in src/GraphQl/Subscription/SubscriptionManager.php

View check run for this annotation

Codecov / codecov/patch

src/GraphQl/Subscription/SubscriptionManager.php#L101

Added line #L101 was not covered by tests
{
$subscriptionsCacheItem = $this->subscriptionsCache->getItem(
$this->generatePrivateCacheKeyPart(
$this->encodeIriToCacheKey($iri),
$fields
)

Check warning on line 107 in src/GraphQl/Subscription/SubscriptionManager.php

View check run for this annotation

Codecov / codecov/patch

src/GraphQl/Subscription/SubscriptionManager.php#L103-L107

Added lines #L103 - L107 were not covered by tests

);

Check warning on line 109 in src/GraphQl/Subscription/SubscriptionManager.php

View check run for this annotation

Codecov / codecov/patch

src/GraphQl/Subscription/SubscriptionManager.php#L109

Added line #L109 was not covered by tests

if ($subscriptionsCacheItem->isHit()) {
$subscriptions = $subscriptionsCacheItem->get();
foreach ($subscriptions as [$subscriptionId, $subscriptionFields, $subscriptionResult]) {
if ($subscriptionFields === $fields) {
return $subscriptionId;
}
}
return $subscriptionsCacheItem->get();

Check warning on line 112 in src/GraphQl/Subscription/SubscriptionManager.php

View check run for this annotation

Codecov / codecov/patch

src/GraphQl/Subscription/SubscriptionManager.php#L112

Added line #L112 was not covered by tests
}

$subscriptionId = $this->subscriptionIdentifierGenerator->generateSubscriptionIdentifier($fields);
unset($result['clientSubscriptionId']);
$subscriptions[] = [$subscriptionId, $fields, $result];
$subscriptionsCacheItem->set($subscriptions);
$this->subscriptionsCache->save($subscriptionsCacheItem);
return [];

Check warning on line 115 in src/GraphQl/Subscription/SubscriptionManager.php

View check run for this annotation

Codecov / codecov/patch

src/GraphQl/Subscription/SubscriptionManager.php#L115

Added line #L115 was not covered by tests
}

return $subscriptionId;
private function removeItemFromSubscriptionCache(string $iri): void

Check warning on line 118 in src/GraphQl/Subscription/SubscriptionManager.php

View check run for this annotation

Codecov / codecov/patch

src/GraphQl/Subscription/SubscriptionManager.php#L118

Added line #L118 was not covered by tests
{
$cacheKey = $this->encodeIriToCacheKey($iri);
if ($this->subscriptionsCache->hasItem($cacheKey)) {
$this->subscriptionsCache->deleteItem($cacheKey);

Check warning on line 122 in src/GraphQl/Subscription/SubscriptionManager.php

View check run for this annotation

Codecov / codecov/patch

src/GraphQl/Subscription/SubscriptionManager.php#L120-L122

Added lines #L120 - L122 were not covered by tests
}
}

public function getPushPayloads(object $object): array
private function encodeIriToCacheKey(string $iri): string

Check warning on line 126 in src/GraphQl/Subscription/SubscriptionManager.php

View check run for this annotation

Codecov / codecov/patch

src/GraphQl/Subscription/SubscriptionManager.php#L126

Added line #L126 was not covered by tests
{
$iri = $this->iriConverter->getIriFromResource($object);
$subscriptions = $this->getSubscriptionsFromIri($iri);
return str_replace('/', '_', $iri);

Check warning on line 128 in src/GraphQl/Subscription/SubscriptionManager.php

View check run for this annotation

Codecov / codecov/patch

src/GraphQl/Subscription/SubscriptionManager.php#L128

Added line #L128 was not covered by tests
}

private function getResourceId(mixed $privateField, object $previousObject): string

Check warning on line 131 in src/GraphQl/Subscription/SubscriptionManager.php

View check run for this annotation

Codecov / codecov/patch

src/GraphQl/Subscription/SubscriptionManager.php#L131

Added line #L131 was not covered by tests
{
$id = $previousObject->{'get'.ucfirst($privateField)}()->getId();
if ($id instanceof \Stringable) {
return (string) $id;

Check warning on line 135 in src/GraphQl/Subscription/SubscriptionManager.php

View check run for this annotation

Codecov / codecov/patch

src/GraphQl/Subscription/SubscriptionManager.php#L133-L135

Added lines #L133 - L135 were not covered by tests
}

return $id;

Check warning on line 138 in src/GraphQl/Subscription/SubscriptionManager.php

View check run for this annotation

Codecov / codecov/patch

src/GraphQl/Subscription/SubscriptionManager.php#L138

Added line #L138 was not covered by tests
}

private function getCollectionIri(string $iri): string

Check warning on line 141 in src/GraphQl/Subscription/SubscriptionManager.php

View check run for this annotation

Codecov / codecov/patch

src/GraphQl/Subscription/SubscriptionManager.php#L141

Added line #L141 was not covered by tests
{
return substr($iri, 0, strrpos($iri, '/'));

Check warning on line 143 in src/GraphQl/Subscription/SubscriptionManager.php

View check run for this annotation

Codecov / codecov/patch

src/GraphQl/Subscription/SubscriptionManager.php#L143

Added line #L143 was not covered by tests
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is too hackish we need to find a better way.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm all ears, I haven't found one :)


private function getCreatedOrUpdatedPayloads(object $object): array

Check warning on line 146 in src/GraphQl/Subscription/SubscriptionManager.php

View check run for this annotation

Codecov / codecov/patch

src/GraphQl/Subscription/SubscriptionManager.php#L146

Added line #L146 was not covered by tests
{
$resourceClass = $this->getObjectClass($object);
$resourceMetadata = $this->resourceMetadataCollectionFactory->create($resourceClass);
$shortName = $resourceMetadata->getOperation()->getShortName();

$mercure = $resourceMetadata->getOperation()->getMercure() ?? false;
$private = $mercure['private'] ?? false;
$privateFieldsConfig = $mercure['private_fields'] ?? [];
$privateFieldData = [];
if ($private && $privateFieldsConfig) {
foreach ($privateFieldsConfig as $privateField) {
$privateFieldData['__private_field_'.$privateField] = $this->getResourceId($privateField, $object);

Check warning on line 158 in src/GraphQl/Subscription/SubscriptionManager.php

View check run for this annotation

Codecov / codecov/patch

src/GraphQl/Subscription/SubscriptionManager.php#L152-L158

Added lines #L152 - L158 were not covered by tests
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've seen this logic twice, could you use a function to remove a few lines?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A Trait then? This logic is used in 2 different files.


$iri = $this->iriConverter->getIriFromResource($object);

Check warning on line 162 in src/GraphQl/Subscription/SubscriptionManager.php

View check run for this annotation

Codecov / codecov/patch

src/GraphQl/Subscription/SubscriptionManager.php#L162

Added line #L162 was not covered by tests
// Add collection subscriptions
$subscriptions = array_merge(
$this->getSubscriptionsFromIri($this->getCollectionIri($iri), $privateFieldData),
$this->getSubscriptionsFromIri($iri)
);

Check warning on line 167 in src/GraphQl/Subscription/SubscriptionManager.php

View check run for this annotation

Codecov / codecov/patch

src/GraphQl/Subscription/SubscriptionManager.php#L164-L167

Added lines #L164 - L167 were not covered by tests

$payloads = [];
foreach ($subscriptions as [$subscriptionId, $subscriptionFields, $subscriptionResult]) {
if ($privateFieldData) {
$fieldDiff = array_intersect_assoc($subscriptionFields, $privateFieldData);
if ($fieldDiff !== $privateFieldData) {
continue;

Check warning on line 174 in src/GraphQl/Subscription/SubscriptionManager.php

View check run for this annotation

Codecov / codecov/patch

src/GraphQl/Subscription/SubscriptionManager.php#L171-L174

Added lines #L171 - L174 were not covered by tests
}
}
$resolverContext = ['fields' => $subscriptionFields, 'is_collection' => false, 'is_mutation' => false, 'is_subscription' => true];
/** @var Operation */
$operation = (new Subscription())->withName('update_subscription')->withShortName($shortName);
$operation = (new Subscription())->withName('mercure_subscription')->withShortName($shortName);

Check warning on line 178 in src/GraphQl/Subscription/SubscriptionManager.php

View check run for this annotation

Codecov / codecov/patch

src/GraphQl/Subscription/SubscriptionManager.php#L178

Added line #L178 was not covered by tests
$data = $this->normalizeProcessor->process($object, $operation, [], $resolverContext);

unset($data['clientSubscriptionId']);
Expand All @@ -96,22 +188,97 @@
return $payloads;
}

/**
* @return array<array>
*/
private function getSubscriptionsFromIri(string $iri): array
private function getDeletePushPayloads(object $object): array

Check warning on line 191 in src/GraphQl/Subscription/SubscriptionManager.php

View check run for this annotation

Codecov / codecov/patch

src/GraphQl/Subscription/SubscriptionManager.php#L191

Added line #L191 was not covered by tests
{
$subscriptionsCacheItem = $this->subscriptionsCache->getItem($this->encodeIriToCacheKey($iri));
$iri = $object->id;
$subscriptions = array_merge(
$this->getSubscriptionsFromIri($iri),
$this->getSubscriptionsFromIri($this->getCollectionIri($iri), $object->private),
);

Check warning on line 197 in src/GraphQl/Subscription/SubscriptionManager.php

View check run for this annotation

Codecov / codecov/patch

src/GraphQl/Subscription/SubscriptionManager.php#L193-L197

Added lines #L193 - L197 were not covered by tests

$payloads = [];
$payload = ['type' => 'delete', 'payload' => ['id' => $object->id, 'iri' => $object->iri, 'type' => $object->type]];
foreach ($subscriptions as [$subscriptionId, $subscriptionFields, $subscriptionResult]) {
$payloads[] = [$subscriptionId, $payload];

Check warning on line 202 in src/GraphQl/Subscription/SubscriptionManager.php

View check run for this annotation

Codecov / codecov/patch

src/GraphQl/Subscription/SubscriptionManager.php#L199-L202

Added lines #L199 - L202 were not covered by tests
}
$this->removeItemFromSubscriptionCache($iri);

Check warning on line 204 in src/GraphQl/Subscription/SubscriptionManager.php

View check run for this annotation

Codecov / codecov/patch

src/GraphQl/Subscription/SubscriptionManager.php#L204

Added line #L204 was not covered by tests

return $payloads;

Check warning on line 206 in src/GraphQl/Subscription/SubscriptionManager.php

View check run for this annotation

Codecov / codecov/patch

src/GraphQl/Subscription/SubscriptionManager.php#L206

Added line #L206 was not covered by tests
}

private function updateSubscriptionItemCacheData(

Check warning on line 209 in src/GraphQl/Subscription/SubscriptionManager.php

View check run for this annotation

Codecov / codecov/patch

src/GraphQl/Subscription/SubscriptionManager.php#L209

Added line #L209 was not covered by tests
string $iri,
array $fields,
?array $result,
bool $private,
array $privateFields,
?object $previousObject,
): string {
$subscriptionsCacheItem = $this->subscriptionsCache->getItem($this->encodeIriToCacheKey($iri));
$subscriptions = [];

Check warning on line 218 in src/GraphQl/Subscription/SubscriptionManager.php

View check run for this annotation

Codecov / codecov/patch

src/GraphQl/Subscription/SubscriptionManager.php#L217-L218

Added lines #L217 - L218 were not covered by tests
if ($subscriptionsCacheItem->isHit()) {
return $subscriptionsCacheItem->get();
/*
* @var array<array{string, array<string, string|array>, array<string, string|array>}>
*/
$subscriptions = $subscriptionsCacheItem->get();
foreach ($subscriptions as [$subscriptionId, $subscriptionFields, $subscriptionResult]) {
if ($subscriptionFields === $fields) {
return $subscriptionId;

Check warning on line 226 in src/GraphQl/Subscription/SubscriptionManager.php

View check run for this annotation

Codecov / codecov/patch

src/GraphQl/Subscription/SubscriptionManager.php#L223-L226

Added lines #L223 - L226 were not covered by tests
}
}
}

return [];
unset($result['clientSubscriptionId']);
if ($private && $privateFields && $previousObject) {
$subscriptionId = $this->subscriptionIdentifierGenerator->generateSubscriptionIdentifier($fields);
foreach ($privateFields as $privateField) {
unset($result['__private_field_'.$privateField]);

Check warning on line 235 in src/GraphQl/Subscription/SubscriptionManager.php

View check run for this annotation

Codecov / codecov/patch

src/GraphQl/Subscription/SubscriptionManager.php#L231-L235

Added lines #L231 - L235 were not covered by tests
}
} else {
$subscriptionId = $this->subscriptionIdentifierGenerator->generateSubscriptionIdentifier($fields);

Check warning on line 238 in src/GraphQl/Subscription/SubscriptionManager.php

View check run for this annotation

Codecov / codecov/patch

src/GraphQl/Subscription/SubscriptionManager.php#L238

Added line #L238 was not covered by tests
}
$subscriptions[] = [$subscriptionId, $fields, $result];
$subscriptionsCacheItem->set($subscriptions);
$this->subscriptionsCache->save($subscriptionsCacheItem);

Check warning on line 242 in src/GraphQl/Subscription/SubscriptionManager.php

View check run for this annotation

Codecov / codecov/patch

src/GraphQl/Subscription/SubscriptionManager.php#L240-L242

Added lines #L240 - L242 were not covered by tests

return $subscriptionId;

Check warning on line 244 in src/GraphQl/Subscription/SubscriptionManager.php

View check run for this annotation

Codecov / codecov/patch

src/GraphQl/Subscription/SubscriptionManager.php#L244

Added line #L244 was not covered by tests
}

private function encodeIriToCacheKey(string $iri): string
private function updateSubscriptionCollectionCacheData(

Check warning on line 247 in src/GraphQl/Subscription/SubscriptionManager.php

View check run for this annotation

Codecov / codecov/patch

src/GraphQl/Subscription/SubscriptionManager.php#L247

Added line #L247 was not covered by tests
string $iri,
array $fields,
array $privateFieldData,
): string {

$subscriptionCollectionCacheItem = $this->subscriptionsCache->getItem(
$this->generatePrivateCacheKeyPart(
$this->encodeIriToCacheKey($this->getCollectionIri($iri)),
$privateFieldData
),
);
$collectionSubscriptions = [];
if ($subscriptionCollectionCacheItem->isHit()) {
$collectionSubscriptions = $subscriptionCollectionCacheItem->get();
foreach ($collectionSubscriptions as [$subscriptionId, $subscriptionFields, $result]) {
if ($subscriptionFields === $fields) {
return $subscriptionId;

Check warning on line 264 in src/GraphQl/Subscription/SubscriptionManager.php

View check run for this annotation

Codecov / codecov/patch

src/GraphQl/Subscription/SubscriptionManager.php#L253-L264

Added lines #L253 - L264 were not covered by tests
}
}
}
$subscriptionId = $this->subscriptionIdentifierGenerator->generateSubscriptionIdentifier($fields + ['__collection' => true]);
$collectionSubscriptions[] = [$subscriptionId, $fields, []];
$subscriptionCollectionCacheItem->set($collectionSubscriptions);
$this->subscriptionsCache->save($subscriptionCollectionCacheItem);

Check warning on line 271 in src/GraphQl/Subscription/SubscriptionManager.php

View check run for this annotation

Codecov / codecov/patch

src/GraphQl/Subscription/SubscriptionManager.php#L268-L271

Added lines #L268 - L271 were not covered by tests

return $subscriptionId;

Check warning on line 273 in src/GraphQl/Subscription/SubscriptionManager.php

View check run for this annotation

Codecov / codecov/patch

src/GraphQl/Subscription/SubscriptionManager.php#L273

Added line #L273 was not covered by tests
}

private function generatePrivateCacheKeyPart(string $iriKey, array $fields = []): string

Check warning on line 276 in src/GraphQl/Subscription/SubscriptionManager.php

View check run for this annotation

Codecov / codecov/patch

src/GraphQl/Subscription/SubscriptionManager.php#L276

Added line #L276 was not covered by tests
{
return str_replace('/', '_', $iri);
if (empty($fields)) {
return $iriKey;

Check warning on line 279 in src/GraphQl/Subscription/SubscriptionManager.php

View check run for this annotation

Codecov / codecov/patch

src/GraphQl/Subscription/SubscriptionManager.php#L278-L279

Added lines #L278 - L279 were not covered by tests
}
return $iriKey.'_'.implode('_', $fields);

Check warning on line 281 in src/GraphQl/Subscription/SubscriptionManager.php

View check run for this annotation

Codecov / codecov/patch

src/GraphQl/Subscription/SubscriptionManager.php#L281

Added line #L281 was not covered by tests
}

}
2 changes: 1 addition & 1 deletion src/GraphQl/Subscription/SubscriptionManagerInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,5 @@ interface SubscriptionManagerInterface
{
public function retrieveSubscriptionId(array $context, ?array $result): ?string;

public function getPushPayloads(object $object): array;
public function getPushPayloads(object $object, string $type): array;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is a public interface, the added argument should be optional to cover the BC layer

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok

}
Loading
Loading