Overview

Namespaces

  • Apptus
    • ESales
      • Connector
        • Report
        • Time
    • Util
      • Cache
  • PHP
  • Overview
  • Namespace
  • Class
  • Tree
  1:   2:   3:   4:   5:   6:   7:   8:   9:  10:  11:  12:  13:  14:  15:  16:  17:  18:  19:  20:  21:  22:  23:  24:  25:  26:  27:  28:  29:  30:  31:  32:  33:  34:  35:  36:  37:  38:  39:  40:  41:  42:  43:  44:  45:  46:  47:  48:  49:  50:  51:  52:  53:  54:  55:  56:  57:  58:  59:  60:  61:  62:  63:  64:  65:  66:  67:  68:  69:  70:  71:  72:  73:  74:  75:  76:  77:  78:  79:  80:  81:  82:  83:  84:  85:  86:  87:  88:  89:  90:  91:  92:  93:  94:  95:  96:  97:  98:  99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143: 144: 145: 146: 147: 148: 149: 150: 151: 152: 153: 154: 155: 156: 157: 158: 159: 160: 161: 162: 163: 164: 165: 166: 167: 168: 169: 170: 171: 172: 173: 174: 175: 176: 177: 178: 179: 180: 181: 182: 183: 184: 185: 186: 187: 188: 189: 190: 191: 192: 193: 194: 195: 196: 197: 198: 199: 200: 201: 202: 203: 204: 205: 206: 207: 208: 209: 210: 211: 212: 213: 214: 215: 216: 217: 218: 219: 220: 221: 222: 223: 224: 225: 226: 227: 228: 229: 230: 231: 232: 233: 234: 235: 236: 237: 238: 239: 240: 241: 242: 243: 244: 245: 246: 247: 248: 249: 250: 251: 252: 253: 254: 255: 256: 257: 258: 259: 260: 261: 262: 263: 264: 265: 266: 267: 268: 269: 270: 271: 272: 273: 274: 275: 276: 277: 278: 279: 280: 281: 282: 283: 284: 285: 286: 287: 288: 289: 290: 291: 292: 293: 294: 295: 296: 297: 298: 299: 300: 301: 302: 303: 304: 305: 306: 307: 308: 309: 310: 311: 312: 313: 314: 315: 316: 317: 318: 319: 320: 321: 322: 323: 324: 325: 326: 327: 328: 329: 330: 331: 332: 333: 334: 335: 336: 337: 338: 339: 340: 341: 342: 343: 344: 345: 346: 347: 348: 349: 350: 351: 352: 353: 354: 355: 356: 357: 358: 359: 360: 361: 362: 363: 364: 365: 366: 367: 368: 369: 370: 371: 372: 373: 374: 375: 376: 377: 378: 379: 380: 381: 382: 383: 384: 385: 386: 387: 388: 389: 390: 391: 392: 393: 394: 395: 396: 397: 398: 399: 400: 401: 402: 403: 404: 405: 406: 407: 408: 409: 410: 411: 412: 413: 414: 415: 416: 417: 418: 419: 420: 421: 422: 423: 424: 425: 426: 427: 428: 429: 430: 431: 432: 433: 434: 435: 436: 437: 438: 439: 440: 441: 442: 443: 444: 445: 446: 447: 448: 449: 450: 451: 452: 453: 454: 455: 456: 457: 458: 459: 460: 461: 462: 463: 464: 465: 466: 467: 468: 469: 470: 471: 472: 473: 474: 475: 476: 477: 478: 479: 480: 481: 482: 483: 484: 485: 486: 487: 488: 489: 490: 491: 492: 493: 494: 495: 496: 497: 498: 499: 500: 501: 502: 503: 504: 505: 506: 507: 508: 509: 510: 511: 512: 513: 514: 515: 516: 517: 518: 519: 520: 521: 522: 523: 524: 525: 526: 527: 528: 529: 530: 531: 532: 533: 534: 535: 536: 537: 538: 539: 540: 541: 542: 543: 544: 545: 546: 547: 548: 549: 550: 551: 552: 553: 554: 555: 556: 557: 558: 559: 560: 561: 562: 563: 564: 565: 566: 567: 568: 569: 570: 571: 572: 573: 574: 575: 576: 577: 578: 579: 580: 581: 582: 583: 584: 585: 586: 587: 588: 589: 590: 591: 592: 593: 594: 595: 596: 597: 598: 599: 600: 601: 602: 603: 604: 605: 606: 607: 608: 609: 610: 611: 612: 613: 614: 615: 616: 617: 618: 619: 620: 621: 622: 623: 624: 625: 626: 627: 628: 629: 630: 631: 632: 633: 634: 635: 636: 637: 638: 639: 640: 641: 
