You are here

abstract class AcquiaLiftReportBase in Acquia Lift Connector 7

Base class providing report data loading functionality common to all Acquia Lift Reports.

Hierarchy

Expanded class hierarchy of AcquiaLiftReportBase

File

plugins/agent_types/AcquiaLiftAgent.inc, line 1156
Provides an agent type for Acquia Lift

View source
abstract class AcquiaLiftReportBase implements PersonalizeAgentReportInterface, AcquiaLiftReportInterface {

  /**
   * The value to show when report data is not applicable.
   */
  const DATA_NA = '—';

  /**
   * The value representing no features applied to an experiment.
   */
  const NO_FEATURES = '(none)';

  /**
   * The Acquia Lift agent instance for reporting on.
   *
   * @var AcquiaLiftAgent
   */
  protected $agent;

  /**
   * An instance of AcquiaLiftAPI.
   *
   * @var AcquiaLiftAPI
   */
  protected $liftAPI;

  /**
   * The confidence measure for determining statistical significance.
   */
  protected $confidence_measure = 95;

  /**
   * The extracted report data for each of the Acquia Lift API calls keyed
   * by date/feature set requested.
   *
   * @var array;
   */
  protected $report_data;

  /**
   * Constructs an AcquiaLiftReport object
   *
   * @param PersonalizeAgentInterface $agent
   *   The agent the report is for.
   *
   * @param AcquiaLiftReportDataSourceInterface $report_data_src
   *   The source for the report data.
   */
  function __construct(PersonalizeAgentInterface $agent, AcquiaLiftReportDataSourceInterface $report_data_src) {
    $this->agent = $agent;
    $this->reportDataSrc = $report_data_src;
  }

  /**
   * Implements AcquiaLiftReportInterface()::getConfidenceMeasure().
   */
  public function getConfidenceMeasure() {
    return $this->confidence_measure;
  }

  /**
   * Implements AcquiaLiftReportInterface()::setConfidenceMeasure().
   */
  public function setConfidenceMeasure($value) {
    if ($value < 0) {
      $value = 0;
    }
    if ($value > 100) {
      $value = 100;
    }
    $this->confidence_measure = $value;
  }

  /**
   * Implements AcquiaLiftReportInterface()::buildConversionReport().
   */
  public function buildConversionReport($options) {
    $report_data = $this
      ->generateReportConfiguration($options);
    $report_name = t('All goals');
    $report_options = array();
    if (!empty($options['goal'])) {

      // Get the summary data for the whole campaign in order to have overall
      // statistics.
      $this
        ->loadConversionReportHelper($report_data, FALSE, $options);
      $report_options['goal'] = $options['goal'];
      $actions = visitor_actions_get_actions();

      // If the action still exists, use the label, otherwise just use the goal
      // machine name.
      if (isset($actions[$options['goal']])) {
        $report_name = $actions[$options['goal']]['label'];
      }
      else {
        $report_name = $options['goal'];
      }
    }
    $this
      ->loadConversionReportHelper($report_data, TRUE, $report_options);
    $this
      ->loadConversionReportHelper($report_data, FALSE, $report_options);
    $reports = $this
      ->buildConversionReports(array(
      'name' => $report_name,
      'detail' => empty($options['goal']) ? $report_data['conversion_all']['detail'] : $report_data['conversion_goals'][$options['goal']]['detail'],
      'summary' => empty($options['goal']) ? $report_data['conversion_all']['summary'] : $report_data['conversion_goals'][$options['goal']]['summary'],
    ), $report_data);
    return $reports;
  }

  /**
   * Generates a message to show when there is insufficient confidence in the
   * test results.
   *
   * @return string
   */
  protected function getLowConfidenceMessage() {
    return t('There is not enough data to declare a winner with @confidence% confidence. Consider letting the test run longer before using the results.', array(
      '@confidence' => $this
        ->getConfidenceMeasure(),
    ));
  }

  /**
   * Generates the variation abbreviated label.
   *
   * @param $counter
   *   Indicates the number for the variation.
   * @param $is_control
   *   True if this is the control option.
   */
  protected function getVariationLabel($counter, $is_control) {
    if ($is_control) {
      return t('Control');
    }
    else {
      return t('V@num', array(
        '@num' => $counter,
      ));
    }
  }

