googleads / google-ads-php

Google Ads API Client Library for PHP
https://developers.google.com/google-ads/api/docs/client-libs/php
Apache License 2.0
291 stars 260 forks source link

Pagination with #499

Closed chrisooo3 closed 3 years ago

chrisooo3 commented 3 years ago

Hi, I am trying to do the pagination with google-ads-php like here: image

So this is my code:

    public function runExample(GoogleAdsClient $googleAdsClient, int $customerId)
    {
        $googleAdsServiceClient = $googleAdsClient->getGoogleAdsServiceClient();
        // Creates a query that retrieves all ads.
        $query = "SELECT campaign.name, ad_group.name, "
            . "ad_group_ad.ad.responsive_display_ad.marketing_images, "
            . "ad_group_ad.ad.app_ad.images, ad_group_ad.ad.app_ad.youtube_videos, "
            . "ad_group_ad.ad.responsive_display_ad.youtube_videos, ad_group_ad.ad.local_ad.videos, "
            . "ad_group_ad.ad.video_responsive_ad.videos, ad_group_ad.ad.video_ad.media_file,  "
            . "ad_group_ad.ad.app_engagement_ad.images, ad_group_ad.ad.app_engagement_ad.videos, "
            . "ad_group_ad.ad.display_upload_ad.media_bundle, ad_group_ad.ad.gmail_ad.product_images, "
            . "ad_group_ad.ad.gmail_ad.product_videos, ad_group_ad.ad.gmail_ad.teaser.logo_image, "
            . "ad_group_ad.ad.image_ad.image_url, ad_group_ad.ad.legacy_responsive_display_ad.square_marketing_image, "
            . "ad_group_ad.ad.local_ad.marketing_images, ad_group_ad.ad.responsive_display_ad.logo_images, "
            . "ad_group_ad.ad.responsive_display_ad.square_logo_images, "
            . "ad_group_ad.ad.responsive_display_ad.square_marketing_images, "
            . "ad_group_ad.ad.responsive_display_ad.youtube_videos, "
            . "metrics.impressions, campaign.campaign_budget, campaign.status, "
            . "campaign.start_date, campaign.end_date, metrics.all_conversions, "
            . "metrics.average_cost, ad_group_ad.ad.type, ad_group_ad.ad.id, "
            . "campaign.campaign_budget, metrics.cost_micros, ad_group_ad.status, metrics.impressions "
            . "FROM ad_group_ad "
            . "WHERE segments.date >= '{$this->from}' AND segments.date <= '{$this->to}' "
            . "ORDER BY campaign.name ASC";

        // Issues a search stream request.
        /** @var GoogleAdsServerStreamDecorator $stream */
        $stream = $googleAdsServiceClient->search($customerId, $query, ['pageSize' => 10]);
        $ads = [];
        foreach ($stream->iterateAllElements() as $googleAdsRow) {
            dump($googleAdsRow->serializeToJsonString());
            /** @var GoogleAdsRow $googleAdsRow */
            $ads[] = json_decode($googleAdsRow->serializeToJsonString(), true);
        }

As you see the pageSize is set to 10, so it will be 23 pages, because I have 230 ads.

How can I do the pagination, now the $stream returns all ads in one response. How can return only 10 ads, and then when user click for example second page button, it will return the next 10 ads, and so on?

Thanks in advance!

chiragvels commented 3 years ago

Hi @chrisooo3 ,

I think you need to use search option instead search stream.

https://developers.google.com/google-ads/api/docs/reporting/streaming#search_vs_searchstream

If you have an app that requires paging, Search may be a better choice since it does not require downloading the entire result set, while streaming would require downloading it entirely. Also, if a stream is interrupted or experiences a failure in the middle of a download, your platform would have to restart the entire download again from the beginning.

Thanks,

chrisooo3 commented 3 years ago

Ok so my code looks like this, after your advice:

    public function runExample(GoogleAdsClient $googleAdsClient, int $customerId)
    {
        $googleAdsServiceClient = $googleAdsClient->getGoogleAdsServiceClient();
        // Creates a query that retrieves all ads.
        $query = "SELECT campaign.name, ad_group.name, "
            . "ad_group_ad.ad.responsive_display_ad.marketing_images, "
            . "ad_group_ad.ad.app_ad.images, ad_group_ad.ad.app_ad.youtube_videos, "
            . "ad_group_ad.ad.responsive_display_ad.youtube_videos, ad_group_ad.ad.local_ad.videos, "
            . "ad_group_ad.ad.video_responsive_ad.videos, ad_group_ad.ad.video_ad.media_file,  "
            . "ad_group_ad.ad.app_engagement_ad.images, ad_group_ad.ad.app_engagement_ad.videos, "
            . "ad_group_ad.ad.display_upload_ad.media_bundle, ad_group_ad.ad.gmail_ad.product_images, "
            . "ad_group_ad.ad.gmail_ad.product_videos, ad_group_ad.ad.gmail_ad.teaser.logo_image, "
            . "ad_group_ad.ad.image_ad.image_url, ad_group_ad.ad.legacy_responsive_display_ad.square_marketing_image, "
            . "ad_group_ad.ad.local_ad.marketing_images, ad_group_ad.ad.responsive_display_ad.logo_images, "
            . "ad_group_ad.ad.responsive_display_ad.square_logo_images, "
            . "ad_group_ad.ad.responsive_display_ad.square_marketing_images, "
            . "ad_group_ad.ad.responsive_display_ad.youtube_videos, "
            . "metrics.impressions, campaign.campaign_budget, campaign.status, "
            . "campaign.start_date, campaign.end_date, metrics.all_conversions, "
            . "metrics.average_cost, ad_group_ad.ad.type, ad_group_ad.ad.id, "
            . "campaign.campaign_budget, metrics.cost_micros, ad_group_ad.status, metrics.impressions "
            . "FROM ad_group_ad "
            . "WHERE segments.date >= '{$this->from}' AND segments.date <= '{$this->to}' "
            . "ORDER BY campaign.name ASC";

        // Issues a search stream request.
        /** @var GoogleAdsServerStreamDecorator $stream */
        $stream = $googleAdsServiceClient->search($customerId, $query, ['pageSize' => 10]);
        $ads = [];
        foreach ($stream->iterateAllElements() as $googleAdsRow) {
            dump($googleAdsRow->serializeToJsonString());
            /** @var GoogleAdsRow $googleAdsRow */
            $ads[] = json_decode($googleAdsRow->serializeToJsonString(), true);
        }

What should I do know? Currently the result is the same, so it is returning all ads in one response. How can I return only one chunk of ads, and then on the click of the button next next chunk?

chiragvels commented 3 years ago

Hi @chrisooo3,

I didn't noticed you are using search only.

/* @var GoogleAdsServerStreamDecorator $stream / $stream = $googleAdsServiceClient->search($customerId, $query, ['pageSize' => 10]);

You need to do some change in your code like advised here .

Thanks,

chrisooo3 commented 3 years ago

Thanks, so my code looks like this right now:

        $googleAdsServiceClient = $googleAdsClient->getGoogleAdsServiceClient();
        // Creates a query that retrieves all ads.
        $query = "SELECT campaign.name, ad_group.name, "
            . "ad_group_ad.ad.responsive_display_ad.marketing_images, "
            . "ad_group_ad.ad.app_ad.images, ad_group_ad.ad.app_ad.youtube_videos, "
            . "ad_group_ad.ad.responsive_display_ad.youtube_videos, ad_group_ad.ad.local_ad.videos, "
            . "ad_group_ad.ad.video_responsive_ad.videos, ad_group_ad.ad.video_ad.media_file,  "
            . "ad_group_ad.ad.app_engagement_ad.images, ad_group_ad.ad.app_engagement_ad.videos, "
            . "ad_group_ad.ad.display_upload_ad.media_bundle, ad_group_ad.ad.gmail_ad.product_images, "
            . "ad_group_ad.ad.gmail_ad.product_videos, ad_group_ad.ad.gmail_ad.teaser.logo_image, "
            . "ad_group_ad.ad.image_ad.image_url, ad_group_ad.ad.legacy_responsive_display_ad.square_marketing_image, "
            . "ad_group_ad.ad.local_ad.marketing_images, ad_group_ad.ad.responsive_display_ad.logo_images, "
            . "ad_group_ad.ad.responsive_display_ad.square_logo_images, "
            . "ad_group_ad.ad.responsive_display_ad.square_marketing_images, "
            . "ad_group_ad.ad.responsive_display_ad.youtube_videos, "
            . "metrics.impressions, campaign.campaign_budget, campaign.status, "
            . "campaign.start_date, campaign.end_date, metrics.all_conversions, "
            . "metrics.average_cost, ad_group_ad.ad.type, ad_group_ad.ad.id, "
            . "campaign.campaign_budget, metrics.cost_micros, ad_group_ad.status, metrics.impressions "
            . "FROM ad_group_ad "
            . "WHERE segments.date >= '{$this->from}' AND segments.date <= '{$this->to}' "
            . "ORDER BY campaign.name ASC ";

        $stream = $googleAdsServiceClient->search($customerId, $query, ['pageSize' => 5])->getPage();
        $nextToken = $stream->getNextPageToken();
        $total = $stream->getResponseObject()->getTotalResultsCount();
        $ads = [];
        foreach ($stream->getIterator() as $googleAdsRow) {
            /** @var GoogleAdsRow $googleAdsRow */
            dump($googleAdsRow->serializeToJsonString());
            $ads[] = json_decode($googleAdsRow->serializeToJsonString(), true);
        }

1) Why after dumping the $total I get 0? 2) I see method getNextPageToken() but I do not see method getPreviousePageToken(). How to go back in the results?

