@@ -42,14 +42,24 @@ public function __construct(private readonly CacheItemPoolInterface $subscriptio
4242
4343 public function retrieveSubscriptionId (array $ context , ?array $ result , ?Operation $ operation = null ): ?string
4444 {
45+
4546 /** @var ResolveInfo $info */
4647 $ info = $ context ['info ' ];
4748 $ fields = $ info ->getFieldSelection (\PHP_INT_MAX );
4849 $ this ->arrayRecursiveSort ($ fields , 'ksort ' );
4950 $ iri = $ operation ? $ this ->getIdentifierFromOperation ($ operation , $ context ['args ' ] ?? []) : $ this ->getIdentifierFromContext ($ context );
50- if (null === $ iri ) {
51+ if (empty ( $ iri) ) {
5152 return null ;
5253 }
54+ $ options = $ operation ->getMercure () ?? false ;
55+ $ private = $ options ['private ' ] ?? false ;
56+ $ privateFields = $ options ['private_fields ' ] ?? [];
57+ $ previousObject = $ context ['graphql_context ' ]['previous_object ' ] ?? null ;
58+ if ($ private && $ privateFields && $ previousObject ) {
59+ foreach ($ options ['private_fields ' ] as $ privateField ) {
60+ $ fields ['__private_field_ ' .$ privateField ] = $ this ->getResourceId ($ privateField , $ previousObject );
61+ }
62+ }
5363 $ subscriptionsCacheItem = $ this ->subscriptionsCache ->getItem ($ this ->encodeIriToCacheKey ($ iri ));
5464 $ subscriptions = [];
5565 if ($ subscriptionsCacheItem ->isHit ()) {
@@ -63,26 +73,129 @@ public function retrieveSubscriptionId(array $context, ?array $result, ?Operatio
6373
6474 $ subscriptionId = $ this ->subscriptionIdentifierGenerator ->generateSubscriptionIdentifier ($ fields );
6575 unset($ result ['clientSubscriptionId ' ]);
76+ if ($ private && $ privateFields && $ previousObject ) {
77+ foreach ($ options ['private_fields ' ] as $ privateField ) {
78+ unset($ result ['__private_field_ ' .$ privateField ]);
79+ }
80+ }
6681 $ subscriptions [] = [$ subscriptionId , $ fields , $ result ];
6782 $ subscriptionsCacheItem ->set ($ subscriptions );
6883 $ this ->subscriptionsCache ->save ($ subscriptionsCacheItem );
6984
85+ $ this ->updateSubscriptionCollectionCacheData (
86+ $ iri ,
87+ $ fields ,
88+ $ subscriptions ,
89+ );
90+
7091 return $ subscriptionId ;
7192 }
7293
73- public function getPushPayloads (object $ object ): array
94+ public function getPushPayloads (object $ object , string $ type ): array
95+ {
96+ if ('delete ' === $ type ) {
97+ $ payloads = $ this ->getDeletePushPayloads ($ object );
98+ } else {
99+ $ payloads = $ this ->getCreatedOrUpdatedPayloads ($ object );
100+ }
101+
102+ return $ payloads ;
103+ }
104+
105+ /**
106+ * @return array<array>
107+ */
108+ private function getSubscriptionsFromIri (string $ iri ): array
109+ {
110+ $ subscriptionsCacheItem = $ this ->subscriptionsCache ->getItem ($ this ->encodeIriToCacheKey ($ iri ));
111+
112+ if ($ subscriptionsCacheItem ->isHit ()) {
113+ return $ subscriptionsCacheItem ->get ();
114+ }
115+
116+ return [];
117+ }
118+
119+ private function removeItemFromSubscriptionCache (string $ iri ): void
120+ {
121+ $ cacheKey = $ this ->encodeIriToCacheKey ($ iri );
122+ if ($ this ->subscriptionsCache ->hasItem ($ cacheKey )) {
123+ $ this ->subscriptionsCache ->deleteItem ($ cacheKey );
124+ }
125+ }
126+
127+ private function encodeIriToCacheKey (string $ iri ): string
128+ {
129+ return str_replace ('/ ' , '_ ' , $ iri );
130+ }
131+
132+ private function updateSubscriptionCollectionCacheData (
133+ ?string $ iri ,
134+ array $ fields ,
135+ array $ subscriptions ,
136+ ): void
137+ {
138+ $ subscriptionCollectionCacheItem = $ this ->subscriptionsCache ->getItem (
139+ $ this ->encodeIriToCacheKey ($ this ->getCollectionIri ($ iri )),
140+ );
141+ if ($ subscriptionCollectionCacheItem ->isHit ()) {
142+ $ collectionSubscriptions = $ subscriptionCollectionCacheItem ->get ();
143+ foreach ($ collectionSubscriptions as [$ subscriptionId , $ subscriptionFields , $ subscriptionResult ]) {
144+ if ($ subscriptionFields === $ fields ) {
145+ return ;
146+ }
147+ }
148+ }
149+ $ subscriptionCollectionCacheItem ->set ($ subscriptions );
150+ $ this ->subscriptionsCache ->save ($ subscriptionCollectionCacheItem );
151+ }
152+
153+ private function getResourceId (mixed $ privateField , object $ previousObject ): string
154+ {
155+ $ id = $ previousObject ->{'get ' . ucfirst ($ privateField )}()->getId ();
156+ if ($ id instanceof \Stringable) {
157+ return (string )$ id ;
158+ }
159+ return $ id ;
160+ }
161+
162+ private function getCollectionIri (string $ iri ): string
163+ {
164+ return substr ($ iri , 0 , strrpos ($ iri , '/ ' ));
165+ }
166+
167+ private function getCreatedOrUpdatedPayloads (object $ object ): array
74168 {
75169 $ iri = $ this ->iriConverter ->getIriFromResource ($ object );
76170 $ subscriptions = $ this ->getSubscriptionsFromIri ($ iri );
171+ if ($ subscriptions === []) {
172+ // Get subscriptions from collection Iri
173+ $ subscriptions = $ this ->getSubscriptionsFromIri ($ this ->getCollectionIri ($ iri ));
174+ }
77175
78176 $ resourceClass = $ this ->getObjectClass ($ object );
79177 $ resourceMetadata = $ this ->resourceMetadataCollectionFactory ->create ($ resourceClass );
80178 $ shortName = $ resourceMetadata ->getOperation ()->getShortName ();
81179
180+ $ mercure = $ resourceMetadata ->getOperation ()->getMercure () ?? false ;
181+ $ private = $ mercure ['private ' ] ?? false ;
182+ $ privateFieldsConfig = $ mercure ['private_fields ' ] ?? [];
183+ $ privateFieldData = [];
184+ if ($ private && $ privateFieldsConfig ) {
185+ foreach ($ privateFieldsConfig as $ privateField ) {
186+ $ privateFieldData ['__private_field_ ' .$ privateField ] = $ this ->getResourceId ($ privateField , $ object );
187+ }
188+ }
189+
82190 $ payloads = [];
83191 foreach ($ subscriptions as [$ subscriptionId , $ subscriptionFields , $ subscriptionResult ]) {
192+ if ($ privateFieldData ) {
193+ $ fieldDiff = array_intersect_assoc ($ subscriptionFields , $ privateFieldData );
194+ if ($ fieldDiff !== $ privateFieldData ) {
195+ continue ;
196+ }
197+ }
84198 $ resolverContext = ['fields ' => $ subscriptionFields , 'is_collection ' => false , 'is_mutation ' => false , 'is_subscription ' => true ];
85- /** @var Operation */
86199 $ operation = (new Subscription ())->withName ('update_subscription ' )->withShortName ($ shortName );
87200 $ data = $ this ->normalizeProcessor ->process ($ object , $ operation , [], $ resolverContext );
88201
@@ -92,26 +205,24 @@ public function getPushPayloads(object $object): array
92205 $ payloads [] = [$ subscriptionId , $ data ];
93206 }
94207 }
95-
96208 return $ payloads ;
97209 }
98210
99- /**
100- * @return array<array>
101- */
102- private function getSubscriptionsFromIri (string $ iri ): array
211+ private function getDeletePushPayloads (object $ object ): array
103212 {
104- $ subscriptionsCacheItem = $ this ->subscriptionsCache ->getItem ($ this ->encodeIriToCacheKey ($ iri ));
105-
106- if ($ subscriptionsCacheItem ->isHit ()) {
107- return $ subscriptionsCacheItem ->get ();
213+ $ iri = $ object ->id ;
214+ $ subscriptions = $ this ->getSubscriptionsFromIri ($ iri );
215+ if ($ subscriptions === []) {
216+ // Get subscriptions from collection Iri
217+ $ subscriptions = $ this ->getSubscriptionsFromIri ($ this ->getCollectionIri ($ iri ));
108218 }
109219
110- return [];
220+ $ payloads = [];
221+ foreach ($ subscriptions as [$ subscriptionId , $ subscriptionFields , $ subscriptionResult ]) {
222+ $ payloads [] = [$ subscriptionId , ['type ' => 'delete ' , 'payload ' => $ object ]];
223+ }
224+ $ this ->removeItemFromSubscriptionCache ($ iri );
225+ return $ payloads ;
111226 }
112227
113- private function encodeIriToCacheKey (string $ iri ): string
114- {
115- return str_replace ('/ ' , '_ ' , $ iri );
116- }
117228}
0 commit comments