@@ -448,13 +448,109 @@ mongoc_bulk_operation_t *phongo_bulkwrite_init(zend_bool ordered) { /* {{{ */
448
448
return mongoc_bulk_operation_new (ordered );
449
449
} /* }}} */
450
450
451
- bool phongo_execute_write (mongoc_client_t * client , const char * namespace , php_phongo_bulkwrite_t * bulk_write , const mongoc_write_concern_t * write_concern , int server_id , zval * return_value , int return_value_used TSRMLS_DC ) /* {{{ */
451
+ #define PHONGO_WRITECONCERN_ALLOWED 0x01
452
+ #define PHONGO_READPREFERENCE_ALLOWED 0x02
453
+
454
+ static int process_read_preference (zval * option , zval * * zreadPreference TSRMLS_DC )
455
+ {
456
+ if (Z_TYPE_P (option ) == IS_OBJECT && instanceof_function (Z_OBJCE_P (option ), php_phongo_readpreference_ce TSRMLS_CC )) {
457
+ * zreadPreference = option ;
458
+ } else {
459
+ phongo_throw_exception (
460
+ PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC ,
461
+ "Expected 'readPreference' option to be 'MongoDB\\Driver\\ReadPreference', %s given" ,
462
+ zend_get_type_by_const (Z_TYPE_P (option ))
463
+ );
464
+ return false;
465
+ }
466
+ return true;
467
+ }
468
+
469
+ static int process_write_concern (zval * option , zval * * zwriteConcern TSRMLS_DC )
470
+ {
471
+ if (Z_TYPE_P (option ) == IS_OBJECT && instanceof_function (Z_OBJCE_P (option ), php_phongo_writeconcern_ce TSRMLS_CC )) {
472
+ * zwriteConcern = option ;
473
+ } else {
474
+ phongo_throw_exception (
475
+ PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC ,
476
+ "Expected 'writeConcern' option to be 'MongoDB\\Driver\\WriteConcern', %s given" ,
477
+ zend_get_type_by_const (Z_TYPE_P (option ))
478
+ );
479
+ return false;
480
+ }
481
+ return true;
482
+ }
483
+
484
+ static int phongo_execute_parse_options (zval * options , int flags , zval * * zreadPreference , zval * * zwriteConcern TSRMLS_DC )
485
+ {
486
+ if (options && Z_TYPE_P (options ) == IS_ARRAY ) {
487
+ HashTable * ht_data = HASH_OF (options );
488
+ #if PHP_VERSION_ID >= 70000
489
+ zend_string * string_key = NULL ;
490
+ zend_ulong num_key = 0 ;
491
+ zval * option ;
492
+
493
+ ZEND_HASH_FOREACH_KEY_VAL (ht_data , num_key , string_key , option ) {
494
+ if (!string_key ) {
495
+ continue ;
496
+ }
497
+
498
+ if ((!strcasecmp (ZSTR_VAL (string_key ), "readPreference" )) && (flags & PHONGO_READPREFERENCE_ALLOWED )) {
499
+ if (!process_read_preference (option , zreadPreference )) {
500
+ return false;
501
+ }
502
+ } else if ((!strcasecmp (ZSTR_VAL (string_key ), "writeConcern" )) && (flags & PHONGO_WRITECONCERN_ALLOWED )) {
503
+ if (!process_write_concern (option , zwriteConcern )) {
504
+ return false;
505
+ }
506
+ } else {
507
+ phongo_throw_exception (PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC , "Unknown option '%s'" , ZSTR_VAL (string_key ));
508
+ return false;
509
+ }
510
+ } ZEND_HASH_FOREACH_END ();
511
+ #else
512
+ HashPosition pos ;
513
+ zval * * option ;
514
+
515
+ for (zend_hash_internal_pointer_reset_ex (ht_data , & pos );
516
+ zend_hash_get_current_data_ex (ht_data , (void * * ) & option , & pos ) == SUCCESS ;
517
+ zend_hash_move_forward_ex (ht_data , & pos )) {
518
+ char * string_key = NULL ;
519
+ uint string_key_len = 0 ;
520
+ ulong num_key = 0 ;
521
+
522
+ if (HASH_KEY_IS_STRING != zend_hash_get_current_key_ex (ht_data , & string_key , & string_key_len , & num_key , 0 , & pos )) {
523
+ continue ;
524
+ }
525
+
526
+ /* URI options are case-insensitive */
527
+ if ((!strcasecmp (string_key , "readPreference" )) && (flags & PHONGO_READPREFERENCE_ALLOWED )) {
528
+ if (!process_read_preference (* option , zreadPreference TSRMLS_CC )) {
529
+ return false;
530
+ }
531
+ } else if ((!strcasecmp (string_key , "writeConcern" )) && (flags & PHONGO_WRITECONCERN_ALLOWED )) {
532
+ if (!process_write_concern (* option , zwriteConcern TSRMLS_CC )) {
533
+ return false;
534
+ }
535
+ } else {
536
+ phongo_throw_exception (PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC , "Unknown option '%s'" , string_key );
537
+ return false;
538
+ }
539
+ }
540
+ #endif
541
+ }
542
+ return true;
543
+ }
544
+
545
+ bool phongo_execute_write (mongoc_client_t * client , const char * namespace , php_phongo_bulkwrite_t * bulk_write , zval * options , int server_id , zval * return_value , int return_value_used TSRMLS_DC ) /* {{{ */
452
546
{
453
547
bson_error_t error ;
454
548
int success ;
455
549
bson_t reply = BSON_INITIALIZER ;
456
550
mongoc_bulk_operation_t * bulk = bulk_write -> bulk ;
457
551
php_phongo_writeresult_t * writeresult ;
552
+ zval * zwriteConcern = NULL ;
553
+ const mongoc_write_concern_t * write_concern ;
458
554
459
555
if (bulk_write -> executed ) {
460
556
phongo_throw_exception (PHONGO_ERROR_WRITE_FAILED TSRMLS_CC , "BulkWrite objects may only be executed once and this instance has already been executed" );
@@ -466,12 +562,20 @@ bool phongo_execute_write(mongoc_client_t *client, const char *namespace, php_ph
466
562
return false;
467
563
}
468
564
565
+ /* FIXME: Legacy way of specifying the writeConcern option into this function */
566
+ if (options && Z_TYPE_P (options ) == IS_OBJECT && instanceof_function (Z_OBJCE_P (options ), php_phongo_writeconcern_ce TSRMLS_CC )) {
567
+ zwriteConcern = options ;
568
+ } else if (!phongo_execute_parse_options (options , PHONGO_WRITECONCERN_ALLOWED , NULL , & zwriteConcern TSRMLS_CC )) {
569
+ return false;
570
+ }
571
+
469
572
mongoc_bulk_operation_set_database (bulk , bulk_write -> database );
470
573
mongoc_bulk_operation_set_collection (bulk , bulk_write -> collection );
471
574
mongoc_bulk_operation_set_client (bulk , client );
472
575
473
576
/* If a write concern was not specified, libmongoc will use the client's
474
577
* write concern; however, we should still fetch it for the write result. */
578
+ write_concern = phongo_write_concern_from_zval (zwriteConcern TSRMLS_CC );
475
579
if (write_concern ) {
476
580
mongoc_bulk_operation_set_write_concern (bulk , write_concern );
477
581
} else {
@@ -542,13 +646,14 @@ static bool phongo_advance_cursor_and_check_for_error(mongoc_cursor_t *cursor TS
542
646
return true;
543
647
}
544
648
545
- int phongo_execute_query (mongoc_client_t * client , const char * namespace , zval * zquery , zval * zreadPreference , int server_id , zval * return_value , int return_value_used TSRMLS_DC ) /* {{{ */
649
+ int phongo_execute_query (mongoc_client_t * client , const char * namespace , zval * zquery , zval * options , int server_id , zval * return_value , int return_value_used TSRMLS_DC ) /* {{{ */
546
650
{
547
651
const php_phongo_query_t * query ;
548
652
mongoc_cursor_t * cursor ;
549
653
char * dbname ;
550
654
char * collname ;
551
655
mongoc_collection_t * collection ;
656
+ zval * zreadPreference = NULL ;
552
657
553
658
if (!phongo_split_namespace (namespace , & dbname , & collname )) {
554
659
phongo_throw_exception (PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC , "%s: %s" , "Invalid namespace provided" , namespace );
@@ -564,6 +669,13 @@ int phongo_execute_query(mongoc_client_t *client, const char *namespace, zval *z
564
669
mongoc_collection_set_read_concern (collection , query -> read_concern );
565
670
}
566
671
672
+ /* FIXME: Legacy way of specifying the readPreference option into this function */
673
+ if (options && Z_TYPE_P (options ) == IS_OBJECT && instanceof_function (Z_OBJCE_P (options ), php_phongo_readpreference_ce TSRMLS_CC )) {
674
+ zreadPreference = options ;
675
+ } else if (!phongo_execute_parse_options (options , PHONGO_READPREFERENCE_ALLOWED , & zreadPreference , NULL TSRMLS_CC )) {
676
+ return false;
677
+ }
678
+
567
679
cursor = mongoc_collection_find_with_opts (collection , query -> filter , query -> opts , phongo_read_preference_from_zval (zreadPreference TSRMLS_CC ));
568
680
mongoc_collection_destroy (collection );
569
681
@@ -603,7 +715,7 @@ static bson_t *create_wrapped_command_envelope(const char *db, bson_t *reply)
603
715
return tmp ;
604
716
}
605
717
606
- static int phongo_do_select_server (mongoc_client_t * client , bson_t * opts , zval * zreadPreference , int server_id )
718
+ static int phongo_do_select_server (mongoc_client_t * client , bson_t * opts , zval * zreadPreference , int server_id TSRMLS_DC )
607
719
{
608
720
bson_error_t error ;
609
721
uint32_t selected_server_id ;
@@ -632,7 +744,7 @@ static int phongo_do_select_server(mongoc_client_t *client, bson_t *opts, zval *
632
744
return selected_server_id ;
633
745
}
634
746
635
- int phongo_execute_command (mongoc_client_t * client , const char * db , zval * zcommand , zval * zreadPreference , int server_id , zval * return_value , int return_value_used TSRMLS_DC ) /* {{{ */
747
+ int phongo_execute_command (mongoc_client_t * client , const char * db , zval * zcommand , zval * options , int server_id , zval * return_value , int return_value_used TSRMLS_DC ) /* {{{ */
636
748
{
637
749
const php_phongo_command_t * command ;
638
750
bson_iter_t iter ;
@@ -641,17 +753,28 @@ int phongo_execute_command(mongoc_client_t *client, const char *db, zval *zcomma
641
753
bson_t * opts ;
642
754
mongoc_cursor_t * cmd_cursor ;
643
755
uint32_t selected_server_id ;
756
+ zval * zreadPreference = NULL ;
644
757
645
758
command = Z_COMMAND_OBJ_P (zcommand );
646
759
647
760
opts = bson_new ();
648
761
649
- selected_server_id = phongo_do_select_server (client , opts , zreadPreference , server_id );
762
+ /* FIXME: Legacy way of specifying the readPreference option into this function */
763
+ if (options && Z_TYPE_P (options ) == IS_OBJECT && instanceof_function (Z_OBJCE_P (options ), php_phongo_readpreference_ce TSRMLS_CC )) {
764
+ zreadPreference = options ;
765
+ } else if (!phongo_execute_parse_options (options , PHONGO_READPREFERENCE_ALLOWED , & zreadPreference , NULL TSRMLS_CC )) {
766
+ return false;
767
+ }
768
+
769
+ selected_server_id = phongo_do_select_server (client , opts , zreadPreference , server_id TSRMLS_CC );
650
770
if (!selected_server_id ) {
651
771
bson_free (opts );
652
772
return false;
653
773
}
654
774
775
+ /* Although "opts" already always includes the serverId option, the read
776
+ * preference is added to the command parts, which is relevant for mongos
777
+ * command construction. */
655
778
if (!mongoc_client_command_with_opts (client , db , command -> bson , phongo_read_preference_from_zval (zreadPreference TSRMLS_CC ), opts , & reply , & error )) {
656
779
phongo_throw_exception_from_bson_error_t (& error TSRMLS_CC );
657
780
bson_free (opts );
0 commit comments