@@ -46,6 +46,181 @@ PHONGO_API zend_class_entry *php_phongo_cursor_ce;
4646
4747zend_object_handlers php_phongo_handler_cursor ;
4848
49+ static void php_phongo_cursor_free_current (php_phongo_cursor_t * cursor ) /* {{{ */
50+ {
51+ if (!Z_ISUNDEF (cursor -> visitor_data .zchild )) {
52+ zval_ptr_dtor (& cursor -> visitor_data .zchild );
53+ #if PHP_VERSION_ID >= 70000
54+ ZVAL_UNDEF (& cursor -> visitor_data .zchild );
55+ #else
56+ cursor -> visitor_data .zchild = NULL ;
57+ #endif
58+ }
59+ } /* }}} */
60+
61+ void php_phongo_cursor_free (php_phongo_cursor_t * cursor ) /* {{{ */
62+ {
63+ if (cursor -> cursor ) {
64+ mongoc_cursor_destroy (cursor -> cursor );
65+ cursor -> cursor = NULL ;
66+ }
67+
68+ php_phongo_cursor_free_current (cursor );
69+ } /* }}} */
70+
71+ /* {{{ Iterator handlers */
72+ static void php_phongo_cursor_iterator_dtor (zend_object_iterator * iter TSRMLS_DC ) /* {{{ */
73+ {
74+ php_phongo_cursor_iterator * cursor_it = (php_phongo_cursor_iterator * )iter ;
75+
76+ if (!Z_ISUNDEF (cursor_it -> intern .data )) {
77+ #if PHP_VERSION_ID >= 70000
78+ zval_ptr_dtor (& cursor_it -> intern .data );
79+ #else
80+ zval_ptr_dtor ((zval * * )& cursor_it -> intern .data );
81+ cursor_it -> intern .data = NULL ;
82+ #endif
83+ }
84+
85+ #if PHP_VERSION_ID < 70000
86+ efree (cursor_it );
87+ #endif
88+ } /* }}} */
89+
90+ static int php_phongo_cursor_iterator_valid (zend_object_iterator * iter TSRMLS_DC ) /* {{{ */
91+ {
92+ php_phongo_cursor_t * cursor = ((php_phongo_cursor_iterator * )iter )-> cursor ;
93+
94+ if (!Z_ISUNDEF (cursor -> visitor_data .zchild )) {
95+ return SUCCESS ;
96+ }
97+
98+ return FAILURE ;
99+ } /* }}} */
100+
101+ #if PHP_VERSION_ID < 50500
102+ static int php_phongo_cursor_iterator_get_current_key (zend_object_iterator * iter , char * * str_key , uint * str_key_len , ulong * int_key TSRMLS_DC ) /* {{{ */
103+ {
104+ php_phongo_cursor_t * cursor = ((php_phongo_cursor_iterator * )iter )-> cursor ;
105+
106+ * int_key = (ulong ) cursor -> current ;
107+ return HASH_KEY_IS_LONG ;
108+ } /* }}} */
109+ #else
110+ static void php_phongo_cursor_iterator_get_current_key (zend_object_iterator * iter , zval * key TSRMLS_DC ) /* {{{ */
111+ {
112+ php_phongo_cursor_t * cursor = ((php_phongo_cursor_iterator * )iter )-> cursor ;
113+
114+ ZVAL_LONG (key , cursor -> current );
115+ } /* }}} */
116+ #endif
117+
118+ #if PHP_VERSION_ID < 70000
119+ static void php_phongo_cursor_iterator_get_current_data (zend_object_iterator * iter , zval * * * data TSRMLS_DC ) /* {{{ */
120+ {
121+ php_phongo_cursor_t * cursor = ((php_phongo_cursor_iterator * )iter )-> cursor ;
122+
123+ * data = & cursor -> visitor_data .zchild ;
124+ } /* }}} */
125+ #else
126+ static zval * php_phongo_cursor_iterator_get_current_data (zend_object_iterator * iter ) /* {{{ */
127+ {
128+ php_phongo_cursor_t * cursor = ((php_phongo_cursor_iterator * )iter )-> cursor ;
129+
130+ return & cursor -> visitor_data .zchild ;
131+ } /* }}} */
132+ #endif
133+
134+ static void php_phongo_cursor_iterator_move_forward (zend_object_iterator * iter TSRMLS_DC ) /* {{{ */
135+ {
136+ php_phongo_cursor_iterator * cursor_it = (php_phongo_cursor_iterator * )iter ;
137+ php_phongo_cursor_t * cursor = cursor_it -> cursor ;
138+ const bson_t * doc ;
139+
140+ php_phongo_cursor_free_current (cursor );
141+ cursor -> current ++ ;
142+
143+ if (mongoc_cursor_next (cursor -> cursor , & doc )) {
144+ phongo_bson_to_zval_ex (bson_get_data (doc ), doc -> len , & cursor -> visitor_data );
145+ } else {
146+ bson_error_t error ;
147+
148+ if (mongoc_cursor_error (cursor -> cursor , & error )) {
149+ /* Intentionally not destroying the cursor as it will happen
150+ * naturally now that there are no more results */
151+ phongo_throw_exception_from_bson_error_t (& error TSRMLS_CC );
152+ }
153+ }
154+ } /* }}} */
155+
156+ static void php_phongo_cursor_iterator_rewind (zend_object_iterator * iter TSRMLS_DC ) /* {{{ */
157+ {
158+ php_phongo_cursor_iterator * cursor_it = (php_phongo_cursor_iterator * )iter ;
159+ php_phongo_cursor_t * cursor = cursor_it -> cursor ;
160+ const bson_t * doc ;
161+
162+ if (cursor -> current > 0 ) {
163+ phongo_throw_exception (PHONGO_ERROR_LOGIC TSRMLS_CC , "Cursors cannot rewind after starting iteration" );
164+ return ;
165+ }
166+
167+ php_phongo_cursor_free_current (cursor );
168+
169+ doc = mongoc_cursor_current (cursor -> cursor );
170+
171+ if (doc ) {
172+ phongo_bson_to_zval_ex (bson_get_data (doc ), doc -> len , & cursor -> visitor_data );
173+ }
174+ } /* }}} */
175+
176+ /* iterator handler table */
177+ zend_object_iterator_funcs php_phongo_cursor_iterator_funcs = {
178+ php_phongo_cursor_iterator_dtor ,
179+ php_phongo_cursor_iterator_valid ,
180+ php_phongo_cursor_iterator_get_current_data ,
181+ php_phongo_cursor_iterator_get_current_key ,
182+ php_phongo_cursor_iterator_move_forward ,
183+ php_phongo_cursor_iterator_rewind ,
184+ NULL /* invalidate_current is not used */
185+ };
186+
187+ zend_object_iterator * php_phongo_cursor_get_iterator (zend_class_entry * ce , zval * object , int by_ref TSRMLS_DC ) /* {{{ */
188+ {
189+ php_phongo_cursor_iterator * cursor_it = NULL ;
190+ php_phongo_cursor_t * cursor = Z_CURSOR_OBJ_P (object );
191+
192+ if (by_ref ) {
193+ zend_error (E_ERROR , "An iterator cannot be used with foreach by reference" );
194+ }
195+
196+ if (cursor -> got_iterator ) {
197+ phongo_throw_exception (PHONGO_ERROR_LOGIC TSRMLS_CC , "Cursors cannot yield multiple iterators" );
198+ return NULL ;
199+ }
200+
201+ cursor -> got_iterator = 1 ;
202+
203+ cursor_it = ecalloc (1 , sizeof (php_phongo_cursor_iterator ));
204+ #if PHP_VERSION_ID >= 70000
205+ zend_iterator_init (& cursor_it -> intern );
206+ #endif
207+
208+ #if PHP_VERSION_ID >= 70000
209+ ZVAL_COPY (& cursor_it -> intern .data , object );
210+ #else
211+ Z_ADDREF_P (object );
212+ cursor_it -> intern .data = (void * )object ;
213+ #endif
214+ cursor_it -> intern .funcs = & php_phongo_cursor_iterator_funcs ;
215+ cursor_it -> cursor = cursor ;
216+ /* cursor_it->current should already be allocated to zero */
217+
218+ php_phongo_cursor_free_current (cursor_it -> cursor );
219+
220+ return & cursor_it -> intern ;
221+ } /* }}} */
222+ /* }}} */
223+
49224/* {{{ proto void Cursor::setTypeMap(array $typemap)
50225 Sets a type map to use for BSON unserialization */
51226PHP_METHOD (Cursor , setTypeMap )
0 commit comments