public static function showAdGroupTree(
        AdWordsServices $adWordsServices,
        AdWordsSession $session,
        $adGroupId
    ) {
        $adGroupCriterionService =
            $adWordsServices->get($session, AdGroupCriterionService::class);

        $children = [];
        $rootNode = null;
        $totalNumEntries = 0;
        $offset = 0;
        do {
            $query = sprintf(
                'SELECT AdGroupId, Id, ParentCriterionId, CaseValue, PartitionType'
                . ' WHERE AdGroupId = %s AND CriteriaType = PRODUCT_PARTITION'
                . ' AND Status IN [ENABLED, PAUSED]',
                $adGroupId
            );
            // Retrieve ad group criteria one page at a time.
            $page = $adGroupCriterionService->query($query);

            // Print out some information for each keyword.
            if ($page->getEntries() !== null) {
                $totalNumEntries = $page->getTotalNumEntries();
                foreach ($page->getEntries() as $adGroupCriterion) {
                    $criterionId = $adGroupCriterion->getCriterion()->getId();
                    if (!array_key_exists($criterionId, $children)) {
                        $children[$criterionId] = [];
                    }

                    if ($adGroupCriterion->getCriterion()->getParentCriterionId()
                        !== null) {
                        $parentCriterionId =
                            $adGroupCriterion->getCriterion()
                                ->getParentCriterionId();
                        $children[$parentCriterionId][] =
                            $adGroupCriterion->getCriterion();
                    } else {
                        $rootNode = $adGroupCriterion->getCriterion();
                    }
                }
            }

            $offset += self::PAGE_LIMIT;
        } while ($offset < $totalNumEntries);

        if ($rootNode === null) {
            return 'Empty tree';
        }

        return self::traverseTree($rootNode, $children, 0);
    }