2424#include "phongo_compat.h"
2525#include "php_phongo.h"
2626#include "php_bson.h"
27+ #include "php_array_api.h"
28+ #include "Session.h"
2729
2830zend_class_entry * php_phongo_session_ce ;
2931
@@ -228,6 +230,166 @@ static PHP_METHOD(Session, getOperationTime)
228230 php_phongo_new_timestamp_from_increment_and_timestamp (return_value , increment , timestamp TSRMLS_CC );
229231} /* }}} */
230232
233+ /* Creates a opts structure from an array optionally containing an RP, RC,
234+ * and/or WC object. Returns NULL if no options were found, or there was an
235+ * invalid option. If there was an invalid option or structure, an exception
236+ * will be thrown too. */
237+ mongoc_transaction_opt_t * php_mongodb_session_parse_transaction_options (zval * options TSRMLS_DC )
238+ {
239+ mongoc_transaction_opt_t * opts = NULL ;
240+
241+ if (php_array_existsc (options , "readConcern" )) {
242+ zval * read_concern = php_array_fetchc (options , "readConcern" );
243+
244+ if (Z_TYPE_P (read_concern ) != IS_OBJECT || !instanceof_function (Z_OBJCE_P (read_concern ), php_phongo_readconcern_ce TSRMLS_CC )) {
245+ phongo_throw_exception (PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC , "Expected \"readConcern\" option to be %s, %s given" , ZSTR_VAL (php_phongo_readconcern_ce -> name ), PHONGO_ZVAL_CLASS_OR_TYPE_NAME_P (read_concern ));
246+ /* Freeing opts is not needed here, as it can't be set yet. The
247+ * code is here to keep it consistent with the others in case more
248+ * options are added before this one. */
249+ if (opts ) {
250+ mongoc_transaction_opts_destroy (opts );
251+ }
252+ return NULL ;
253+ }
254+
255+ if (!opts ) {
256+ opts = mongoc_transaction_opts_new ();
257+ }
258+
259+ mongoc_transaction_opts_set_read_concern (opts , phongo_read_concern_from_zval (read_concern TSRMLS_CC ));
260+ }
261+
262+ if (php_array_existsc (options , "readPreference" )) {
263+ zval * read_preference = php_array_fetchc (options , "readPreference" );
264+
265+ if (Z_TYPE_P (read_preference ) != IS_OBJECT || !instanceof_function (Z_OBJCE_P (read_preference ), php_phongo_readpreference_ce TSRMLS_CC )) {
266+ phongo_throw_exception (PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC , "Expected \"readPreference\" option to be %s, %s given" , ZSTR_VAL (php_phongo_readpreference_ce -> name ), PHONGO_ZVAL_CLASS_OR_TYPE_NAME_P (read_preference ));
267+ if (opts ) {
268+ mongoc_transaction_opts_destroy (opts );
269+ }
270+ return NULL ;
271+ }
272+
273+ if (!opts ) {
274+ opts = mongoc_transaction_opts_new ();
275+ }
276+
277+ mongoc_transaction_opts_set_read_prefs (opts , phongo_read_preference_from_zval (read_preference TSRMLS_CC ));
278+ }
279+
280+ if (php_array_existsc (options , "writeConcern" )) {
281+ zval * write_concern = php_array_fetchc (options , "writeConcern" );
282+
283+ if (Z_TYPE_P (write_concern ) != IS_OBJECT || !instanceof_function (Z_OBJCE_P (write_concern ), php_phongo_writeconcern_ce TSRMLS_CC )) {
284+ phongo_throw_exception (PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC , "Expected \"writeConcern\" option to be %s, %s given" , ZSTR_VAL (php_phongo_writeconcern_ce -> name ), PHONGO_ZVAL_CLASS_OR_TYPE_NAME_P (write_concern ));
285+ if (opts ) {
286+ mongoc_transaction_opts_destroy (opts );
287+ }
288+ return NULL ;
289+ }
290+
291+ if (!opts ) {
292+ opts = mongoc_transaction_opts_new ();
293+ }
294+
295+ mongoc_transaction_opts_set_write_concern (opts , phongo_write_concern_from_zval (write_concern TSRMLS_CC ));
296+ }
297+
298+ return opts ;
299+ }
300+
301+ /* {{{ proto void MongoDB\Driver\Session::startTransaction([array $options = null])
302+ Starts a new transaction */
303+ static PHP_METHOD (Session , startTransaction )
304+ {
305+ php_phongo_session_t * intern ;
306+ zval * options = NULL ;
307+ mongoc_transaction_opt_t * txn_options = NULL ;
308+ bson_error_t error ;
309+ SUPPRESS_UNUSED_WARNING (return_value_ptr )
310+ SUPPRESS_UNUSED_WARNING (return_value_used )
311+
312+ intern = Z_SESSION_OBJ_P (getThis ());
313+
314+ if (zend_parse_parameters (ZEND_NUM_ARGS () TSRMLS_CC , "|a" , & options ) == FAILURE ) {
315+ return ;
316+ }
317+
318+ if (options ) {
319+ txn_options = php_mongodb_session_parse_transaction_options (options TSRMLS_CC );
320+ }
321+ if (EG (exception )) {
322+ return ;
323+ }
324+
325+ if (!mongoc_client_session_start_transaction (intern -> client_session , txn_options , & error )) {
326+ phongo_throw_exception_from_bson_error_t (& error TSRMLS_CC );
327+ }
328+
329+ if (txn_options ) {
330+ mongoc_transaction_opts_destroy (txn_options );
331+ }
332+ } /* }}} */
333+
334+ /* {{{ proto void MongoDB\Driver\Session::commitTransaction(void)
335+ Commits an existing transaction */
336+ static PHP_METHOD (Session , commitTransaction )
337+ {
338+ php_phongo_session_t * intern ;
339+ bson_error_t error ;
340+ bson_t reply ;
341+ SUPPRESS_UNUSED_WARNING (return_value_ptr )
342+ SUPPRESS_UNUSED_WARNING (return_value_used )
343+
344+ intern = Z_SESSION_OBJ_P (getThis ());
345+
346+ if (zend_parse_parameters_none () == FAILURE ) {
347+ return ;
348+ }
349+
350+ if (!mongoc_client_session_commit_transaction (intern -> client_session , & reply , & error )) {
351+ phongo_throw_exception_from_bson_error_and_reply_t (& error , & reply TSRMLS_CC );
352+ bson_destroy (& reply );
353+ }
354+ } /* }}} */
355+
356+ /* {{{ proto void MongoDB\Driver\Session::abortTransaction(void)
357+ Aborts (rolls back) an existing transaction */
358+ static PHP_METHOD (Session , abortTransaction )
359+ {
360+ php_phongo_session_t * intern ;
361+ bson_error_t error ;
362+ SUPPRESS_UNUSED_WARNING (return_value_ptr )
363+ SUPPRESS_UNUSED_WARNING (return_value_used )
364+
365+ intern = Z_SESSION_OBJ_P (getThis ());
366+
367+ if (zend_parse_parameters_none () == FAILURE ) {
368+ return ;
369+ }
370+
371+ if (!mongoc_client_session_abort_transaction (intern -> client_session , & error )) {
372+ phongo_throw_exception_from_bson_error_t (& error TSRMLS_CC );
373+ }
374+ } /* }}} */
375+
376+ /* {{{ proto void MongoDB\Driver\Session::endSession(void)
377+ Ends the session, and a running transaction if active */
378+ static PHP_METHOD (Session , endSession )
379+ {
380+ php_phongo_session_t * intern ;
381+ SUPPRESS_UNUSED_WARNING (return_value_ptr )
382+ SUPPRESS_UNUSED_WARNING (return_value_used )
383+
384+ intern = Z_SESSION_OBJ_P (getThis ());
385+
386+ if (zend_parse_parameters_none () == FAILURE ) {
387+ return ;
388+ }
389+
390+ mongoc_client_session_destroy (intern -> client_session );
391+ } /* }}} */
392+
231393/* {{{ MongoDB\Driver\Session function entries */
232394ZEND_BEGIN_ARG_INFO_EX (ai_Session_advanceClusterTime , 0 , 0 , 1 )
233395 ZEND_ARG_INFO (0 , clusterTime )
@@ -237,6 +399,10 @@ ZEND_BEGIN_ARG_INFO_EX(ai_Session_advanceOperationTime, 0, 0, 1)
237399 ZEND_ARG_INFO (0 , timestamp )
238400ZEND_END_ARG_INFO ()
239401
402+ ZEND_BEGIN_ARG_INFO_EX (ai_Session_startTransaction , 0 , 0 , 0 )
403+ ZEND_ARG_INFO (0 , options )
404+ ZEND_END_ARG_INFO ()
405+
240406ZEND_BEGIN_ARG_INFO_EX (ai_Session_void , 0 , 0 , 0 )
241407ZEND_END_ARG_INFO ()
242408
@@ -247,6 +413,10 @@ static zend_function_entry php_phongo_session_me[] = {
247413 PHP_ME (Session , getClusterTime , ai_Session_void , ZEND_ACC_PUBLIC | ZEND_ACC_FINAL )
248414 PHP_ME (Session , getLogicalSessionId , ai_Session_void , ZEND_ACC_PUBLIC | ZEND_ACC_FINAL )
249415 PHP_ME (Session , getOperationTime , ai_Session_void , ZEND_ACC_PUBLIC | ZEND_ACC_FINAL )
416+ PHP_ME (Session , startTransaction , ai_Session_startTransaction , ZEND_ACC_PUBLIC | ZEND_ACC_FINAL )
417+ PHP_ME (Session , commitTransaction , ai_Session_void , ZEND_ACC_PUBLIC | ZEND_ACC_FINAL )
418+ PHP_ME (Session , abortTransaction , ai_Session_void , ZEND_ACC_PUBLIC | ZEND_ACC_FINAL )
419+ PHP_ME (Session , endSession , ai_Session_void , ZEND_ACC_PUBLIC | ZEND_ACC_FINAL )
250420 ZEND_NAMED_ME (__construct , PHP_FN (MongoDB_disabled___construct ), ai_Session_void , ZEND_ACC_PRIVATE | ZEND_ACC_FINAL )
251421 ZEND_NAMED_ME (__wakeup , PHP_FN (MongoDB_disabled___wakeup ), ai_Session_void , ZEND_ACC_PUBLIC | ZEND_ACC_FINAL )
252422 PHP_FE_END
0 commit comments