  /**
   * Generates an internal raw report name for a confidence report based on
   * the options.
   *
   * @param $options
   *   An array of options passed to the confidence report loader.
   * @returns string
   *   The name of a report to reference within the raw reporting data.
   */
  protected function getConfidenceReportRawName($options = array()) {
    $report_name = 'confidence';
    if (!empty($options['goal'])) {
      $report_name .= '_' . $options['goal'];
    }
    if (isset($options['aggregated-over-dates']) && $options['aggregated-over-dates'] == FALSE) {
      $report_name .= '_detail';
    }
    return $report_name;
  }

  /**
   * Helper function to generate the report options necessary to get a detailed
   * confidence report rather than a summary report.
   *
   * @returns array
   *   An array of confidence report options.
   */
  protected function getConfidenceDetailReportOptions() {
    $options['aggregated-over-dates'] = FALSE;
    return $options;
  }

  /**
   * Generates the general report configuration that is used to load any report.
   *
   * @param $options
   *   An array of options for the report.
   *   - decision: (Optional) decision point name to limit results.
   *   - start: (Optional) start date for report, defaults to agent start.
   *   - end: (Optional) end date for report, defaults to current date.
   *   - goal: (Optional) goal to show in report, defaults to all.
   *   - conversion_metric: (Optional) metric to show in report, defaults to
   *     'rate'.
   * @return array
   *   The basic reporting configuration.
   */
  protected function generateReportConfiguration($options) {
    $decision_name = empty($options['decision']) ? NULL : $options['decision'];
    $date_from = empty($options['start']) ? NULL : $options['start'];
    $date_to = empty($options['end']) ? NULL : $options['end'];
    $machine_name = $this->agent
      ->getMachineName();
    $today_only = $date_from === date('Y-m-d') && empty($date_to);
    $date_from = empty($date_from) ? date('Y-m-d', $this->agent
      ->getStartTime()) : $date_from;
    $date_to = empty($date_to) ? date('Y-m-d') : $date_to;
    $key = 'S' . $date_from . 'E' . $date_to;
    if (!isset($this->report_data[$key])) {
      $confidence_measure = $this
        ->getConfidenceMeasure();

      // Convert the confidence measure from a percentage to a value between
      // 0 and 1 as expected by the Lift API.
      $confidence_measure /= 100;

      // Save basic report generation information with the data.
      $this->report_data[$key]['today_only'] = $today_only;
      $this->report_data[$key]['date_from'] = $date_from;
      $this->report_data[$key]['date_to'] = $date_to;
      $this->report_data[$key]['decision_name'] = $decision_name;
      $this->report_data[$key]['machine_name'] = $machine_name;
      $this->report_data[$key]['confidence_measure'] = $confidence_measure;
      $this->report_data[$key]['features'] = array(
        AcquiaLiftReportBase::NO_FEATURES,
      );
      $this->report_data[$key]['goal'] = empty($options['goal']) ? NULL : $options['goal'];
      $this->report_data[$key]['conversion_metric'] = empty($options['conversion_metric']) ? 'rate' : $options['conversion_metric'];
    }
    return $this->report_data[$key];
  }

  /**
   * Loads the context filter raw values into the report data.
   *
   * @param $report_data
   *   The current reporting array by reference.
   * @return array
   *   The updated reporting data for chaining purposes.  Note that the
   *   reporting data is updated by reference as well.
   */
  protected function loadContextFilterData(&$report_data) {

    // Check and see if it is already loaded.
    if (isset($report_data['raw']['potential_context'])) {
      return $report_data;
    }

    // Load it from the report source.
    try {
      $report_data['raw']['potential_context'] = $this->reportDataSrc
        ->getContextFilters($report_data['machine_name']);
    } catch (Exception $e) {
      $report_data['raw']['potential_context']['error'] = $e
        ->getMessage();
    }
    return $report_data;
  }

  /**
   * Loads the agent status raw reporting data.
   *
   * @param $report_data
   *   The current reporting array by reference.
   * @return array
   *   The updated reporting data for chaining purposes.  Note that the
   *   reporting data is updated by reference as well.
   */
  protected function loadAgentStatusData(&$report_data) {

    // Check and see if it is already loaded.
    if (isset($report_data['raw']['status'])) {
      return $report_data;
    }
    try {
      if ($report_data['today_only']) {
        $num_days = 1;
      }
      else {
        $interval = date_diff(date_create($report_data['date_from']), date_create($report_data['date_to']));
        $num_days = $interval->days;
      }
      $report_data['raw']['status'] = $this->reportDataSrc
        ->getAgentStatusReport(array(
        $report_data['machine_name'],
      ), $num_days);
    } catch (Exception $e) {
      $report_data['raw']['status']['error'] = $e
        ->getMessage();
    }
    return $report_data;
  }