<?php
namespace Apptus\ESales\Connector;

use Apptus\ESales\Connector\Report\AdConversionReport;
use Apptus\ESales\Connector\Report\AdList;
use Apptus\ESales\Connector\Report\AdOrderValueReport;
use Apptus\ESales\Connector\Report\AdPlacementReport;
use Apptus\ESales\Connector\Report\FormatException;
use Apptus\ESales\Connector\Report\PanelConversionReport;
use Apptus\ESales\Connector\Report\ProductSalesByAttributeReport;
use Apptus\ESales\Connector\Report\ProductSalesByTimeReport;
use Apptus\ESales\Connector\Report\ProductTopSellersReport;
use Apptus\ESales\Connector\Report\SearchStatisticsReport;
use Apptus\ESales\Connector\Report\SessionStatisticsReport;
use Apptus\ESales\Connector\Report\SessionSummaryReport;
use Apptus\ESales\Connector\Report\TimelineType;
use Apptus\ESales\Connector\Report\TopSellingSearchesReport;
use Apptus\ESales\Connector\Time\Duration;
use Apptus\ESales\Connector\Time\TimeInterval;
use Apptus\Util\String\ListCodec;

/**
 * A Reporter fetches market-specific reports from an eSales cluster.
 *
 * All reports contains statistical data from a given time interval.
 */
class Reporter {
    private $cluster;
    private $market;
    private $interval;
    /** @var \DateTimeZone */
    private $timeZone;
    private $locale;

    /**
     * Creates a Reporter for the specified cluster, market and time interval.
     * The default locale and time zone is used, unless changed by <code>setLocale</code>
     * and <code>setTimeZone</code>.
     *
     * @internal
     * @param Cluster
     *              The cluster to fetch reports from.
     * @param null|string
     *              The market to fetch reports for.
     * @param \Apptus\ESales\Connector\Time\TimeInterval
     *              The time interval for reports.
     * @throws \InvalidArgumentException if the ini setting date.timezone is not a valid timezone.
     */
    public function __construct(Cluster $cluster, $market, TimeInterval $interval) {
        $this->cluster = $cluster;
        $this->market = $market;
        $this->interval = $interval;

        $this->setTimeZone(null);
        $this->setLocale(null);
    }

    /**
     * Sets the time zone.
     *
     * A time zone defines the beginning of a day. For instance, Sunday 23:30 GMT (London)
     * is the same time as Monday 00:30 GMT+01 (Berlin). Events from that time may be
     * included in statistics for Sunday or Monday, depending on the time zone specified
     * (Europe/London or Europe/Berlin).
     *
     * The default time zone is <code>ini_get('date.timezone')</code> or <code>'UTC'</code>
     * if <code>date.timezone</code> is not configured.
     *
     * @param null|string|\DateTimeZone
     *            A string with the name of a {@link http://php.net/manual/en/timezones.php supported timezone} or a DateTimeZone object.
     *            Use null to set to default timezone.
     * @throws \InvalidArgumentException if the given timezone is invalid.
     */
    public function setTimeZone($timeZone) {
        if ($timeZone === null) {
            $timeZone = ini_get('date.timezone');
            $timeZone = ($timeZone === false || $timeZone === '') ? 'UTC' : $timeZone;
        }
        if (is_string($timeZone)) {
            $timeZone = timezone_open($timeZone);
        }
        if ($timeZone instanceof \DateTimeZone) {
            $this->timeZone = $timeZone;
        } else {
            throw new \InvalidArgumentException('Invalid time zone.');
        }
    }

