Chèn bài đánh giá về người bán một cách không đồng bộ

Mã mẫu Merchant API để chèn các bài đánh giá về người bán một cách không đồng bộ.

Java

// Copyright 2025 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package shopping.merchant.samples.reviews.v1beta;

import com.google.api.core.ApiFuture;
import com.google.api.core.ApiFutureCallback;
import com.google.api.core.ApiFutures;
import com.google.api.gax.core.FixedCredentialsProvider;
import com.google.auth.oauth2.GoogleCredentials;
import com.google.common.util.concurrent.MoreExecutors;
import com.google.protobuf.Timestamp;
import com.google.shopping.merchant.reviews.v1beta.InsertMerchantReviewRequest;
import com.google.shopping.merchant.reviews.v1beta.MerchantReview;
import com.google.shopping.merchant.reviews.v1beta.MerchantReviewAttributes;
import com.google.shopping.merchant.reviews.v1beta.MerchantReviewsServiceClient;
import com.google.shopping.merchant.reviews.v1beta.MerchantReviewsServiceSettings;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;
import shopping.merchant.samples.utils.Authenticator;
import shopping.merchant.samples.utils.Config;

/** This class demonstrates how to insert multiple merchant reviews asynchronously. */
public class InsertMerchantReviewsAsyncSample {

  private static String generateRandomString() {
    String characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
    Random random = new Random();
    StringBuilder sb = new StringBuilder(8);
    for (int i = 0; i < 8; i++) {
      sb.append(characters.charAt(random.nextInt(characters.length())));
    }
    return sb.toString();
  }

  // Returns a merchant review with a random ID.
  private static MerchantReview createMerchantReview(String accountId) {
    String merchantReviewId = generateRandomString();

    MerchantReviewAttributes attributes =
        MerchantReviewAttributes.newBuilder()
            .setTitle("Great Merchant!")
            .setContent("Would buy there again.")
            .setMinRating(1)
            .setMaxRating(5)
            .setRating(4)
            .setReviewTime(Timestamp.newBuilder().setSeconds(1731165684).build())
            .setReviewLanguage("en-US")
            .build();

    return MerchantReview.newBuilder()
        .setMerchantReviewId(merchantReviewId)
        .setAttributes(attributes)
        .build();
  }

  public static void asyncInsertMerchantReviews(String accountId, String dataSourceId)
      throws Exception {
    GoogleCredentials credential = new Authenticator().authenticate();

    MerchantReviewsServiceSettings merchantReviewsServiceSettings =
        MerchantReviewsServiceSettings.newBuilder()
            .setCredentialsProvider(FixedCredentialsProvider.create(credential))
            .build();

    try (MerchantReviewsServiceClient merchantReviewsServiceClient =
        MerchantReviewsServiceClient.create(merchantReviewsServiceSettings)) {

      // Arbitrarily creates five merchant reviews with random IDs.
      List<InsertMerchantReviewRequest> requests = new ArrayList<>();
      for (int i = 0; i < 5; i++) {
        InsertMerchantReviewRequest request =
            InsertMerchantReviewRequest.newBuilder()
                .setParent(String.format("accounts/%s", accountId))
                .setMerchantReview(createMerchantReview(accountId))
                // Must be a merchant reviews data source. In other words, a data source whose
                // "type"
                // is MerchantReviewDataSource.
                .setDataSource(String.format("accounts/%s/dataSources/%s", accountId, dataSourceId))
                .build();
        requests.add(request);
      }

      // Inserts the merchant reviews.
      List<ApiFuture<MerchantReview>> futures =
          requests.stream()
              .map(
                  request ->
                      merchantReviewsServiceClient
                          .insertMerchantReviewCallable()
                          .futureCall(request))
              .collect(Collectors.toList());

      // Creates callback to handle the responses when all are ready.
      ApiFuture<List<MerchantReview>> responses = ApiFutures.allAsList(futures);
      ApiFutures.addCallback(
          responses,
          new ApiFutureCallback<List<MerchantReview>>() {
            @Override
            public void onSuccess(List<MerchantReview> results) {
              System.out.println("Inserted merchant reviews below:");
              System.out.println(results);
            }

            @Override
            public void onFailure(Throwable throwable) {
              System.out.println(throwable);
            }
          },
          MoreExecutors.directExecutor());
    } catch (Exception e) {
      System.out.println(e);
    }
  }

  public static void main(String[] args) throws Exception {
    Config config = Config.load();
    asyncInsertMerchantReviews(config.getAccountId().toString(), "YOUR_DATA_SOURCE_ID");
  }
}

PHP

<?php
/**
 * Copyright 2025 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

require_once __DIR__ . '/../../../vendor/autoload.php';
require_once __DIR__ . '/../../Authentication/Authentication.php';
require_once __DIR__ . '/../../Authentication/Config.php';
use GuzzleHttp\Promise\Utils;
use Google\Protobuf\Timestamp;
use Google\Shopping\Merchant\Reviews\V1beta\Client\MerchantReviewsServiceClient;
use Google\Shopping\Merchant\Reviews\V1beta\InsertMerchantReviewRequest;
use Google\Shopping\Merchant\Reviews\V1beta\MerchantReview;
use Google\Shopping\Merchant\Reviews\V1beta\MerchantReviewAttributes;

/**
 * This class demonstrates how to insert multiple merchant reviews asynchronously.
 */