  /**
   * Loads the agent confidence raw reporting data.
   *
   * @param $report_data
   *   The current reporting array by reference.
   * @param $options
   *   (Optional) An array of options to pass to the report source.
   * @return array
   *   The updated reporting data for chaining purposes.  Note that the
   *   reporting data is updated by reference as well.
   */
  protected function loadConfidenceData(&$report_data, $options = array()) {
    $report_name = $this
      ->getConfidenceReportRawName($options);

    // Check and see if it is already loaded.
    if (isset($report_data['raw'][$report_name])) {
      return $report_data;
    }
    try {
      $defaults = array(
        'features' => 'all',
        'confidence-measure' => $report_data['confidence_measure'],
      );
      $options = array_merge($defaults, $options);
      $report_data['raw'][$report_name] = $this->reportDataSrc
        ->getConfidenceReport($report_data['machine_name'], $report_data['date_from'], $report_data['date_to'], $report_data['decision_name'], $options);
    } catch (Exception $e) {
      $report_data['raw'][$report_name]['error'] = $e
        ->getMessage();
    }
    return $report_data;
  }

  /**
   * Loads the agent targeting raw reporting data.
   *
   * @param $report_data
   *   The current reporting array by reference.
   * @return array
   *   The updated reporting data for chaining purposes.  Note that the
   *   reporting data is updated by reference as well.
   */
  protected function loadTargetingData(&$report_data) {

    // Check and see if it is already loaded.
    if (isset($report_data['raw']['targeting'])) {
      return $report_data;
    }
    try {
      $report_data['raw']['targeting'] = $this->reportDataSrc
        ->getTargetingImpactReport($report_data['machine_name'], $report_data['date_from'], $report_data['date_to'], $report_data['decision_name']);
    } catch (Exception $e) {
      $report_data['raw']['confidence']['error'] = $e
        ->getMessage();
    }
    return $report_data;
  }

  /**
   * Formats a percentage value for use in reports.
   *
   * @param $value
   *   The number to show as a percentage.
   * @param bool $include_sign
   *   True to include positive/negative sign indicators.
   * @param $trim
   *   Boolean indicating whether the number should be trimmed of trailing 0s.
   * @param $decimals
   *   The number of decimal places to display.
   * @param $padding
   *   The total number of characters (including decimal) for padding of the
   *   final number.  This allows numbers to align properly  in column views.
   *   This will have no effect if trim is set to true.
   * @return string
   *   The formatted number to display.
   */
  protected function formatReportPercentage($value, $include_sign = FALSE, $trim = TRUE, $decimals = 2, $padding = 1) {
    $percent = (double) $value * 100;
    if ($percent > 0 && $include_sign) {
      return '+' . $this
        ->formatReportNumber($percent, $trim, $decimals, $padding) . '%';
    }
    return $this
      ->formatReportNumber($percent, $trim, $decimals, $padding) . '%';
  }

  /**
   * Formats a number value for use in reports.
   *
   * @param $value
   *   The number of format (or an empty value).
   * @param $trim
   *   Boolean indicating whether the number should be trimmed of trailing 0s.
   * @param $decimals
   *   The number of decimal places to display.
   * @param $padding
   *   The total number of characters to pad to the left of the decimal point.
   * @return string
   *   The formatted number to display.
   */
  protected function formatReportNumber($value, $trim = TRUE, $decimals = 2, $padding = 1) {
    if (is_numeric($value)) {
      $value = number_format($value, $decimals);
      if ($trim) {
        $value = rtrim(rtrim($value, '0'), '.');
      }
      if ($padding > 0) {
        $value = str_pad($value, $padding, '0', STR_PAD_LEFT);
      }
    }
    if (empty($value)) {
      $value = 0;
    }
    return $value;
  }

  /**
   * Builds the conversion reports to show basic conversion metrics for report
   * requested in the report_data.
   *
   * @param array $report_data
   *   The loaded report data for the selection decision and dates.
   * @return array
   *   The render array for the report.
   */
  protected function buildAllConversionReports($report_data) {
    if (empty($report_data['goal'])) {

      // Generate the conversion reports for all goals.
      $reports = $this
        ->buildConversionReports(array(
        'name' => t('All goals'),
        'detail' => $report_data['conversion_all']['detail'],
        'summary' => $report_data['conversion_all']['summary'],
      ), $report_data);
    }
    else {

      // Generate the conversion reports for the specified goal.
      $reports = $this
        ->buildConversionReports($report_data['conversion_goals'][$report_data['goal']], $report_data);
    }
    if ($reports == FALSE) {
      drupal_set_message(t('There was a problem retrieving the report data.  Please try again later.'), 'error');
    }
    $build['reports'] = array(
      '#type' => 'container',
      '#attributes' => array(
        'class' => array(
          'lift-statistics',
        ),
      ),
      'conversion' => $reports,
    );
    return $build;
  }

