/** * @see ViewDataTable::main() * @return mixed */ public function render() { $view = new View('@CoreVisualizations/_dataTableViz_sparklines.twig'); $columnsList = array(); if ($this->config->hasSparklineMetrics()) { foreach ($this->config->getSparklineMetrics() as $cols) { $columns = $cols['columns']; if (!is_array($columns)) { $columns = array($columns); } $columnsList = array_merge($columns, $columnsList); } } $view->allMetricsDocumentation = Metrics::getDefaultMetricsDocumentation(); $this->requestConfig->request_parameters_to_modify['columns'] = $columnsList; $this->requestConfig->request_parameters_to_modify['format_metrics'] = '1'; if (!empty($this->requestConfig->apiMethodToRequestDataTable)) { $this->fetchConfiguredSparklines(); } $view->sparklines = $this->config->getSortedSparklines(); $view->isWidget = Common::getRequestVar('widget', 0, 'int'); $view->titleAttributes = $this->config->title_attributes; $view->footerMessage = $this->config->show_footer_message; $view->areSparklinesLinkable = $this->config->areSparklinesLinkable(); $view->title = ''; if ($this->config->show_title) { $view->title = $this->config->title; } return $view->render(); }
/** * @dataProvider getUnitColumns * @group Core */ public function testGetUnit($column, $expected) { Site::setSites(array(1 => array('name' => 'TestSite', 'currency' => 'EUR'))); FakeAccess::$superUser = true; $actual = Metrics::getUnit($column, 1); $this->assertEquals($expected, $actual); }
/** Render the area left of the iframe */ public function renderSidebar() { $idSite = Common::getRequestVar('idSite'); $period = Common::getRequestVar('period'); $date = Common::getRequestVar('date'); $currentUrl = Common::getRequestVar('currentUrl'); $currentUrl = Common::unsanitizeInputValue($currentUrl); $normalizedCurrentUrl = PageUrl::excludeQueryParametersFromUrl($currentUrl, $idSite); $normalizedCurrentUrl = Common::unsanitizeInputValue($normalizedCurrentUrl); // load the appropriate row of the page urls report using the label filter ArchivingHelper::reloadConfig(); $path = ArchivingHelper::getActionExplodedNames($normalizedCurrentUrl, Action::TYPE_PAGE_URL); $path = array_map('urlencode', $path); $label = implode('>', $path); $request = new Request('method=Actions.getPageUrls' . '&idSite=' . urlencode($idSite) . '&date=' . urlencode($date) . '&period=' . urlencode($period) . '&label=' . urlencode($label) . '&format=original' . '&format_metrics=0'); $dataTable = $request->process(); $formatter = new Metrics\Formatter\Html(); $data = array(); if ($dataTable->getRowsCount() > 0) { $row = $dataTable->getFirstRow(); $translations = Metrics::getDefaultMetricTranslations(); $showMetrics = array('nb_hits', 'nb_visits', 'nb_users', 'nb_uniq_visitors', 'bounce_rate', 'exit_rate', 'avg_time_on_page'); foreach ($showMetrics as $metric) { $value = $row->getColumn($metric); if ($value === false) { // skip unique visitors for period != day continue; } if ($metric == 'bounce_rate' || $metric == 'exit_rate') { $value = $formatter->getPrettyPercentFromQuotient($value); } else { if ($metric == 'avg_time_on_page') { $value = $formatter->getPrettyTimeFromSeconds($value, $displayAsSentence = true); } } $data[] = array('name' => $translations[$metric], 'value' => $value); } } // generate page url string foreach ($path as &$part) { $part = preg_replace(';^/;', '', urldecode($part)); } $page = '/' . implode('/', $path); $page = preg_replace(';/index$;', '/', $page); if ($page == '/') { $page = '/index'; } // render template $view = new View('@Overlay/renderSidebar'); $view->data = $data; $view->location = $page; $view->normalizedUrl = $normalizedCurrentUrl; $view->label = $label; $view->idSite = $idSite; $view->period = $period; $view->date = $date; $this->outputCORSHeaders(); return $view->render(); }
public function compute(Row $row) { $mappingFromNameToIdGoal = Metrics::getMappingFromNameToIdGoal(); $goalMetrics = $this->getGoalMetrics($row); $goalRevenue = $this->getMetric($goalMetrics, 'revenue', $mappingFromNameToIdGoal); $conversions = $this->getMetric($goalMetrics, 'nb_conversions', $mappingFromNameToIdGoal); return Piwik::getQuotientSafe($goalRevenue, $conversions, GoalManager::REVENUE_PRECISION); }
/** * @dataProvider getUnitColumns * @group Core */ public function testGetUnit($column, $expected) { \Piwik\Site::setSites(array(1 => array('name' => 'TestSite', 'currency' => 'EUR'))); $pseudoMockAccess = new FakeAccess(); FakeAccess::$superUser = true; Access::setSingletonInstance($pseudoMockAccess); $actual = Metrics::getUnit($column, 1); $this->assertEquals($expected, $actual); }
public function configureView(ViewDataTable $view) { $view->requestConfig->filter_sort_column = 'label'; $view->requestConfig->filter_sort_order = 'asc'; $view->requestConfig->filter_limit = 15; $view->config->addTranslations(array('label' => Piwik::translate('VisitorInterest_VisitNum'), 'nb_visits_percentage' => Metrics::getPercentVisitColumn())); $view->config->columns_to_display = array('label', 'nb_visits', 'nb_visits_percentage'); $view->config->show_exclude_low_population = false; $view->config->enable_sort = false; $view->config->show_offset_information = false; $view->config->show_pagination_control = false; $view->config->show_limit_control = false; $view->config->show_search = false; $view->config->show_table_all_columns = false; $view->config->show_all_views_icons = false; }
/** * Returns datatable describing the number of visits for each day of the week. * * @param string $idSite The site ID. Cannot refer to multiple sites. * @param string $period The period type: day, week, year, range... * @param string $date The start date of the period. Cannot refer to multiple dates. * @param bool|string $segment The segment. * @throws Exception * @return DataTable */ public function getByDayOfWeek($idSite, $period, $date, $segment = false) { Piwik::checkUserHasViewAccess($idSite); // metrics to query $metrics = Metrics::getVisitsMetricNames(); unset($metrics[Metrics::INDEX_MAX_ACTIONS]); // disabled for multiple dates if (Period::isMultiplePeriod($date, $period)) { throw new Exception("VisitTime.getByDayOfWeek does not support multiple dates."); } // get metric data for every day within the supplied period $oPeriod = Period\Factory::makePeriodFromQueryParams(Site::getTimezoneFor($idSite), $period, $date); $dateRange = $oPeriod->getDateStart()->toString() . ',' . $oPeriod->getDateEnd()->toString(); $archive = Archive::build($idSite, 'day', $dateRange, $segment); // disabled for multiple sites if (count($archive->getParams()->getIdSites()) > 1) { throw new Exception("VisitTime.getByDayOfWeek does not support multiple sites."); } $dataTable = $archive->getDataTableFromNumeric($metrics)->mergeChildren(); // if there's no data for this report, don't bother w/ anything else if ($dataTable->getRowsCount() == 0) { return $dataTable; } // group by the day of the week (see below for dayOfWeekFromDate function) $dataTable->filter('GroupBy', array('label', __NAMESPACE__ . '\\dayOfWeekFromDate')); // create new datatable w/ empty rows, then add calculated datatable $rows = array(); foreach (array(1, 2, 3, 4, 5, 6, 7) as $day) { $rows[] = array('label' => $day, 'nb_visits' => 0); } $result = new DataTable(); $result->addRowsFromSimpleArray($rows); $result->addDataTable($dataTable); // set day of week integer as metadata $result->filter('ColumnCallbackAddMetadata', array('label', 'day_of_week')); // translate labels $result->filter('ColumnCallbackReplace', array('label', __NAMESPACE__ . '\\translateDayOfWeek')); // set datatable metadata for period start & finish $result->setMetadata('date_start', $oPeriod->getDateStart()); $result->setMetadata('date_end', $oPeriod->getDateEnd()); return $result; }
public function compute(Row $row) { $mappingFromNameToIdGoal = Metrics::getMappingFromNameToIdGoal(); $goals = $this->getMetric($row, 'goals') ?: array(); $revenue = 0; foreach ($goals as $goalId => $goalMetrics) { if ($goalId == Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_CART) { continue; } if ($goalId >= GoalManager::IDGOAL_ORDER || $goalId == Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_ORDER) { $revenue += (int) $this->getMetric($goalMetrics, 'revenue', $mappingFromNameToIdGoal); } } if ($revenue == 0) { $revenue = (int) $this->getMetric($row, 'revenue'); } $nbVisits = (int) $this->getMetric($row, 'nb_visits'); $conversions = (int) $this->getMetric($row, 'nb_conversions'); // If no visit for this metric, but some conversions, we still want to display some kind of "revenue per visit" // even though it will actually be in this edge case "Revenue per conversion" return Piwik::getQuotientSafe($revenue, $nbVisits == 0 ? $conversions : $nbVisits, GoalManager::REVENUE_PRECISION); }
/** * Adds ratio metrics if possible. * * @param DataTable $dataTable * @return DataTable */ protected function manipulateDataTable($dataTable) { if (!empty($this->report) && !$this->report->getDimension() && !$this->isAllMetricsReport()) { // we currently do not calculate the total value for reports having no dimension return $dataTable; } $this->totals = array(); $firstLevelTable = $this->makeSureToWorkOnFirstLevelDataTable($dataTable); $metricsToCalculate = Metrics::getMetricIdsToProcessReportTotal(); $metricNames = array(); foreach ($metricsToCalculate as $metricId) { $metricNames[$metricId] = Metrics::getReadableColumnName($metricId); } foreach ($firstLevelTable->getRows() as $row) { $columns = $row->getColumns(); foreach ($metricNames as $metricId => $metricName) { $this->sumColumnValueToTotal($columns, $metricId, $metricName); } } $dataTable->setMetadata('totals', $this->totals); return $dataTable; }
/** * Sets the column to be used for Excluding low population * * @param DataTable\Row $row * @return int */ private function selectColumnToExclude($columnToFilter, $row) { if ($row->hasColumn($columnToFilter)) { return $columnToFilter; } // filter_excludelowpop=nb_visits but the column name is still Metrics::INDEX_NB_VISITS in the table $columnIdToName = Metrics::getMappingFromNameToId(); if (isset($columnIdToName[$columnToFilter])) { $column = $columnIdToName[$columnToFilter]; if ($row->hasColumn($column)) { return $column; } } return $columnToFilter; }
protected function aggregateMultipleVisitsMetrics() { $toSum = Metrics::getVisitsMetricNames(); $metrics = $this->archiveProcessor->aggregateNumericMetrics($toSum); return $metrics; }
/** * Enhance a $dataTable using metadata : * * - remove metrics based on $reportMetadata['metrics'] * - add 0 valued metrics if $dataTable doesn't provide all $reportMetadata['metrics'] * - format metric values to a 'human readable' format * - extract row metadata to a separate Simple|Set : $rowsMetadata * - translate metric names to a separate array : $columns * * @param int $idSite enables monetary value formatting based on site currency * @param \Piwik\DataTable\Map|\Piwik\DataTable\Simple $dataTable * @param array $reportMetadata * @param bool $showRawMetrics * @param bool|null $formatMetrics * @return array Simple|Set $newReport with human readable format & array $columns list of translated column names & Simple|Set $rowsMetadata */ private function handleTableReport($idSite, $dataTable, &$reportMetadata, $showRawMetrics = false, $formatMetrics = null) { $hasDimension = isset($reportMetadata['dimension']); $columns = @$reportMetadata['metrics'] ?: array(); if ($hasDimension) { $columns = array_merge(array('label' => $reportMetadata['dimension']), $columns); } if (isset($reportMetadata['processedMetrics']) && is_array($reportMetadata['processedMetrics'])) { $processedMetricsAdded = Metrics::getDefaultProcessedMetrics(); foreach ($reportMetadata['processedMetrics'] as $processedMetricId => $processedMetricTranslation) { // this processed metric can be displayed for this report if ($processedMetricTranslation && $processedMetricId !== $processedMetricTranslation) { $columns[$processedMetricId] = $processedMetricTranslation; } elseif (isset($processedMetricsAdded[$processedMetricId])) { // for instance in case 'nb_visits' => 'nb_visits' we will translate it $columns[$processedMetricId] = $processedMetricsAdded[$processedMetricId]; } } } // Display the global Goal metrics if (isset($reportMetadata['metricsGoal'])) { $metricsGoalDisplay = array('revenue'); // Add processed metrics to be displayed for this report foreach ($metricsGoalDisplay as $goalMetricId) { if (isset($reportMetadata['metricsGoal'][$goalMetricId])) { $columns[$goalMetricId] = $reportMetadata['metricsGoal'][$goalMetricId]; } } } $columns = $this->hideShowMetrics($columns); $totals = array(); // $dataTable is an instance of Set when multiple periods requested if ($dataTable instanceof DataTable\Map) { // Need a new Set to store the 'human readable' values $newReport = new DataTable\Map(); $newReport->setKeyName("prettyDate"); // Need a new Set to store report metadata $rowsMetadata = new DataTable\Map(); $rowsMetadata->setKeyName("prettyDate"); // Process each Simple entry foreach ($dataTable->getDataTables() as $simpleDataTable) { $this->removeEmptyColumns($columns, $reportMetadata, $simpleDataTable); list($enhancedSimpleDataTable, $rowMetadata) = $this->handleSimpleDataTable($idSite, $simpleDataTable, $columns, $hasDimension, $showRawMetrics, $formatMetrics); $enhancedSimpleDataTable->setAllTableMetadata($simpleDataTable->getAllTableMetadata()); $period = $simpleDataTable->getMetadata(DataTableFactory::TABLE_METADATA_PERIOD_INDEX)->getLocalizedLongString(); $newReport->addTable($enhancedSimpleDataTable, $period); $rowsMetadata->addTable($rowMetadata, $period); $totals = $this->aggregateReportTotalValues($simpleDataTable, $totals); } } else { $this->removeEmptyColumns($columns, $reportMetadata, $dataTable); list($newReport, $rowsMetadata) = $this->handleSimpleDataTable($idSite, $dataTable, $columns, $hasDimension, $showRawMetrics, $formatMetrics); $totals = $this->aggregateReportTotalValues($dataTable, $totals); } return array($newReport, $columns, $rowsMetadata, $totals); }
private function deriveUnitsFromRequestedColumnNames() { $idSite = Common::getRequestVar('idSite', null, 'int'); $units = array(); foreach ($this->properties['columns_to_display'] as $columnName) { $derivedUnit = Metrics::getUnit($columnName, $idSite); $units[$columnName] = empty($derivedUnit) ? false : $derivedUnit; } return $units; }
/** * Constructor. */ public function __construct() { $this->export_limit = \Piwik\Config::getInstance()->General['API_datatable_default_limit']; $this->translations = array_merge(Metrics::getDefaultMetrics(), Metrics::getDefaultProcessedMetrics()); $this->show_title = (bool) Common::getRequestVar('showtitle', 0, 'int'); }
private function getMetricTranslations($metricsToTranslate) { $translations = Metrics::getDefaultMetricTranslations(); $metrics = array(); foreach ($metricsToTranslate as $metric) { if ($metric instanceof Metric) { $metricName = $metric->getName(); $translation = $metric->getTranslatedName(); } else { $metricName = $metric; $translation = @$translations[$metric]; } $metrics[$metricName] = $translation ?: $metricName; } return $metrics; }
public function test_getProcessedMetrics_reportShouldUseDefaultProcessedMetrics() { $this->assertEquals(Metrics::getDefaultProcessedMetrics(), $this->basicReport->getProcessedMetrics()); }
/** * Default translations for many core metrics. * This is used for exports with translated labels. The exports contain columns that * are not visible in the UI and not present in the API meta data. These columns are * translated here. * @return array * @deprecated since Piwik 2.15.1 */ public function getDefaultMetricTranslations() { return Metrics::getDefaultMetricTranslations(); }
/** * Prepare metrics toggles with spark lines * @return array */ protected function getMetricsToggles() { $i = 0; $metrics = array(); foreach ($this->availableMetrics as $metric => $metricData) { $unit = Metrics::getUnit($metric, $this->idSite); $change = isset($metricData['change']) ? $metricData['change'] : false; list($first, $last) = $this->getFirstAndLastDataPointsForMetric($metric); $details = Piwik::translate('RowEvolution_MetricBetweenText', array(NumberFormatter::getInstance()->format($first), NumberFormatter::getInstance()->format($last))); if ($change !== false) { $lowerIsBetter = Metrics::isLowerValueBetter($metric); if (substr($change, 0, 1) == '+') { $changeClass = $lowerIsBetter ? 'bad' : 'good'; $changeImage = $lowerIsBetter ? 'arrow_up_red' : 'arrow_up'; } else { if (substr($change, 0, 1) == '-') { $changeClass = $lowerIsBetter ? 'good' : 'bad'; $changeImage = $lowerIsBetter ? 'arrow_down_green' : 'arrow_down'; } else { $changeClass = 'neutral'; $changeImage = false; } } $change = '<span class="' . $changeClass . '">' . ($changeImage ? '<img src="plugins/MultiSites/images/' . $changeImage . '.png" /> ' : '') . $change . '</span>'; $details .= ', ' . Piwik::translate('RowEvolution_MetricChangeText', $change); } // set metric min/max text (used as tooltip for details) $max = isset($metricData['max']) ? $metricData['max'] : 0; $min = isset($metricData['min']) ? $metricData['min'] : 0; $min .= $unit; $max .= $unit; $minmax = Piwik::translate('RowEvolution_MetricMinMax', array($metricData['name'], NumberFormatter::getInstance()->formatNumber($min), NumberFormatter::getInstance()->formatNumber($max))); $newMetric = array('label' => $metricData['name'], 'details' => $details, 'minmax' => $minmax, 'sparkline' => $this->getSparkline($metric)); // Multi Rows, each metric can be for a particular row and display an icon if (!empty($metricData['logo'])) { $newMetric['logo'] = $metricData['logo']; } // TODO: this check should be determined by metric metadata, not hardcoded here if ($metric == 'nb_users' && $first == 0 && $last == 0) { $newMetric['hide'] = true; } $metrics[] = $newMetric; $i++; } return $metrics; }
private function sumColumnValueToTotal(Row $row, $metricId, $totalValues) { $value = $this->getColumn($row, $metricId); if (false === $value) { return $totalValues; } $metricName = Metrics::getReadableColumnName($metricId); if (array_key_exists($metricName, $totalValues)) { $totalValues[$metricName] += $value; } else { $totalValues[$metricName] = $value; } return $totalValues; }
/** * Sets the column to be used for sorting * * @param Row $row * @return int */ protected function selectColumnToSort($row) { $value = $row->getColumn($this->columnToSort); if ($value !== false) { return $this->columnToSort; } $columnIdToName = Metrics::getMappingFromIdToName(); // sorting by "nb_visits" but the index is Metrics::INDEX_NB_VISITS in the table if (isset($columnIdToName[$this->columnToSort])) { $column = $columnIdToName[$this->columnToSort]; $value = $row->getColumn($column); if ($value !== false) { return $column; } } // eg. was previously sorted by revenue_per_visit, but this table // doesn't have this column; defaults with nb_visits $column = Metrics::INDEX_NB_VISITS; $value = $row->getColumn($column); if ($value !== false) { return $column; } // even though this column is not set properly in the table, // we select it for the sort, so that the table's internal state is set properly return $this->columnToSort; }
/** * Helper method that determines the actual column for a metric in a {@link Piwik\DataTable}. * * @param DataTable $table * @param string $columnName * @param int[]|null $mappingNameToId A custom mapping of metric names to special index values. By * default {@link Metrics::getMappingFromNameToId()} is used. * @return string */ public static function getActualMetricColumn(DataTable $table, $columnName, $mappingNameToId = null) { if (empty($mappingIdToName)) { $mappingNameToId = Metrics::getMappingFromNameToId(); } $firstRow = $table->getFirstRow(); if (!empty($firstRow) && $firstRow->getColumn($columnName) === false) { $columnName = $mappingNameToId[$columnName]; } return $columnName; }
/** * Returns the name of the plugin that archives a given report. * * @param string $report Archive data name, eg, `'nb_visits'`, `'UserSettings_...'`, etc. * @return string Plugin name. * @throws \Exception If a plugin cannot be found or if the plugin for the report isn't * activated. */ private static function getPluginForReport($report) { // Core metrics are always processed in Core, for the requested date/period/segment if (in_array($report, Metrics::getVisitsMetricNames())) { $report = 'VisitsSummary_CoreMetrics'; } else { if (strpos($report, 'Goal_') === 0) { $report = 'Goals_Metrics'; } else { if (strrpos($report, '_returning') === strlen($report) - strlen('_returning')) { // HACK $report = 'VisitFrequency_Metrics'; } } } $plugin = substr($report, 0, strpos($report, '_')); if (empty($plugin) || !\Piwik\Plugin\Manager::getInstance()->isPluginActivated($plugin)) { throw new \Exception("Error: The report '{$report}' was requested but it is not available at this stage." . " (Plugin '{$plugin}' is not activated.)"); } return $plugin; }
/** * Constructor. */ public function __construct() { $this->export_limit = \Piwik\Config::getInstance()->General['API_datatable_default_limit']; $this->translations = array_merge(Metrics::getDefaultMetrics(), Metrics::getDefaultProcessedMetrics()); }
public function compute(Row $row) { $mappingFromNameToIdGoal = Metrics::getMappingFromNameToIdGoal(); $goalMetrics = $this->getGoalMetrics($row); return (int) $this->getMetric($goalMetrics, 'items', $mappingFromNameToIdGoal); }
public function __construct() { parent::__construct(); $this->translations = Metrics::getDefaultMetricTranslations(); }
private function getMetricTranslations($metricsToTranslate) { $translations = Metrics::getDefaultMetricTranslations(); $metrics = array(); foreach ($metricsToTranslate as $metric) { if (!empty($translations[$metric])) { $metrics[$metric] = $translations[$metric]; } else { $metrics[$metric] = $metric; } } return $metrics; }
/** * Translate column names to the current language. * Used in subclasses. * * @param array $names * @return array */ protected function translateColumnNames($names) { if (!$this->apiMethod) { return $names; } // load the translations only once // when multiple dates are requested (date=...,...&period=day), the meta data would // be loaded lots of times otherwise if ($this->columnTranslations === false) { $meta = $this->getApiMetaData(); if ($meta === false) { return $names; } $t = Metrics::getDefaultMetricTranslations(); foreach (array('metrics', 'processedMetrics', 'metricsGoal', 'processedMetricsGoal') as $index) { if (isset($meta[$index]) && is_array($meta[$index])) { $t = array_merge($t, $meta[$index]); } } $this->columnTranslations =& $t; } foreach ($names as &$name) { if (isset($this->columnTranslations[$name])) { $name = $this->columnTranslations[$name]; } } return $names; }
/** * Constructor. * * @param DataTable $table The table to pivot. * @param string $report The ID of the report being pivoted, eg, `'Referrers.getKeywords'`. * @param string $pivotByDimension The ID of the dimension to pivot by, eg, `'Referrers.Keyword'`. * @param string|false $pivotColumn The metric that should be displayed in the pivot table, eg, `'nb_visits'`. * If `false`, the first non-label column is used. * @param false|int $pivotByColumnLimit The number of columns to limit the pivot table to. * @param bool $isFetchingBySegmentEnabled Whether to allow fetching by segment. * @throws Exception if pivoting the report by a dimension is unsupported. */ public function __construct($table, $report, $pivotByDimension, $pivotColumn, $pivotByColumnLimit = false, $isFetchingBySegmentEnabled = true) { parent::__construct($table); Log::debug("PivotByDimension::%s: creating with [report = %s, pivotByDimension = %s, pivotColumn = %s, " . "pivotByColumnLimit = %s, isFetchingBySegmentEnabled = %s]", __FUNCTION__, $report, $pivotByDimension, $pivotColumn, $pivotByColumnLimit, $isFetchingBySegmentEnabled); $this->pivotColumn = $pivotColumn; $this->pivotByColumnLimit = $pivotByColumnLimit ?: self::getDefaultColumnLimit(); $this->isFetchingBySegmentEnabled = $isFetchingBySegmentEnabled; $namesToId = Metrics::getMappingFromNameToId(); $this->metricIndexValue = isset($namesToId[$this->pivotColumn]) ? $namesToId[$this->pivotColumn] : null; $this->setPivotByDimension($pivotByDimension); $this->setThisReportMetadata($report); $this->checkSupportedPivot(); }
/** * Returns the name of the plugin that archives a given report. * * @param string $report Archive data name, eg, `'nb_visits'`, `'UserSettings_...'`, etc. * @return string Plugin name. * @throws \Exception If a plugin cannot be found or if the plugin for the report isn't * activated. */ private static function getPluginForReport($report) { // Core metrics are always processed in Core, for the requested date/period/segment if (in_array($report, Metrics::getVisitsMetricNames())) { $report = 'VisitsSummary_CoreMetrics'; } else { if (strpos($report, 'Goal_') === 0) { $report = 'Goals_Metrics'; } } $plugin = substr($report, 0, strpos($report, '_')); if (empty($plugin) || !\Piwik\Plugin\Manager::getInstance()->isPluginActivated($plugin)) { $pluginStr = empty($plugin) ? '' : "({$plugin})"; throw new \Exception("Error: The report '{$report}' was requested but it is not available " . "at this stage. You may also disable the related plugin {$pluginStr} " . "to avoid this error."); } return $plugin; }