17
17
18
18
namespace MongoDB ;
19
19
20
- use MongoDB \BSON \Serializable ;
21
- use MongoDB \Driver \Cursor ;
20
+ use MongoDB \Driver \CursorId ;
22
21
use MongoDB \Driver \Exception \ConnectionException ;
23
22
use MongoDB \Driver \Exception \RuntimeException ;
24
23
use MongoDB \Driver \Exception \ServerException ;
25
- use MongoDB \Exception \InvalidArgumentException ;
26
24
use MongoDB \Exception \ResumeTokenException ;
27
- use MongoDB \Model \TailableCursorIterator ;
25
+ use MongoDB \Model \ChangeStreamIterator ;
28
26
use Iterator ;
29
27
30
28
/**
@@ -46,9 +44,8 @@ class ChangeStream implements Iterator
46
44
private static $ errorCodeInterrupted = 11601 ;
47
45
private static $ errorCodeCursorKilled = 237 ;
48
46
49
- private $ resumeToken ;
50
47
private $ resumeCallable ;
51
- private $ csIt ;
48
+ private $ iterator ;
52
49
private $ key = 0 ;
53
50
54
51
/**
@@ -61,14 +58,13 @@ class ChangeStream implements Iterator
61
58
* Constructor.
62
59
*
63
60
* @internal
64
- * @param Cursor $cursor
65
- * @param callable $resumeCallable
66
- * @param boolean $isFirstBatchEmpty
61
+ * @param ChangeStreamIterator $iterator
62
+ * @param callable $resumeCallable
67
63
*/
68
- public function __construct (Cursor $ cursor , callable $ resumeCallable, $ isFirstBatchEmpty )
64
+ public function __construct (ChangeStreamIterator $ iterator , callable $ resumeCallable )
69
65
{
66
+ $ this ->iterator = $ iterator ;
70
67
$ this ->resumeCallable = $ resumeCallable ;
71
- $ this ->csIt = new TailableCursorIterator ($ cursor , $ isFirstBatchEmpty );
72
68
}
73
69
74
70
/**
@@ -77,15 +73,29 @@ public function __construct(Cursor $cursor, callable $resumeCallable, $isFirstBa
77
73
*/
78
74
public function current ()
79
75
{
80
- return $ this ->csIt ->current ();
76
+ return $ this ->iterator ->current ();
81
77
}
82
78
83
79
/**
84
- * @return \MongoDB\Driver\ CursorId
80
+ * @return CursorId
85
81
*/
86
82
public function getCursorId ()
87
83
{
88
- return $ this ->csIt ->getInnerIterator ()->getId ();
84
+ return $ this ->iterator ->getInnerIterator ()->getId ();
85
+ }
86
+
87
+ /**
88
+ * Returns the resume token for the iterator's current position.
89
+ *
90
+ * Null may be returned if no change documents have been iterated and the
91
+ * server did not include a postBatchResumeToken in its aggregate or getMore
92
+ * command response.
93
+ *
94
+ * @return array|object|null
95
+ */
96
+ public function getResumeToken ()
97
+ {
98
+ return $ this ->iterator ->getResumeToken ();
89
99
}
90
100
91
101
/**
@@ -108,7 +118,7 @@ public function key()
108
118
public function next ()
109
119
{
110
120
try {
111
- $ this ->csIt ->next ();
121
+ $ this ->iterator ->next ();
112
122
$ this ->onIteration ($ this ->hasAdvanced );
113
123
} catch (RuntimeException $ e ) {
114
124
$ this ->resumeOrThrow ($ e );
@@ -123,7 +133,7 @@ public function next()
123
133
public function rewind ()
124
134
{
125
135
try {
126
- $ this ->csIt ->rewind ();
136
+ $ this ->iterator ->rewind ();
127
137
/* Unlike next() and resume(), the decision to increment the key
128
138
* does not depend on whether the change stream has advanced. This
129
139
* ensures that multiple calls to rewind() do not alter state. */
@@ -139,40 +149,7 @@ public function rewind()
139
149
*/
140
150
public function valid ()
141
151
{
142
- return $ this ->csIt ->valid ();
143
- }
144
-
145
- /**
146
- * Extracts the resume token (i.e. "_id" field) from the change document.
147
- *
148
- * @param array|object $document Change document
149
- * @return mixed
150
- * @throws InvalidArgumentException
151
- * @throws ResumeTokenException if the resume token is not found or invalid
152
- */
153
- private function extractResumeToken ($ document )
154
- {
155
- if ( ! is_array ($ document ) && ! is_object ($ document )) {
156
- throw InvalidArgumentException::invalidType ('$document ' , $ document , 'array or object ' );
157
- }
158
-
159
- if ($ document instanceof Serializable) {
160
- return $ this ->extractResumeToken ($ document ->bsonSerialize ());
161
- }
162
-
163
- $ resumeToken = is_array ($ document )
164
- ? (isset ($ document ['_id ' ]) ? $ document ['_id ' ] : null )
165
- : (isset ($ document ->_id ) ? $ document ->_id : null );
166
-
167
- if ( ! isset ($ resumeToken )) {
168
- throw ResumeTokenException::notFound ();
169
- }
170
-
171
- if ( ! is_array ($ resumeToken ) && ! is_object ($ resumeToken )) {
172
- throw ResumeTokenException::invalidType ($ resumeToken );
173
- }
174
-
175
- return $ resumeToken ;
152
+ return $ this ->iterator ->valid ();
176
153
}
177
154
178
155
/**
@@ -222,13 +199,11 @@ private function onIteration($incrementKey)
222
199
}
223
200
224
201
/* Return early if there is not a current result. Avoid any attempt to
225
- * increment the iterator's key or extract a resume token */
202
+ * increment the iterator's key. */
226
203
if (!$ this ->valid ()) {
227
204
return ;
228
205
}
229
206
230
- $ this ->resumeToken = $ this ->extractResumeToken ($ this ->csIt ->current ());
231
-
232
207
if ($ incrementKey ) {
233
208
$ this ->key ++;
234
209
}
@@ -237,16 +212,14 @@ private function onIteration($incrementKey)
237
212
}
238
213
239
214
/**
240
- * Creates a new changeStream after a resumable server error.
215
+ * Recreates the ChangeStreamIterator after a resumable server error.
241
216
*
242
217
* @return void
243
218
*/
244
219
private function resume ()
245
220
{
246
- list ($ cursor , $ isFirstBatchEmpty ) = call_user_func ($ this ->resumeCallable , $ this ->resumeToken );
247
-
248
- $ this ->csIt = new TailableCursorIterator ($ cursor , $ isFirstBatchEmpty );
249
- $ this ->csIt ->rewind ();
221
+ $ this ->iterator = call_user_func ($ this ->resumeCallable , $ this ->getResumeToken ());
222
+ $ this ->iterator ->rewind ();
250
223
251
224
$ this ->onIteration ($ this ->hasAdvanced );
252
225
}
0 commit comments