  /**
   * Handles all of the logic to load and extract a conversion report.
   *
   * @param $report_data
   *   The array of existing report data.
   * @param $detail
   *   True if the report should be a detailed report and false for summary.
   * @param array $options
   *   An array of report options such as a goal for limiting.
   */
  protected function loadConversionReportHelper(&$report_data, $detail, $options = array()) {

    // Limit report results to the experimental group.
    $options['policies'] = 'explore';
    if ($detail) {
      $options = array_merge($options, $this
        ->getConfidenceDetailReportOptions());
    }
    $new_report = array();
    $report_name = $this
      ->getConfidenceReportRawName($options);
    if (isset($options['goal'])) {

      // Add the report name for this goal to track which goals are included.
      $report_data['goal_reports'][] = $report_name;

      // Determine the parent for reports added by this helper.
      if (!isset($report_data['conversion_goals'])) {
        $report_data['conversion_goals'][$options['goal']] = FALSE;
      }
      $detail_report =& $report_data['conversion_goals'][$options['goal']];
    }
    else {

      // Determine the parent for reports added by this helper.
      if (!isset($report_data['conversion_all'])) {
        $report_data['conversion_all'] = FALSE;
      }
      $detail_report =& $report_data['conversion_all'];
    }

    // Check if the report is already loaded.
    $subreport_name = $detail ? 'detail' : 'summary';
    if (isset($detail_report[$subreport_name])) {
      return;
    }

    // Load the raw report data.
    if (!isset($report_data['raw'][$report_name])) {
      $this
        ->loadConfidenceData($report_data, $options);
      if (isset($report_data['raw'][$report_name]['error'])) {
        return;
      }
    }
    if (!isset($report_data['raw'][$report_name]['data'])) {
      return;
    }

    // Extract the data into full report data from the raw data.
    $detail_report[$subreport_name] = $detail ? $this
      ->extractConversionReportData($report_data['raw'][$report_name]['data']['items']) : $this
      ->extractConversionSummaryData($report_data['raw'][$report_name]['data']['items']);
  }

  /**
   * Extracts the required overview data from the report data returned by
   * Acquia Lift.
   *
   * @param $items
   *   An array of items as returned from Acquia Lift.
   * @return array
   *   An associative array with information for today's and the total overview.
   */
  protected function extractOverviewReportData($items) {
    $agent_data = $this->agent
      ->getData();
    $decision_style = $agent_data['decision_style'] === 'adaptive' ? t('Auto-personalize') : t('A/B');
    $total_variations = isset($agent_data['decisions']) ? count($agent_data['decisions']) : 0;

    // Create an array of data for each time option.
    $report['today'] = array(
      'unformatted' => array(
        'total_lift' => $items['today']['liftOverDefaultUsingGoals'],
        'total_shown' => $items['today']['sessionCount'],
        'total_goals' => $items['today']['goalCount'],
      ),
      'test_type' => $decision_style,
      'total_shown' => $this
        ->formatReportNumber($items['today']['sessionCount']),
      'total_goals' => $this
        ->formatReportNumber($items['today']['goalCount']),
      'total_goals_positive' => $items['today']['goalCount'] > 0,
      'total_lift' => $this
        ->formatReportPercentage($items['today']['liftOverDefaultUsingGoals']),
      'total_variations' => $total_variations,
    );
    $report['all'] = array(
      'unformatted' => array(
        'total_shown' => $items['totals']['sessions']['count'],
        'total_goals' => $items['totals']['goals']['count'],
        'total_lift' => $items['today']['liftOverDefaultUsingGoalsToDate'],
      ),
      'test_type' => $decision_style,
      'total_shown' => $this
        ->formatReportNumber($items['totals']['sessions']['count']),
      'total_goals' => $this
        ->formatReportNumber($items['totals']['goals']['count']),
      'total_goals_positive' => $items['totals']['goals']['count'] > 0,
      'total_lift' => $this
        ->formatReportPercentage($items['today']['liftOverDefaultUsingGoalsToDate']),
      'total_variations' => $total_variations,
    );
    return $report;
  }