    /**
     * Sets the locale.
     *
     * A locale defines the beginning of a week and what week is the first of the year.
     * For instance, in the U.S., the week starts on Sunday, while in Germany, it starts
     * on Monday. Events from a Sunday may be included in different weeks, depending on
     * the locale specified (en_US or de_DE).
     *
     * The default locale depends on whether the intl extension is loaded or not.
     * If it is loaded, locale defaults to a best guess of client locale based on the
     * HTTP "Accept-Language" header or to the ini setting 'intl.default_locale' if the
     * header is not sent. If the intl extension is not loaded, locale defaults to 'sv_SE'
     * which use ISO 8601 standard week rules, i.e. week starts on Monday and the first
     * week of the year has at least 4 days.

     * @param null|string
     *            A string with the name of a locale. E.g. 'en_US' or 'sv_SE'.
     *            Use null to set to default.
     */
    public function setLocale($locale) {
        if ($locale === null) {
            if (extension_loaded('intl')) {
                if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
                    $locale = locale_accept_from_http($_SERVER['HTTP_ACCEPT_LANGUAGE']);
                } else {
                    $locale = locale_get_default();
                }
            } else {
                $locale = 'sv_SE';
            }
        }
        $this->locale = $locale;
    }

    private function defaultArgs(ArgMap $args) {
        if ($this->market !== null) {
            $args->put('market', $this->market);
        }
        $args->put('time_interval', $this->interval);
        $args->put('time_zone', $this->timeZone->getName());
        $args->put('locale', $this->locale);
    }

    /**
     * Fetches an {@see AdList} of ads that are active during the selected time range.
     *
     * All attributes for the ads are available in the report together with click through rate and conversion rate.
     * The ads in the report are selected by an incremental search and sorted according to the supplied sortBy and locale arguments.
     *
     * @param string
     *            The phrase to incrementally find ads, all ad attributes will be used in the search.
     * @param string
     *            The sort by order for the ads.
     *
     *            Available sort by values:
     *            <ul>
     *                <li>ad_key [asc|desc]</li>
     *                <li>ctr [asc|desc]</li>
     *                <li>conversion [asc|desc]</li>
     *                <li><i>any ad attribute</i> [asc|desc]</li>
     *            </ul>
     * @throws ReportException if there is a problem with fetching or parsing the report.
     * @return AdList
     *            An AdList containing ads with attributes, click through rate and conversion.
     */
    public function adList($phrase, $sortBy) {
        $args = new ArgMap();

        if ($phrase !== null) {
            $args->put('phrase', $phrase);
        }

        if ($sortBy !== null) {
            $args->put('sort_by', $sortBy);
        }

        $this->defaultArgs($args);

        try {
            $response = $this->cluster->queryReport('/ad_list', $args);
            return AdList::parse($response, $this->timeZone);
        } catch (ClusterUnavailableException $e) {
            throw new ReportException('Cannot get ad list.', $e);
        } catch (FormatException $e) {
            throw new ReportException('Cannot get ad list.', $e);
        }
    }

    /**
     * Fetches an {@see AdConversionReport} for the ads specified as argument.
     *
     * The report contains one section for each ad and each sections contains the following information:
     * <ul>
     * <li>All attributes for the ad</li>
     * <li>A timeline with conversion rate for visits that has seen the ad</li>
     * <li>A timeline with conversion rate for visits that has <b>not</b> seen the ad</li>
     * <li>A timeline with conversion rate for the campaign that the ad is part of</li>
     * <li>An average conversion rate for the campaign that the ad is part of</li>
     * </ul>
     *
     * @param array
     *            The ad keys to include in the report.
     * @param Duration
     *            The resolution to use when the report is aggregated.
     * @throws ReportException if there is a problem with fetching or parsing the report.
     * @throws \InvalidArgumentException if there is a problem with the arguments.
     * @return AdConversionReport
     *            An AdConversionReport.
     */
    public function adConversion(array $adKeys, Duration $resolution) {
        if (count($adKeys) === 0) {
            throw new \InvalidArgumentException('Illegal value for argument adKeys.');
        }

        $c = new ListCodec();

        $args = new ArgMap();
        $args->put('ad_keys', $c->encodeList($adKeys));
        $args->put('resolution', $resolution);
        $this->defaultArgs($args);

        try {
            $response = $this->cluster->queryReport('/ad_conversion', $args);
            return AdConversionReport::parse($response, $this->timeZone);
        } catch (ClusterUnavailableException $e) {
            throw new ReportException('Cannot get ad conversion report.', $e);
        } catch (FormatException $e) {
            throw new ReportException('Cannot get ad conversion report.', $e);
        }
    }

    /**
     * Fetches an {@see AdPlacementReport} for the ads specified as argument.
     *
     * The report contains one section for each ad and each sections contains the following information:
     * <ul>
     * <li>All attributes for the ad</li>
     * <li>A list of {@see Placement} containing click, display, click through rate and path information for where the ad has been displayed</li>
     * </ul>
     *
     * @param array
     *            The ad keys to include in the report.
     * @throws ReportException if there is a problem with fetching or parsing the report.
     * @throws \InvalidArgumentException if there is a problem with the arguments.
     * @return AdPlacementReport
     *            An AdPlacementReport.
     */
    public function adPlacement(array $adKeys) {
        if (count($adKeys) == 0) {
            throw new \InvalidArgumentException('Illegal value for argument adKeys.');
        }

        $c = new ListCodec();

        $args = new ArgMap();
        $args->put('ad_keys', $c->encodeList($adKeys));
        $this->defaultArgs($args);

        try {
            $response = $this->cluster->queryReport('/ad_placement', $args);
            return AdPlacementReport::parse($response, $this->timeZone);
        } catch (ClusterUnavailableException $e) {
            throw new ReportException('Cannot get ad placement report.', $e);
        } catch (FormatException $e) {
            throw new ReportException('Cannot get ad placement report.', $e);
        }
    }

    /**
     * Fetches an {@see AdOrderValueReport} for the ads specified as argument.
     *
     * The report contains one section for each ad and each sections contains the following information:
     * <ul>
     * <li>All attributes for the ad</li>
     * <li>A timeline with click through rate for the ad</li>
     * <li>A timeline with average order value for the ad</li>
     * </ul>
     *
     * @param array
     *            The ad keys to include in the report.
     * @param \Apptus\ESales\Connector\Report\TimelineType
     *            The timeline type to use when the report is fetched.
     * @throws ReportException if there is a problem with fetching or parsing the report.
     * @throws \InvalidArgumentException if there is a problem with the arguments.
     * @return AdOrderValueReport
     *            An AdOrderValueReport.
     */
    public function adOrderValue(array $adKeys, TimelineType $timelineType) {
        if (count($adKeys) == 0) {
            throw new \InvalidArgumentException('Illegal value for argument adKeys.');
        }

        $c = new ListCodec();

        $args = new ArgMap();
        $args->put('ad_keys', $c->encodeList($adKeys));
        $args->put('timeline_type', $timelineType);
        $this->defaultArgs($args);

        try {
            $response = $this->cluster->queryReport('/ad_order_value', $args);
            return AdOrderValueReport::parse($response, $this->timeZone);
        } catch (ClusterUnavailableException $e) {
            throw new ReportException('Cannot get ad order value report.', $e);
        } catch (FormatException $e) {
            throw new ReportException('Cannot get ad order value report.', $e);
        }
    }


    /**
     * Fetches a {@see PanelConversionReport} for the supplied panel and all of the sub panels.
     *
     * The report contains one section for each public panel path, sorted alphabetically, and each sections contains the following information:
     * <ul>
     * <li>Number of displays</li>
     * <li>Number of clicks</li>
     * <li>Number of items added to cart that were later purchased or abandoned</li>
     * <li>Number of items added to cart that were later purchased</li>
     * <li>Click through rate</li>
     * <li>Adding to cart rate</li>
     * <li>Payment rate</li>
     * <li>Interest rate</li>
     * </ul>
     *
     * @param string
     *            The public panel path to fetch the report for.
     * @throws ReportException if there is a problem with fetching or parsing the report.
     * @throws \InvalidArgumentException if there is a problem with the arguments.
     * @return PanelConversionReport
     * @deprecated For CloudConnector, please use apps.
     *            A PanelConversionReport.
     */

    public function panelConversion($panelPath) {
        $panelPath = (string) $panelPath;
        if (strlen($panelPath) === 0) {
            throw new \InvalidArgumentException('Illegal value for argument panelPath.');
        }

        $args = new ArgMap();
        $args->put('panel', $panelPath);
        $this->defaultArgs($args);

        try {
            $response = $this->cluster->queryReport('/panel_conversion', $args);
            return PanelConversionReport::parse($response, $this->timeZone);
        } catch (ClusterUnavailableException $e) {
            throw new ReportException('Cannot get panel conversion report.', $e);
        } catch (FormatException $e) {
            throw new ReportException('Cannot get panel conversion report.', $e);
        }
    }

    /**
     * Fetches a {@see SessionStatisticsReport} presented with the supplied resolution.
     *
     * The report contains a timeline of {@see SessionStatistics}
     *
     * @param Duration
     *            The resolution to use when the report is aggregated.
     * @throws ReportException if there is a problem with fetching or parsing the report.
     * @return SessionStatisticsReport
     *            A SessionStatisticsReport.
     */
    public function sessionStatistics(Duration $resolution) {
        $args = new ArgMap();
        $args->put('resolution', $resolution);
        $this->defaultArgs($args);

        try {
            $response = $this->cluster->queryReport('/session_statistics', $args);
            return SessionStatisticsReport::parse($response, $this->timeZone);
        } catch (ClusterUnavailableException $e) {
            throw new ReportException('Cannot get session statistics report.', $e);
        } catch (FormatException $e) {
            throw new ReportException('Cannot get session statistics report.', $e);
        }
    }

    /**
     * Fetches a {@see SessionSummaryReport} containing performance summary information for the whole site.
     *
     * The summary contains:
     * <ul>
     * <li>Bounce rate</li>
     * <li>Number of visits</li>
     * <li>Number of orders</li>
     * <li>Conversion rate</li>
     * </ul>

     * @throws ReportException if there is a problem with fetching or parsing the report.
     * @return SessionSummaryReport
     *            A SessionSummaryReport.
     */
    public function sessionSummary() {
        $args = new ArgMap();
        $this->defaultArgs($args);

        try {
            $response = $this->cluster->queryReport('/session_summary', $args);
            return SessionSummaryReport::parse($response, $this->timeZone);
        } catch (ClusterUnavailableException $e) {
            throw new ReportException('Cannot get session summary report.', $e);
        } catch (FormatException $e) {
            throw new ReportException('Cannot get session summary report.', $e);
        }
    }

    /**
     * Fetches a {@see SearchStatisticsReport}.
     *
     * The report contains:
     * <ul>
     * <li>A ratio for the number of searches that results in a hit.</li>
     * <li>A ratio for the number of searches that results in a no hit.</li>
     * <li>A list of the 100 most popular search phrases that results in a hit.</li>
     * <li>A list of the 100 most popular search phrases that results in a no hit.</li>
     * <li>A list of the 100 search phrases with the highest positive impact on the total conversion rate.</li>
     * <li>A list of the 100 search phrases with the highest negative impact on the total conversion rate.</li>
     * </ul>
     *
     * @throws ReportException if there is a problem with fetching or parsing of the report.
     * @return SearchStatisticsReport
     *            A SearchStatisticsReport.
     */
   public function searchStatistics() {
        $args = new ArgMap();
        $this->defaultArgs($args);

        try {
            $response = $this->cluster->queryReport('/search_statistics', $args);
            return SearchStatisticsReport::parse($response, $this->timeZone);
        } catch (ClusterUnavailableException $e) {
            throw new ReportException('Cannot get search statistics report.', $e);
        } catch (FormatException $e) {
            throw new ReportException('Cannot get search statistics report.', $e);
        }
    }

    /**
     * Fetches a {@see ProductSalesByAttributeReport}.
     * The report is aggregated by facet values for the given attribute or a summary if the attribute is <i>null</i>.
     * <p>The report contains a section for each facet value. Each section contains:</p>
     * <ul>
     * <li>Name of the facet value.</li>
     * <li>The total number of purchased products and variants that has this facet value and matches the filter.</li>
     * <li>The total number of abandoned products and variants that has this facet value and matches the filter.</li>
     * <li>The total discount for the products and variants that has this facet value and matches the filter.</li>
     * <li>The total margin for the products and variants that has this facet value and matches the filter.</li>
     * <li>The total revenue for the products and variants that has this facet value and matches the filter.</li>
     * </ul>
     *
     * @param string|null The filter attribute to find facet values for.
     * @param Filter|null Together with facets, the set of products and variant to create the report for.
     * @param string|null The sort order for the report.
     *               <p>Available sort by values:</p>
     *               <ul>
     *               <li>purchased_units [asc|desc]</li>
     *               <li>abandoned_units [asc|desc]</li>
     *               <li>discount [asc|desc]</li>
     *               <li>margin [asc|desc]</li>
     *               <li>revenue [asc|desc]</li>
     *               <li>attribute [asc|desc]</li>
     *               </ul>
     * @param Facets|null Together with filter, the set of products and variant to create the report for. New since 3.7.0.
     * @return ProductSalesByAttributeReport
     *            A {@see ProductSalesByAttributeReport}.
     * @throws ReportException if there is a problem with fetching or parsing the report.
     * @since 3.4.0
     */
    public function productSalesByAttribute($attribute, Filter $filter = null, $sortBy, Facets $facets = null) {
        $args = new ArgMap();
        $this->defaultArgs($args);

        if ($attribute !== null) {
            $args->put('attribute', $attribute);
        }
        if ($filter !== null) {
            $args->put('filter', $filter);
        }
        if ($facets !== null) {
            $args->put('facets', $facets);
        }
        if ($sortBy !== null) {
            $args->put('sort_by', $sortBy);
        }

        try {
            $response = $this->cluster->queryReport('/product_sales_by_attribute', $args);
            return ProductSalesByAttributeReport::parse($response, $this->timeZone);
        } catch (ClusterUnavailableException $e) {
            throw new ReportException('Cannot get product sales by attribute report.', $e);
        } catch (FormatException $e) {
            throw new ReportException('Cannot get product sales by attribute report.', $e);
        }
    }

    /**
     * Fetches a {@see ProductSalesByTimeReport}.
     * The report contains sales statistics aggregated according to the supplied timeline type.
     * The report aggregates data for all products and variant that matches the filter and the facets.
     * <p>The report contains timelines for the following metrics:</p>
     * <ul>
     * <li>The number of purchased products and variants purchased during the timeslot.</li>
     * <li>The number of abandoned products and variants abandoned during the timeslot</li>
     * <li>The discount for the products and variants purchased during the timeslot.</li>
     * <li>The margin for the products and variants purchased during the timeslot.</li>
     * <li>The revenue for the products and variants purchased during the timeslot.</li>
     * </ul>
     *
     * @param \Apptus\ESales\Connector\Report\TimelineType
     *              The timeline type to use for this report.
     * @param Filter|null
     *              Together with Facets, the set of products and variant to create the report for.
     * @param Facets|null
     *              Together with Filter, the set of products and variant to create the report for. New since 3.7.0
     * @throws ReportException if there is a problem with fetching or parsing of the report.
     * @return ProductSalesByTimeReport
     *            A {@see ProductSalesByTimeReport}
     * @since 3.4.0
     */
    public function productSalesByTime(TimelineType $timelineType, Filter $filter = null, Facets $facets = null) {
        $args = new ArgMap();
        $this->defaultArgs($args);

        $args->put('timeline_type', $timelineType);

        if ($filter !== null) {
            $args->put('filter', $filter);
        }

        if ($facets !== null) {
            $args->put('facets', $facets);
        }
        try {
            $response = $this->cluster->queryReport('/product_sales_by_time', $args);
            return ProductSalesByTimeReport::parse($response, $this->timeZone);
        } catch (ClusterUnavailableException $e) {
            throw new ReportException('Cannot get product sales by time report.', $e);
        } catch (FormatException $e) {
            throw new ReportException('Cannot get product sales by time report.', $e);
        }
    }

    /**
     * Fetches a {@see ProductTopSellersReport}.
     * The report contains sales statistics for the best products and variants that matches the filter and facets.
     * The report is sorted according to the specified <i>sort by</i> order.
     * <p>The report contains a list of sections, each containing the following values:</p>
     * <ul>
     * <li>The product key.</li>
     * <li>The variant key or an empty String if it is a product.</li>
     * <li>The number of purchases during the time interval.</li>
     * <li>The number of abandonment during the time interval.</li>
     * <li>The total discount for the item during the time interval.</li>
     * <li>The total margin for the item during the time interval.</li>
     * <li>The total revenue for the item during the time interval.</li>
     * </ul>
     *
     * @param Filter|null Together with Facets, the set of products and variant to consider when the top list is created.
     * @param string|null The sort order for the report.
     *               <p>Available sort by values:</p>
     *               <ul>
     *               <li>purchased_units [asc|desc]</li>
     *               <li>abandoned_units [asc|desc]</li>
     *               <li>discount [asc|desc]</li>
     *               <li>margin [asc|desc]</li>
     *               <li>revenue [asc|desc]</li>
     *               </ul>
     * @param int
     *              The first position, inclusive, to be present in the report. The first position is 1.
     * @param int
     *              The last position, inclusive, to be present in the report.
     * @param Facets|null Together with Filter, the set of products and variant to consider when the top list is created. New since 3.7.0
     * @return ProductTopSellersReport
     *            A {@see ProductTopSellersReport}.
     * @throws ReportException if there is a problem with fetching or parsing of the report.
     * @since 3.4.0
     */
    public function productTopSellers(Filter $filter, $sortBy, $windowFirst, $windowLast, Facets $facets = null) {
        $args = new ArgMap();
        $this->defaultArgs($args);

        if ($filter !== null) {
            $args->put('filter', $filter);
        }
        if ($facets !== null) {
            $args->put('facets', $facets);
        }
        if ($sortBy !== null) {
            $args->put('sort_by', $sortBy);
        }

        $args->put('window_first', $windowFirst);
        $args->put('window_last', $windowLast);

        try {
            $response = $this->cluster->queryReport('/product_top_sellers', $args);
            return ProductTopSellersReport::parse($response, $this->timeZone);
        } catch (ClusterUnavailableException $e) {
            throw new ReportException('Cannot get product top sellers report.', $e);
        } catch (FormatException $e) {
            throw new ReportException('Cannot get product top sellers report.', $e);
        }
    }

    /**
     * Fetches a {@see TopSellingSearchesReport}.
     * The report contains a top list of search phrases associated with the products and variants that matches the filter and the facets.
     * The report is sorted by the total number of purchases, of products and variants that matches the filter and the facets, that the search phrases can be associated with.
     * <p>
     * The report contains a list of sections, each containing a search phrase and the number of times the search phrase has lead
     * to a purchase of a product or variant that matches the filter and the facets.
     * </p>
     * @param Filter|null Together with Facets, the set of products and variant to consider when the top list is created.
     * @param int
     *              The first position, inclusive, to be present in the report. The first position is 1.
     * @param int
     *              The last position, inclusive, to be present in the report.
     * @param Facets|null Together with Filter, the set of products and variant to consider when the top list is created. New since 3.7.0
     *
     * @return TopSellingSearchesReport
     *            A {@see TopSellingSearchesReport}.
     * @throws ReportException if there is a problem with fetching or parsing of the report.
     * @since 3.5.0
     */
    public function topSellingSearches(Filter $filter = null, $windowFirst, $windowLast, Facets $facets = null) {
        $args = new ArgMap();
        $this->defaultArgs($args);

        if ($filter !== null) {
            $args->put('filter', $filter);
        }

        if ($facets !== null) {
            $args->put('facets', $facets);
        }

        $args->put('window_first', $windowFirst);
        $args->put('window_last', $windowLast);

        try {
            $response = $this->cluster->queryReport('/top_selling_searches', $args);
            return TopSellingSearchesReport::parse($response, $this->timeZone);
        } catch (ClusterUnavailableException $e) {
            throw new ReportException('Cannot get report for top selling searches.', $e);
        } catch (FormatException $e) {
            throw new ReportException('Cannot get report for top selling searches.', $e);
        }
    }
}
Apptus ESales Connector PHP API documentation generated by ApiGen