chiragvels commented 3 years ago

Hi @chrisooo3 ,

  1. Why after dumping the $total I get 0?

This should be total number of records

  1. I see method getNextPageToken() but I do not see method getPreviousePageToken(). How to go back in the results?

No idea about this. But next page token would suffice enough to get you result based on page id and no of records per page.

API team would give you more info on this. You can ask on forum here.

Thanks,

chrisooo3 commented 3 years ago

1) So there is a bug, because, it is returning 0. 2) So how can I move back in my paging?

PierrickVoulet commented 3 years ago

Hi @chrisooo3 - Let me clarify a few things:

  1. You can use both search or searchStream methods to download the results of search queries. The search method provides pagination but only to facilitate the breakdown and download of the results. For GUI pagination widgets, you will need to download and cache all the results. We developed a Laravel application that does just that in case you are interested to take a look.
  2. As previously mentioned (thank you @chiragvels for helping!), you can retrieve the total number of results using search, here is complete and working example that illustrates how to do so. Looking at your last version of your code, I believe you should use ['pageSize' => 5, 'returnTotalResultsCount' => true] instead of ['pageSize' => 5] to make it return something else than 0.

Thanks,

chrisooo3 commented 3 years ago

Hi, thanks for answer. 1) So what is the point of doing this type of pagination? As I know the pagination is for improving time for waiting for the results from the query. Here we are fetching all by once, so why we need pagination?