  /**
   * Extracts data from the raw confidence detail report that is prepared for use
   * within the conversion report rendering process.
   *
   * @param $items
   *   An array of items as return from Acquia Lift.
   * @return array
   *   An associative array with information about the performance of each choice.
   */
  protected function extractConversionReportData($items) {
    if (empty($items)) {
      return array();
    }
    $shown = array();
    $counter = NAN;
    $data = array();
    $total_count = $total_goals = $total_val = array();
    foreach ($items as $item) {

      // Check to see if we are in a new grouping of choices.
      $check = $item['choice'];
      if (is_nan($counter) || isset($shown[$check])) {
        $shown = array();
        $counter = 0;
      }
      else {
        $counter++;
      }
      $shown[$check] = $check;
      $choice = $option_id = $item['choice'];
      $choice_id = $choice;
      if (strpos($choice, ':') !== FALSE) {
        list($decision_name, $option_id) = explode(':', $choice);
      }
      if ($option_label = personalize_get_option_label_for_decision_and_choice($decision_name, $option_id)) {
        $choice_id = $option_label;
      }
      $goals = $item['totals']['goals'];
      $count = $item['totals']['count'];
      $val = $item['totals']['val'];
      $total_count[$counter] = isset($total_count[$counter]) ? $total_count[$counter] + $count : $count;
      $total_goals[$counter] = isset($total_goals[$counter]) ? $total_goals[$counter] + $goals : $goals;
      $total_val[$counter] = isset($total_val[$counter]) ? $total_val[$counter] + $val : $val;
      $rate = $total_count[$counter] > 0 ? $total_goals[$counter] / $total_count[$counter] * 100 : 0;
      $val_rate = $total_count[$counter] > 0 ? $total_val[$counter] / $total_count[$counter] : 0;
      $margin = ($item['bHi'] - $item['bLo']) / 2;
      $data[$item['feature']][] = array(
        'choice_id' => $choice_id,
        'raw_label' => $option_id,
        'goals' => $total_goals[$counter],
        'count' => $total_count[$counter],
        'date' => $item['date'],
        'timestamp' => strtotime($item['date']),
        'conversion' => $this
          ->formatReportNumber($rate, TRUE, 4),
        'conversion_value' => $this
          ->formatReportNumber($val_rate, TRUE, 4),
        'estimated_value' => $this
          ->formatReportNumber($item['vMean'], TRUE, 4),
        'margin_error' => $this
          ->formatReportNumber($margin, TRUE, 4),
        'counter' => $counter,
        'control' => $counter === 0,
      );
    }
    return $data;
  }

  /**
   * Loads and formats the necessary reporting data in order to generate a
   * conversion metrics graph/report.
   *
   * @param array
   *   The report data object to load conversion report data into.
   */
  protected function loadConversionReportData(&$report_data) {

    // All goals - summary report is always loaded in order to get the overview
    // data for the campaign.
    if (!isset($report_data['conversion'])) {
      $this
        ->loadConversionReportHelper($report_data, FALSE);
    }

    // All goals conversion report.
    if (empty($report_data['goal'])) {

      // All goals - detail report.
      if (!isset($report_data['conversion_detail'])) {
        $this
          ->loadConversionReportHelper($report_data, TRUE);
      }
      return;
    }

    // Load the detail and summary reports for the specified goal.
    $actions = visitor_actions_get_actions();
    $goal_id = $report_data['goal'];
    if (!isset($report_data['conversion_goals'][$goal_id])) {
      $report_data['conversion_goals'][$goal_id]['name'] = isset($actions[$goal_id]) ? $actions[$goal_id]['label'] : $goal_id;
      $options['goal'] = $goal_id;

      // Summary report.
      $this
        ->loadConversionReportHelper($report_data, FALSE, $options);

      // Detail report.
      $this
        ->loadConversionReportHelper($report_data, TRUE, $options);
    }
  }