class InsertMerchantReviewsAsyncSample
{
    private const DATA_SOURCE_ID = '<DATA_SOURCE_ID>';

    /**
     * Generates a random string of 8 alphanumeric characters.
     * @return string A random string.
     */
    private static function generateRandomString(): string
    {
        $characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
        $randomString = '';
        $length = 8;
        for ($i = 0; $i < $length; $i++) {
            $randomString .= $characters[random_int(0, strlen($characters) - 1)];
        }
        return $randomString;
    }

    /**
     * Creates a sample MerchantReview object with a random ID.
     * @return MerchantReview A sample MerchantReview object.
     */
    private static function createMerchantReview(): MerchantReview
    {
        $merchantReviewId = self::generateRandomString();

        $attributes = (new MerchantReviewAttributes())
            ->setTitle('Great Merchant!')
            ->setContent('Would buy there again.')
            ->setMinRating(1)
            ->setMaxRating(5)
            ->setRating(4)
            ->setReviewTime(new Timestamp(['seconds' => 1731165684]))
            ->setReviewLanguage('en-US');

        return (new MerchantReview())
            ->setMerchantReviewId($merchantReviewId)
            ->setAttributes($attributes);
    }

    /**
     * Inserts multiple merchant reviews into your Merchant Center account asynchronously.
     *
     * @param array $config The configuration data for authentication and account ID.
     * @param string $dataSourceId The ID of the data source for the reviews.
     */
    public static function asyncInsertMerchantReviewsSample(array $config, string $dataSourceId): void
    {
        // Gets the OAuth credentials to make the request.
        $credentials = Authentication::useServiceAccountOrTokenFile();

        // Creates options config containing credentials for the client to use.
        $options = ['credentials' => $credentials];

        // Creates a client.
        $merchantReviewsServiceClient = new MerchantReviewsServiceClient($options);

        $parent = sprintf('accounts/%s', $config['accountId']);
        $dataSource = sprintf('accounts/%s/dataSources/%s', $config['accountId'], $dataSourceId);

        $insertedReviews = [];
        $errors = [];
        $promises = [];
        // Inserts 5 merchant reviews
        for ($i = 0; $i < 5; $i++) {
            try {
                $merchantReview = self::createMerchantReview();
                $merchantReviewId = $merchantReview->getMerchantReviewId();
                $request = (new InsertMerchantReviewRequest())
                    ->setParent($parent)
                    ->setMerchantReview($merchantReview)
                    ->setDataSource($dataSource);

                printf("Dispatching insert request for Merchant Review ID: %s%s", $merchantReviewId, PHP_EOL);

                // Store the promise, keyed by a unique identifier for this review
                // This helps match responses/errors back to the original request.
                $promises[$merchantReviewId] = $merchantReviewsServiceClient->insertMerchantReviewAsync($request);

            } catch (Exception $e) {
                printf(
                    "Error preparing/dispatching merchant reviews %s",
                    $e->getMessage(),
                    PHP_EOL
                );
            }
        }

        if (empty($promises)) {
            echo "No review insert requests were dispatched." . PHP_EOL;
        } else {
            echo "All review insert requests dispatched. Waiting for responses..." . PHP_EOL;

            // Wait for all the promises to settle (either fulfilled or rejected)
            // Utils::settle() returns an array of results, each with 'state' and 'value' or 'reason'
            $results = Utils::settle($promises)->wait();

            $insertedReviewsResponses = [];
            $errors = [];

            foreach ($results as $merchantReviewId => $result) {

                if ($result['state'] === 'fulfilled') {
                    $response = $result['value']; // This is the actual response object from the API
                    printf("Successfully inserted merchant review ID: %s%s", $merchantReviewId, PHP_EOL);
                    $insertedReviewsResponses[] = $response;
                } elseif ($result['state'] === 'rejected') {
                    $reason = $result['reason']; // This is the exception object
                    printf(
                        "Error inserting merchant review Id: %s. %s",
                        $merchantReviewId,
                        $reason->getMessage(),
                        PHP_EOL
                    );
                    $errors[] = ['reviewId' => $merchantReviewId, 'reason' => $reason];
                }
            }

            // Now $insertedReviewsResponses contains actual successful response objects
            // And $errors contains details about the failed requests.
            printf("Processing complete. Successful inserts: %d, Errors: %d%s", count($insertedReviewsResponses), count($errors), PHP_EOL);
        }
    }

    /**
     * Helper to execute the sample.
     */
    public function callSample(): void
    {
        $config = Config::generateConfig();
        self::asyncInsertMerchantReviewsSample($config, self::DATA_SOURCE_ID);
    }
}

$sample = new InsertMerchantReviewsAsyncSample();
$sample->callSample();