@@ -42,14 +42,24 @@ public function __construct(private readonly CacheItemPoolInterface $subscriptio
42
42
43
43
public function retrieveSubscriptionId (array $ context , ?array $ result , ?Operation $ operation = null ): ?string
44
44
{
45
+
45
46
/** @var ResolveInfo $info */
46
47
$ info = $ context ['info ' ];
47
48
$ fields = $ info ->getFieldSelection (\PHP_INT_MAX );
48
49
$ this ->arrayRecursiveSort ($ fields , 'ksort ' );
49
50
$ iri = $ operation ? $ this ->getIdentifierFromOperation ($ operation , $ context ['args ' ] ?? []) : $ this ->getIdentifierFromContext ($ context );
50
- if (null === $ iri ) {
51
+ if (empty ( $ iri) ) {
51
52
return null ;
52
53
}
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
+ }
53
63
$ subscriptionsCacheItem = $ this ->subscriptionsCache ->getItem ($ this ->encodeIriToCacheKey ($ iri ));
54
64
$ subscriptions = [];
55
65
if ($ subscriptionsCacheItem ->isHit ()) {
@@ -63,26 +73,129 @@ public function retrieveSubscriptionId(array $context, ?array $result, ?Operatio
63
73
64
74
$ subscriptionId = $ this ->subscriptionIdentifierGenerator ->generateSubscriptionIdentifier ($ fields );
65
75
unset($ result ['clientSubscriptionId ' ]);
76
+ if ($ private && $ privateFields && $ previousObject ) {
77
+ foreach ($ options ['private_fields ' ] as $ privateField ) {
78
+ unset($ result ['__private_field_ ' .$ privateField ]);
79
+ }
80
+ }
66
81
$ subscriptions [] = [$ subscriptionId , $ fields , $ result ];
67
82
$ subscriptionsCacheItem ->set ($ subscriptions );
68
83
$ this ->subscriptionsCache ->save ($ subscriptionsCacheItem );
69
84
85
+ $ this ->updateSubscriptionCollectionCacheData (
86
+ $ iri ,
87
+ $ fields ,
88
+ $ subscriptions ,
89
+ );
90
+
70
91
return $ subscriptionId ;
71
92
}
72
93
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
74
168
{
75
169
$ iri = $ this ->iriConverter ->getIriFromResource ($ object );
76
170
$ subscriptions = $ this ->getSubscriptionsFromIri ($ iri );
171
+ if ($ subscriptions === []) {
172
+ // Get subscriptions from collection Iri
173
+ $ subscriptions = $ this ->getSubscriptionsFromIri ($ this ->getCollectionIri ($ iri ));
174
+ }
77
175
78
176
$ resourceClass = $ this ->getObjectClass ($ object );
79
177
$ resourceMetadata = $ this ->resourceMetadataCollectionFactory ->create ($ resourceClass );
80
178
$ shortName = $ resourceMetadata ->getOperation ()->getShortName ();
81
179
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
+
82
190
$ payloads = [];
83
191
foreach ($ subscriptions as [$ subscriptionId , $ subscriptionFields , $ subscriptionResult ]) {
192
+ if ($ privateFieldData ) {
193
+ $ fieldDiff = array_intersect_assoc ($ subscriptionFields , $ privateFieldData );
194
+ if ($ fieldDiff !== $ privateFieldData ) {
195
+ continue ;
196
+ }
197
+ }
84
198
$ resolverContext = ['fields ' => $ subscriptionFields , 'is_collection ' => false , 'is_mutation ' => false , 'is_subscription ' => true ];
85
- /** @var Operation */
86
199
$ operation = (new Subscription ())->withName ('update_subscription ' )->withShortName ($ shortName );
87
200
$ data = $ this ->normalizeProcessor ->process ($ object , $ operation , [], $ resolverContext );
88
201
@@ -92,26 +205,24 @@ public function getPushPayloads(object $object): array
92
205
$ payloads [] = [$ subscriptionId , $ data ];
93
206
}
94
207
}
95
-
96
208
return $ payloads ;
97
209
}
98
210
99
- /**
100
- * @return array<array>
101
- */
102
- private function getSubscriptionsFromIri (string $ iri ): array
211
+ private function getDeletePushPayloads (object $ object ): array
103
212
{
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 ));
108
218
}
109
219
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 ;
111
226
}
112
227
113
- private function encodeIriToCacheKey (string $ iri ): string
114
- {
115
- return str_replace ('/ ' , '_ ' , $ iri );
116
- }
117
228
}
0 commit comments