  /**
   * Extracts data from the raw aggregate confidence report that is prepared for
   * use within the report rendering process.
   *
   * @param $items
   *   An array of items as return from Acquia Lift.
   * @return array
   *   An associative array with information about the performance of each choice.
   */
  protected function extractConversionSummaryData($items) {
    if (empty($items)) {
      return array();
    }
    $shown = array();
    $counter = NAN;
    $data = array();
    $confidence = FALSE;
    $winner = '';
    $winning_value = NAN;
    foreach ($items as $item) {

      // Check to see if we are in a new grouping of choices.
      $check = $item['choice'];

      // First item in the loop so this is the control.
      if (is_nan($counter) || isset($shown[$check])) {
        $shown = array();
        $counter = 0;
      }
      else {
        $counter++;
      }
      $shown[$check] = $check;
      $choice = $option_id = $item['choice'];
      $choice_id = $choice;
      if (strpos($choice, ':') !== FALSE) {
        list($decision_name, $option_id) = explode(':', $choice);
      }
      if ($option_label = personalize_get_option_label_for_decision_and_choice($decision_name, $option_id)) {
        $choice_id = $option_label;
      }
      $goals = $item['totals']['goals'];
      $count = $item['totals']['count'];

      // The format for percentages will already multiply by 100.
      $rate = $count > 0 ? $goals / $count : 0;
      $margin = ($item['bHi'] - $item['bLo']) / 2;
      if ($item['signif']) {
        if (is_nan($winning_value) || $item['confidence'] > $winning_value) {
          $winning_value = $item['confidence'];
          $winner = $counter;
          $confidence = TRUE;
        }
      }
      $data[$item['feature']][] = array(
        'counter' => $counter,
        'choice_id' => $choice_id,
        'raw_label' => $option_id,
        'goals' => $goals,
        'count' => $count,
        'date' => $item['date'],
        'timestamp' => strtotime($item['date']),
        'conversion' => $this
          ->formatReportPercentage($rate),
        'estimated_value' => $this
          ->formatReportNumber($item['vMean'], TRUE, 4),
        'estimated_higher' => $this
          ->formatReportNumber($item['bHi'], TRUE, 4),
        'estimated_lower' => $this
          ->formatReportNumber($item['bLo'], TRUE, 4),
        'margin_error' => $this
          ->formatReportNumber($margin, TRUE, 4),
        'significant' => $item['signif'],
        'control' => $counter === 0,
        'confidence' => $counter === 0 ? self::DATA_NA : $this
          ->formatReportPercentage($item['confidence'] / 100),
        'lift_default' => $counter === 0 ? self::DATA_NA : $this
          ->formatReportPercentage($item['lift']['default'] / 100, TRUE),
        'lift_random' => $this
          ->formatReportPercentage($item['lift']['random'] / 100, TRUE),
      );
    }
    $report = array(
      'data' => $data,
      'overview' => array(
        'confidence' => $confidence,
        'winner' => $winner,
      ),
    );
    return $report;
  }

  /**
   * Builds the render array for the metrics portion of the report.
   *
   * @param array $report_data
   *   All of the reporting data for this AB report.
   * @param array $all_report_data
   *   The report data for all reports to be build including overview data.
   * @param array|bool
   *   A render array for the report or FALSE if it cannot be generated.
   */
  protected function buildConversionDetailReport($report_data, $all_report_data) {
    if ($report_data === FALSE) {
      return FALSE;
    }
    $headers = array(
      t('Date'),
      t('Content variation'),
      array(
        'data' => t('Conversion rate (%)'),
        'data-conversion-metric' => 'rate',
      ),
      array(
        'data' => t('Conversion value'),
        'data-conversion-metric' => 'value',
      ),
      t('Margin of error'),
    );
    $rows = array();
    foreach ($report_data as $feature => $feature_data) {
      if (!in_array($feature, $all_report_data['features'])) {
        continue;
      }
      foreach ($feature_data as $data) {
        $rows[] = array(
          'data' => array(
            array(
              'data' => $data['timestamp'],
            ),
            array(
              'data' => $data['choice_id'],
              'data-acquia-lift-variation-label' => $this
                ->getVariationLabel($data['counter'], $data['control']),
            ),
            array(
              'data' => $data['conversion'],
            ),
            array(
              'data' => $data['conversion_value'],
            ),
            array(
              'data' => $data['margin_error'],
            ),
          ),
          'no_striping' => TRUE,
        );
      }
    }
    if (!empty($rows)) {
      $build['metric_table'] = array(
        '#theme' => 'table',
        '#header' => $headers,
        '#rows' => $rows,
        '#sticky' => FALSE,
        '#attributes' => array(
          'data-lift-statistics' => '',
          'data-liftGraph-columnName' => '2',
          'data-liftGraph-columnX' => '1',
          'data-liftGraph-renderer' => 'line',
          'data-liftgraph-excluded' => '5',
          'data-acquia-lift-campaign' => $all_report_data['machine_name'],
          'data-acquia-lift-decision-name' => $all_report_data['decision_name'],
        ),
      );
    }
    return $build;
  }

