@@ -103,22 +103,7 @@ public function next()
103
103
{
104
104
try {
105
105
$ this ->csIt ->next ();
106
- if ($ this ->valid ()) {
107
- if ($ this ->hasAdvanced ) {
108
- $ this ->key ++;
109
- }
110
- $ this ->hasAdvanced = true ;
111
- $ this ->resumeToken = $ this ->extractResumeToken ($ this ->csIt ->current ());
112
- }
113
- /* If the cursorId is 0, the server has invalidated the cursor so we
114
- * will never perform another getMore. This means that we cannot
115
- * resume and we can therefore unset the resumeCallable, which will
116
- * free any reference to Watch. This will also free the only
117
- * reference to an implicit session, since any such reference
118
- * belongs to Watch. */
119
- if ((string ) $ this ->getCursorId () === '0 ' ) {
120
- $ this ->resumeCallable = null ;
121
- }
106
+ $ this ->onIteration (true );
122
107
} catch (RuntimeException $ e ) {
123
108
$ this ->resumeOrThrow ($ e );
124
109
}
@@ -133,14 +118,7 @@ public function rewind()
133
118
{
134
119
try {
135
120
$ this ->csIt ->rewind ();
136
- if ($ this ->valid ()) {
137
- $ this ->hasAdvanced = true ;
138
- $ this ->resumeToken = $ this ->extractResumeToken ($ this ->csIt ->current ());
139
- }
140
- // As with next(), free the callable once we know it will never be used.
141
- if ((string ) $ this ->getCursorId () === '0 ' ) {
142
- $ this ->resumeCallable = null ;
143
- }
121
+ $ this ->onIteration (false );
144
122
} catch (RuntimeException $ e ) {
145
123
$ this ->resumeOrThrow ($ e );
146
124
}
@@ -158,7 +136,7 @@ public function valid()
158
136
/**
159
137
* Extracts the resume token (i.e. "_id" field) from the change document.
160
138
*
161
- * @param array|document $document Change document
139
+ * @param array|object $document Change document
162
140
* @return mixed
163
141
* @throws InvalidArgumentException
164
142
* @throws ResumeTokenException if the resume token is not found or invalid
@@ -212,6 +190,38 @@ private function isResumableError(RuntimeException $exception)
212
190
return true ;
213
191
}
214
192
193
+ /**
194
+ * Perform housekeeping after an iteration event (i.e. next or rewind).
195
+ *
196
+ * @param boolean $isNext Whether the iteration event was a call to next()
197
+ * @throws ResumeTokenException
198
+ */
199
+ private function onIteration ($ isNext )
200
+ {
201
+ /* If the cursorId is 0, the server has invalidated the cursor and we
202
+ * will never perform another getMore nor need to resume since any
203
+ * remaining results (up to and including the invalidate event) will
204
+ * have been received in the last response. Therefore, we can unset the
205
+ * resumeCallable. This will free any reference to Watch as well as the
206
+ * only reference to any implicit session created therein. */
207
+ if ((string ) $ this ->getCursorId () === '0 ' ) {
208
+ $ this ->resumeCallable = null ;
209
+ }
210
+
211
+ if (!$ this ->valid ()) {
212
+ return ;
213
+ }
214
+
215
+ /* Increment the key if the iteration event was a call to next() and we
216
+ * have already advanced past the first result. */
217
+ if ($ isNext && $ this ->hasAdvanced ) {
218
+ $ this ->key ++;
219
+ }
220
+
221
+ $ this ->hasAdvanced = true ;
222
+ $ this ->resumeToken = $ this ->extractResumeToken ($ this ->csIt ->current ());
223
+ }
224
+
215
225
/**
216
226
* Creates a new changeStream after a resumable server error.
217
227
*
@@ -222,6 +232,7 @@ private function resume()
222
232
$ newChangeStream = call_user_func ($ this ->resumeCallable , $ this ->resumeToken );
223
233
$ this ->csIt = $ newChangeStream ->csIt ;
224
234
$ this ->csIt ->rewind ();
235
+ $ this ->onIteration (false );
225
236
}
226
237
227
238
/**
0 commit comments