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);
}
}
}