  /**
   * Builds the render array for the summary portion of the report.
   *
   * @param array $report_data
   *   Reporting data for this summary report.
   * @param array $all_report_data
   *   The report data for all reports to be build including overview data.
   * @param array|bool
   *   A render array for the report or FALSE if it cannot be generated.
   */
  protected function buildConversionSummaryReport($report_data, $all_report_data) {
    if ($report_data === FALSE) {
      return FALSE;
    }
    $confidence = !empty($all_report_data['conversion_all']['summary']['overview']['confidence']);
    $winner = $all_report_data['conversion_all']['summary']['overview']['winner'];
    $headers = array(
      t('Variation'),
      array(
        'data' => t('Total goals met'),
        'data-help-tooltip' => t('Number of times visitors completed a goal after viewing the variation.'),
      ),
      array(
        'data' => t('Total conversion rate'),
        'data-help-tooltip' => t('Percentage of goals met for each display of the variation.'),
      ),
      array(
        'data' => t('Chance to beat control'),
        'data-help-tooltip' => t('Likelihood visitors will complete goals for a variation compared to the control.'),
      ),
      array(
        'data' => t('Lift'),
        'data-help-tooltip' => t('Likelihood visitors will complete goals for a variation compared to the control.'),
      ),
      array(
        'data' => t('Winner'),
        'data-help-tooltip' => t('Most effective variation for visitors based on a @confidence% confidence level.', array(
          '@confidence' => $this
            ->getConfidenceMeasure(),
        )),
      ),
    );
    $confidence_message_shown = FALSE;
    $rows = array();
    foreach ($report_data['data'] as $feature => $feature_data) {
      if (!in_array($feature, $all_report_data['features'])) {
        continue;
      }
      foreach ($feature_data as $data) {
        $row_data = array(
          array(
            'data' => $data['choice_id'],
            'data-acquia-lift-variation-label' => $this
              ->getVariationLabel($data['counter'], $data['control']),
          ),
          array(
            'data' => $data['goals'],
          ),
          array(
            'data' => $data['conversion'],
          ),
          array(
            'data' => $data['confidence'],
          ),
          array(
            'data' => $data['lift_default'],
          ),
        );

        // Add the winner column data.
        if (empty($rows) && !$confidence) {

          // If there is low confidence then show the message throughout the
          // winner column.
          $row_data[] = array(
            'data' => $this
              ->getLowConfidenceMessage(),
            'rowspan' => count($feature_data),
            'class' => array(
              'acquia-lift-ab-winner',
            ),
          );
          $confidence_message_shown = TRUE;
        }
        else {
          if (!$confidence_message_shown) {

            // Show the winner indicator if this is the winning variation.
            $row_data[] = $confidence && $winner === $data['counter'] ? '<span class="lift-winner">' . t('Winner') . '</span>' : '';
          }
        }
        $rows[] = array(
          'data' => $row_data,
          'no_striping' => TRUE,
        );
      }
    }
    if (empty($rows)) {
      return array();
    }
    $build['summary_holder'] = array(
      '#type' => 'container',
      '#attributes' => array(
        'class' => array(
          'lift-graph-result',
        ),
      ),
    );
    $build['summary_holder']['summary_table'] = array(
      '#theme' => 'table',
      '#header' => $headers,
      '#rows' => $rows,
      '#sticky' => FALSE,
      '#attributes' => array(
        'class' => array(
          'lift-graph-result-data',
        ),
        'data-acquia-lift-campaign' => $all_report_data['machine_name'],
        'data-acquia-lift-decision-name' => $all_report_data['decision_name'],
      ),
      '#attached' => array(
        'library' => array(
          array(
            'acquia_lift',
            'acquia_lift.help',
          ),
        ),
      ),
    );
    return $build;
  }