2) In google ads platform they have pagination that do not fetch all ads by once. How it is done?

PierrickVoulet commented 3 years ago
  1. The primary purpose of the example is to illustrate how to integrate with Laravel, this is not a production-grade implementation. As you said, search pagination helps with performance. Our library only reflects what is provided by the Google Ads API, I recommend you contact their dedicated support as your feedback is valuable.
  2. Not sure what you are referring to, do they use our library? If they do, could you give more details otherwise I suggest you contact them to gather more information.
chrisooo3 commented 3 years ago
  1. So how to improve performance with search? How to make pagination buttons with search? How to go to previous page(to next you have shown that we have to use nextPageToken?
  2. I do not know if they use, are you one team with them?
fiboknacky commented 3 years ago

I do not know if they use, are you one team with them?

I guess you mean the Google Ads UI, right? We're a different team. Although the underlying data are the same, the API used to build that application is different from the publicly available Google Ads API.

chrisooo3 commented 3 years ago

@fiboknacky what are the key differences between your lib and google ads API? Where I can find the documentation about your library?

fiboknacky commented 3 years ago

It seems you're confused with my explanation. Sorry about that. Let me explain again.

This library is a client library of the Google Ads API. In other words, it's a PHP library that allows you to use the Google Ads API. The public documentation, apart from that available in README, can be found here. The Google Ads UI is another thing. It's not backed directly by the publicly available Google Ads API.

chrisooo3 commented 3 years ago

@fiboknacky Ok, thanks for the response.

So to summarize, could you answer the question? How to do the pagination with Google Ads PHP lib? Your colleague @PierrickVoulet only mentioned how to go forward with results? We still do not know how to go backwards with results?

PierrickVoulet commented 3 years ago

@chrisooo3 The only way is to download and cache the results. This is because the pagination feature provided with the GoogleAdsService.Search API method is only used for technical purposes (see the related Google Ads API guide), not as a convenience for Graphical User Interfaces. Our client library basically reflects what is provided by the Google Ads API here.

This does not mean that this paging feature of the Google Ads API could not be improved though. Like with any feedback or suggestion on how to improve the Google Ads API, do not hesitate to reach out to their dedicated support so it is taken into account.

PierrickVoulet commented 2 years ago

We updated the Laravel code example in #696 to illustrate how pages of results can be lazily loaded to avoid caching all results. It's a bit more complex to implement but it's helpful if you need to optimize time and memory when working with large sets of results.