@@ -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,19 +715,11 @@ static bson_t *create_wrapped_command_envelope(const char *db, bson_t *reply)
603
715
return tmp ;
604
716
}
605
717
606
- 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 ) /* {{{ */
718
+ static int phongo_do_select_server (mongoc_client_t * client , bson_t * opts , zval * zreadPreference , int server_id TSRMLS_DC )
607
719
{
608
- const php_phongo_command_t * command ;
609
- bson_iter_t iter ;
610
- bson_t reply ;
611
720
bson_error_t error ;
612
- bson_t * opts ;
613
- mongoc_cursor_t * cmd_cursor ;
614
721
uint32_t selected_server_id ;
615
722
616
- command = Z_COMMAND_OBJ_P (zcommand );
617
-
618
- opts = bson_new ();
619
723
if (server_id > 0 ) {
620
724
bson_append_int32 (opts , "serverId" , -1 , server_id );
621
725
selected_server_id = server_id ;
@@ -633,11 +737,44 @@ int phongo_execute_command(mongoc_client_t *client, const char *db, zval *zcomma
633
737
phongo_throw_exception_from_bson_error_t (& error TSRMLS_CC );
634
738
}
635
739
636
- bson_free (opts );
637
740
return false;
638
741
}
639
742
}
640
743
744
+ return selected_server_id ;
745
+ }
746
+
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 ) /* {{{ */
748
+ {
749
+ const php_phongo_command_t * command ;
750
+ bson_iter_t iter ;
751
+ bson_t reply ;
752
+ bson_error_t error ;
753
+ bson_t * opts ;
754
+ mongoc_cursor_t * cmd_cursor ;
755
+ uint32_t selected_server_id ;
756
+ zval * zreadPreference = NULL ;
757
+
758
+ command = Z_COMMAND_OBJ_P (zcommand );
759
+
760
+ opts = bson_new ();
761
+
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 );
770
+ if (!selected_server_id ) {
771
+ bson_free (opts );
772
+ return false;
773
+ }
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. */
641
778
if (!mongoc_client_command_with_opts (client , db , command -> bson , phongo_read_preference_from_zval (zreadPreference TSRMLS_CC ), opts , & reply , & error )) {
642
779
phongo_throw_exception_from_bson_error_t (& error TSRMLS_CC );
643
780
bson_free (opts );
0 commit comments