  /**
   * Build a set of confidence reports from the report data.
   *
   * @param array $report_data
   *   The extracted report data with the following keys:
   *   - name: The name of the section
   *   - detail:  The detail report data
   *   - summary: The summary report data
   * @param array $all_report_data
   *   The full report data for all reports including overview information.
   * @return array|bool
   *   The render array for the reports or false if invalid data.
   */
  protected function buildConversionReports($report_data, $all_report_data) {
    if ($report_data['detail'] == FALSE || $report_data['summary'] == FALSE) {
      return FALSE;
    }
    $build = array();
    $build['reports']['title'] = array(
      '#theme' => 'html_tag',
      '#tag' => 'h3',
      '#value' => $report_data['name'],
      '#attributes' => array(
        'class' => array(
          'lift-statistic-category-name',
          'element-invisible',
        ),
      ),
    );
    $build['reports']['detail'] = $this
      ->buildConversionDetailReport($report_data['detail'], $all_report_data);
    $build['reports']['summary'] = $this
      ->buildConversionSummaryReport($report_data['summary'], $all_report_data);
    $build['reports']['#theme_wrappers'] = array(
      'container',
    );
    $build['reports']['#attributes'] = array(
      'class' => array(
        'lift-statistic-category',
      ),
    );
    return $build;
  }

}

Members

Namesort descending Modifiers Type Description Overrides
AcquiaLiftReportBase::$agent protected property The Acquia Lift agent instance for reporting on.
AcquiaLiftReportBase::$confidence_measure protected property The confidence measure for determining statistical significance.
AcquiaLiftReportBase::$liftAPI protected property An instance of AcquiaLiftAPI.
AcquiaLiftReportBase::$report_data protected property The extracted report data for each of the Acquia Lift API calls keyed by date/feature set requested.
AcquiaLiftReportBase::buildAllConversionReports protected function Builds the conversion reports to show basic conversion metrics for report requested in the report_data.
AcquiaLiftReportBase::buildConversionDetailReport protected function Builds the render array for the metrics portion of the report.
AcquiaLiftReportBase::buildConversionReport public function Implements AcquiaLiftReportInterface()::buildConversionReport(). Overrides AcquiaLiftReportInterface::buildConversionReport
AcquiaLiftReportBase::buildConversionReports protected function Build a set of confidence reports from the report data.
AcquiaLiftReportBase::buildConversionSummaryReport protected function Builds the render array for the summary portion of the report.
AcquiaLiftReportBase::DATA_NA constant The value to show when report data is not applicable.
AcquiaLiftReportBase::extractConversionReportData protected function Extracts data from the raw confidence detail report that is prepared for use within the conversion report rendering process.
AcquiaLiftReportBase::extractConversionSummaryData protected function Extracts data from the raw aggregate confidence report that is prepared for use within the report rendering process.
AcquiaLiftReportBase::extractOverviewReportData protected function Extracts the required overview data from the report data returned by Acquia Lift.
AcquiaLiftReportBase::formatReportNumber protected function Formats a number value for use in reports.
AcquiaLiftReportBase::formatReportPercentage protected function Formats a percentage value for use in reports.
AcquiaLiftReportBase::generateReportConfiguration protected function Generates the general report configuration that is used to load any report.
AcquiaLiftReportBase::getConfidenceDetailReportOptions protected function Helper function to generate the report options necessary to get a detailed confidence report rather than a summary report.
AcquiaLiftReportBase::getConfidenceMeasure public function Implements AcquiaLiftReportInterface()::getConfidenceMeasure(). Overrides AcquiaLiftReportInterface::getConfidenceMeasure
AcquiaLiftReportBase::getConfidenceReportRawName protected function Generates an internal raw report name for a confidence report based on the options.
AcquiaLiftReportBase::getLowConfidenceMessage protected function Generates a message to show when there is insufficient confidence in the test results.
AcquiaLiftReportBase::getVariationLabel protected function Generates the variation abbreviated label.
AcquiaLiftReportBase::loadAgentStatusData protected function Loads the agent status raw reporting data.
AcquiaLiftReportBase::loadConfidenceData protected function Loads the agent confidence raw reporting data.
AcquiaLiftReportBase::loadContextFilterData protected function Loads the context filter raw values into the report data.
AcquiaLiftReportBase::loadConversionReportData protected function Loads and formats the necessary reporting data in order to generate a conversion metrics graph/report.
AcquiaLiftReportBase::loadConversionReportHelper protected function Handles all of the logic to load and extract a conversion report.
AcquiaLiftReportBase::loadTargetingData protected function Loads the agent targeting raw reporting data.
AcquiaLiftReportBase::NO_FEATURES constant The value representing no features applied to an experiment.
AcquiaLiftReportBase::setConfidenceMeasure public function Implements AcquiaLiftReportInterface()::setConfidenceMeasure(). Overrides AcquiaLiftReportInterface::setConfidenceMeasure
AcquiaLiftReportBase::__construct function Constructs an AcquiaLiftReport object