vel_names ), 'default' => self::DEFAULT_DB_TRANSACTIONS_ISOLATION_LEVEL, ); $settings[] = array( 'type' => 'sectionend' ); return $settings; } /** * Get the valid database transaction isolation level names. * * @return string[] */ public static function get_valid_transaction_isolation_levels() { return array( 'REPEATABLE READ', 'READ COMMITTED', 'READ UNCOMMITTED', 'SERIALIZABLE', ); } /** * Handler for the individual setting updated hook. * * @param string $option Setting name. * @param mixed $old_value Old value of the setting. * @param mixed $value New value of the setting. */ private function process_updated_option( $option, $old_value, $value ) { if ( DataSynchronizer::ORDERS_DATA_SYNC_ENABLED_OPTION === $option && 'no' === $value ) { $this->data_synchronizer->cleanup_synchronization_state(); } } /** * Handler for the setting pre-update hook. * We use it to verify that authoritative orders table switch doesn't happen while sync is pending. * * @param mixed $value New value of the setting. * @param string $option Setting name. * @param mixed $old_value Old value of the setting. * * @throws \Exception Attempt to change the authoritative orders table while orders sync is pending. */ private function process_pre_update_option( $value, $option, $old_value ) { if ( self::CUSTOM_ORDERS_TABLE_USAGE_ENABLED_OPTION !== $option || $value === $old_value || false === $old_value ) { return $value; } /** * Commenting out for better testability. $sync_is_pending = 0 !== $this->data_synchronizer->get_current_orders_pending_sync_count(); if ( $sync_is_pending ) { throw new \Exception( "The authoritative table for orders storage can't be changed while there are orders out of sync" ); } */ return $value; } /** * Handler for the synchronization finished hook. * Here we switch the authoritative table if needed. */ private function process_sync_finished() { if ( ! $this->auto_flip_authoritative_table_enabled() ) { return; } update_option( self::AUTO_FLIP_AUTHORITATIVE_TABLE_ROLES_OPTION, 'no' ); if ( $this->custom_orders_table_usage_is_enabled() ) { update_option( self::CUSTOM_ORDERS_TABLE_USAGE_ENABLED_OPTION, 'no' ); } else { update_option( self::CUSTOM_ORDERS_TABLE_USAGE_ENABLED_OPTION, 'yes' ); } } /** * Is the automatic authoritative table switch setting set? * * @return bool */ private function auto_flip_authoritative_table_enabled(): bool { return get_option( self::AUTO_FLIP_AUTHORITATIVE_TABLE_ROLES_OPTION ) === 'yes'; } /** * Handler for the all settings updated hook. */ private function process_options_updated() { $data_sync_is_enabled = $this->data_synchronizer->data_sync_is_enabled(); // Disabling the sync implies disabling the automatic authoritative table switch too. if ( ! $data_sync_is_enabled && $this->auto_flip_authoritative_table_enabled() ) { update_option( self::AUTO_FLIP_AUTHORITATIVE_TABLE_ROLES_OPTION, 'no' ); } // Enabling/disabling the sync implies starting/stopping it too, if needed. // We do this check here, and not in process_pre_update_option, so that if for some reason // the setting is enabled but no sync is in process, sync will start by just saving the // settings even without modifying them (and the opposite: sync will be stopped if for // some reason it was ongoing while it was disabled). if ( $data_sync_is_enabled ) { $this->batch_processing_controller->enqueue_processor( DataSynchronizer::class ); } else { $this->batch_processing_controller->remove_processor( DataSynchronizer::class ); } } /** * Handle the 'woocommerce_feature_enabled_changed' action, * if the custom orders table feature is enabled create the database tables if they don't exist. * * @param string $feature_id The id of the feature that is being enabled or disabled. * @param bool $is_enabled True if the feature is being enabled, false if it's being disabled. */ private function handle_feature_enabled_changed( $feature_id, $is_enabled ): void { if ( 'custom_order_tables' !== $feature_id || ! $is_enabled ) { return; } if ( ! $this->data_synchronizer->check_orders_table_exists() ) { update_option( DataSynchronizer::ORDERS_DATA_SYNC_ENABLED_OPTION, 'no' ); $this->create_custom_orders_tables( false ); } } /** * Handler for the woocommerce_after_register_post_type post, * registers the post type for placeholder orders. * * @return void */ private function register_post_type_for_order_placeholders(): void { wc_register_order_type( DataSynchronizer::PLACEHOLDER_ORDER_POST_TYPE, array( 'public' => false, 'exclude_from_search' => true, 'publicly_queryable' => false, 'show_ui' => false, 'show_in_menu' => false, 'show_in_nav_menus' => false, 'show_in_admin_bar' => false, 'show_in_rest' => false, 'rewrite' => false, 'query_var' => false, 'can_export' => false, 'supports' => array(), 'capabilities' => array(), 'exclude_from_order_count' => true, 'exclude_from_order_views' => true, 'exclude_from_order_reports' => true, 'exclude_from_order_sales_reports' => true, ) ); } }