update Piwik to version 2.16 (fixes #91)
This commit is contained in:
parent
296343bf3b
commit
d885a4baa9
5833 changed files with 418860 additions and 226988 deletions
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
/**
|
||||
* Piwik - Open source web analytics
|
||||
* Piwik - free/libre analytics platform
|
||||
*
|
||||
* @link http://piwik.org
|
||||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
||||
|
|
@ -38,17 +38,16 @@ class Flattener extends DataTableManipulator
|
|||
* Separator for building recursive labels (or paths)
|
||||
* @var string
|
||||
*/
|
||||
public $recursiveLabelSeparator = ' - ';
|
||||
public $recursiveLabelSeparator = '';
|
||||
|
||||
/**
|
||||
* @param DataTable $dataTable
|
||||
* @param string $recursiveLabelSeparator
|
||||
* @return DataTable|DataTable\Map
|
||||
*/
|
||||
public function flatten($dataTable)
|
||||
public function flatten($dataTable, $recursiveLabelSeparator)
|
||||
{
|
||||
if ($this->apiModule == 'Actions' || $this->apiMethod == 'getWebsites') {
|
||||
$this->recursiveLabelSeparator = '/';
|
||||
}
|
||||
$this->recursiveLabelSeparator = $recursiveLabelSeparator;
|
||||
|
||||
return $this->manipulate($dataTable);
|
||||
}
|
||||
|
|
@ -72,9 +71,10 @@ class Flattener extends DataTableManipulator
|
|||
}
|
||||
|
||||
$newDataTable = $dataTable->getEmptyClone($keepFilters);
|
||||
foreach ($dataTable->getRows() as $row) {
|
||||
$this->flattenRow($row, $newDataTable);
|
||||
foreach ($dataTable->getRows() as $rowId => $row) {
|
||||
$this->flattenRow($row, $rowId, $newDataTable);
|
||||
}
|
||||
|
||||
return $newDataTable;
|
||||
}
|
||||
|
||||
|
|
@ -84,15 +84,21 @@ class Flattener extends DataTableManipulator
|
|||
* @param string $labelPrefix
|
||||
* @param bool $parentLogo
|
||||
*/
|
||||
private function flattenRow(Row $row, DataTable $dataTable,
|
||||
private function flattenRow(Row $row, $rowId, DataTable $dataTable,
|
||||
$labelPrefix = '', $parentLogo = false)
|
||||
{
|
||||
$label = $row->getColumn('label');
|
||||
if ($label !== false) {
|
||||
$label = trim($label);
|
||||
if (substr($label, 0, 1) == '/' && $this->recursiveLabelSeparator == '/') {
|
||||
$label = substr($label, 1);
|
||||
|
||||
if ($this->recursiveLabelSeparator == '/') {
|
||||
if (substr($label, 0, 1) == '/') {
|
||||
$label = substr($label, 1);
|
||||
} elseif ($rowId === DataTable::ID_SUMMARY_ROW && $labelPrefix && $label != DataTable::LABEL_SUMMARY_ROW) {
|
||||
$label = ' - ' . $label;
|
||||
}
|
||||
}
|
||||
|
||||
$label = $labelPrefix . $label;
|
||||
$row->setColumn('label', $label);
|
||||
}
|
||||
|
|
@ -103,7 +109,16 @@ class Flattener extends DataTableManipulator
|
|||
$row->setMetadata('logo', $logo);
|
||||
}
|
||||
|
||||
$subTable = $this->loadSubtable($dataTable, $row);
|
||||
/** @var DataTable $subTable */
|
||||
$subTable = $row->getSubtable();
|
||||
|
||||
if ($subTable) {
|
||||
$subTable->applyQueuedFilters();
|
||||
$row->deleteMetadata('idsubdatatable_in_db');
|
||||
} else {
|
||||
$subTable = $this->loadSubtable($dataTable, $row);
|
||||
}
|
||||
|
||||
$row->removeSubtable();
|
||||
|
||||
if ($subTable === null) {
|
||||
|
|
@ -117,8 +132,8 @@ class Flattener extends DataTableManipulator
|
|||
$dataTable->addRow($row);
|
||||
}
|
||||
$prefix = $label . $this->recursiveLabelSeparator;
|
||||
foreach ($subTable->getRows() as $row) {
|
||||
$this->flattenRow($row, $dataTable, $prefix, $logo);
|
||||
foreach ($subTable->getRows() as $rowId => $row) {
|
||||
$this->flattenRow($row, $rowId, $dataTable, $prefix, $logo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -127,6 +142,7 @@ class Flattener extends DataTableManipulator
|
|||
* Remove the flat parameter from the subtable request
|
||||
*
|
||||
* @param array $request
|
||||
* @return array
|
||||
*/
|
||||
protected function manipulateSubtableRequest($request)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
/**
|
||||
* Piwik - Open source web analytics
|
||||
* Piwik - free/libre analytics platform
|
||||
*
|
||||
* @link http://piwik.org
|
||||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
||||
|
|
@ -24,6 +24,7 @@ use Piwik\DataTable\Row;
|
|||
class LabelFilter extends DataTableManipulator
|
||||
{
|
||||
const SEPARATOR_RECURSIVE_LABEL = '>';
|
||||
const TERMINAL_OPERATOR = '@';
|
||||
|
||||
private $labels;
|
||||
private $addLabelIndex;
|
||||
|
|
@ -63,6 +64,10 @@ class LabelFilter extends DataTableManipulator
|
|||
*/
|
||||
private function doFilterRecursiveDescend($labelParts, $dataTable)
|
||||
{
|
||||
// we need to make sure to rebuild the index as some filters change the label column directly via
|
||||
// $row->setColumn('label', '') which would not be noticed in the label index otherwise.
|
||||
$dataTable->rebuildIndex();
|
||||
|
||||
// search for the first part of the tree search
|
||||
$labelPart = array_shift($labelParts);
|
||||
|
||||
|
|
@ -101,6 +106,9 @@ class LabelFilter extends DataTableManipulator
|
|||
protected function manipulateSubtableRequest($request)
|
||||
{
|
||||
unset($request['label']);
|
||||
unset($request['flat']);
|
||||
$request['totals'] = 0;
|
||||
$request['filter_sort_column'] = ''; // do not sort, we only want to find a matching column
|
||||
|
||||
return $request;
|
||||
}
|
||||
|
|
@ -111,16 +119,22 @@ class LabelFilter extends DataTableManipulator
|
|||
* Note: The HTML Encoded version must be tried first, since in ResponseBuilder the $label is unsanitized
|
||||
* via Common::unsanitizeLabelParameter.
|
||||
*
|
||||
* @param string $label
|
||||
* @param string $originalLabel
|
||||
* @return array
|
||||
*/
|
||||
private function getLabelVariations($label)
|
||||
private function getLabelVariations($originalLabel)
|
||||
{
|
||||
static $pageTitleReports = array('getPageTitles', 'getEntryPageTitles', 'getExitPageTitles');
|
||||
|
||||
$originalLabel = trim($originalLabel);
|
||||
|
||||
$isTerminal = substr($originalLabel, 0, 1) == self::TERMINAL_OPERATOR;
|
||||
if ($isTerminal) {
|
||||
$originalLabel = substr($originalLabel, 1);
|
||||
}
|
||||
|
||||
$variations = array();
|
||||
$label = urldecode($label);
|
||||
$label = trim($label);
|
||||
$label = trim(urldecode($originalLabel));
|
||||
|
||||
$sanitizedLabel = Common::sanitizeInputValue($label);
|
||||
$variations[] = $sanitizedLabel;
|
||||
|
|
@ -128,13 +142,20 @@ class LabelFilter extends DataTableManipulator
|
|||
if ($this->apiModule == 'Actions'
|
||||
&& in_array($this->apiMethod, $pageTitleReports)
|
||||
) {
|
||||
// special case: the Actions.getPageTitles report prefixes some labels with a blank.
|
||||
// the blank might be passed by the user but is removed in Request::getRequestArrayFromString.
|
||||
$variations[] = ' ' . $sanitizedLabel;
|
||||
$variations[] = ' ' . $label;
|
||||
if ($isTerminal) {
|
||||
array_unshift($variations, ' ' . $sanitizedLabel);
|
||||
array_unshift($variations, ' ' . $label);
|
||||
} else {
|
||||
// special case: the Actions.getPageTitles report prefixes some labels with a blank.
|
||||
// the blank might be passed by the user but is removed in Request::getRequestArrayFromString.
|
||||
$variations[] = ' ' . $sanitizedLabel;
|
||||
$variations[] = ' ' . $label;
|
||||
}
|
||||
}
|
||||
$variations[] = $label;
|
||||
|
||||
$variations = array_unique($variations);
|
||||
|
||||
return $variations;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
/**
|
||||
* Piwik - Open source web analytics
|
||||
* Piwik - free/libre analytics platform
|
||||
*
|
||||
* @link http://piwik.org
|
||||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
||||
|
|
@ -10,13 +10,9 @@ namespace Piwik\API\DataTableManipulator;
|
|||
|
||||
use Piwik\API\DataTableManipulator;
|
||||
use Piwik\DataTable;
|
||||
use Piwik\DataTable\Row;
|
||||
use Piwik\DataTable\BaseFilter;
|
||||
use Piwik\Period\Range;
|
||||
use Piwik\Period;
|
||||
use Piwik\Piwik;
|
||||
use Piwik\Metrics;
|
||||
use Piwik\Plugins\API\API;
|
||||
use Piwik\Period;
|
||||
use Piwik\Plugin\Report;
|
||||
|
||||
/**
|
||||
* This class is responsible for setting the metadata property 'totals' on each dataTable if the report
|
||||
|
|
@ -26,10 +22,29 @@ use Piwik\Plugins\API\API;
|
|||
class ReportTotalsCalculator extends DataTableManipulator
|
||||
{
|
||||
/**
|
||||
* Cached report metadata array.
|
||||
* Array [readableMetric] => [summed value]
|
||||
* @var array
|
||||
*/
|
||||
private static $reportMetadata = array();
|
||||
private $totals = array();
|
||||
|
||||
/**
|
||||
* @var Report
|
||||
*/
|
||||
private $report;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param bool $apiModule
|
||||
* @param bool $apiMethod
|
||||
* @param array $request
|
||||
* @param Report $report
|
||||
*/
|
||||
public function __construct($apiModule = false, $apiMethod = false, $request = array(), $report = null)
|
||||
{
|
||||
parent::__construct($apiModule, $apiMethod, $request);
|
||||
$this->report = $report;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DataTable $table
|
||||
|
|
@ -46,7 +61,7 @@ class ReportTotalsCalculator extends DataTableManipulator
|
|||
|
||||
try {
|
||||
return $this->manipulate($table);
|
||||
} catch(\Exception $e) {
|
||||
} catch (\Exception $e) {
|
||||
// eg. requests with idSubtable may trigger this exception
|
||||
// (where idSubtable was removed in
|
||||
// ?module=API&method=Events.getNameFromCategoryId&idSubtable=1&secondaryDimension=eventName&format=XML&idSite=1&period=day&date=yesterday&flat=0
|
||||
|
|
@ -62,75 +77,32 @@ class ReportTotalsCalculator extends DataTableManipulator
|
|||
*/
|
||||
protected function manipulateDataTable($dataTable)
|
||||
{
|
||||
$report = $this->findCurrentReport();
|
||||
|
||||
if (!empty($report) && empty($report['dimension'])) {
|
||||
if (!empty($this->report) && !$this->report->getDimension() && !$this->isAllMetricsReport()) {
|
||||
// we currently do not calculate the total value for reports having no dimension
|
||||
return $dataTable;
|
||||
}
|
||||
|
||||
// Array [readableMetric] => [summed value]
|
||||
$totalValues = array();
|
||||
|
||||
$this->totals = array();
|
||||
$firstLevelTable = $this->makeSureToWorkOnFirstLevelDataTable($dataTable);
|
||||
$metricsToCalculate = Metrics::getMetricIdsToProcessReportTotal();
|
||||
|
||||
$metricNames = array();
|
||||
foreach ($metricsToCalculate as $metricId) {
|
||||
if (!$this->hasDataTableMetric($firstLevelTable, $metricId)) {
|
||||
continue;
|
||||
}
|
||||
$metricNames[$metricId] = Metrics::getReadableColumnName($metricId);
|
||||
}
|
||||
|
||||
foreach ($firstLevelTable->getRows() as $row) {
|
||||
$totalValues = $this->sumColumnValueToTotal($row, $metricId, $totalValues);
|
||||
foreach ($firstLevelTable->getRows() as $row) {
|
||||
$columns = $row->getColumns();
|
||||
foreach ($metricNames as $metricId => $metricName) {
|
||||
$this->sumColumnValueToTotal($columns, $metricId, $metricName);
|
||||
}
|
||||
}
|
||||
|
||||
$dataTable->setMetadata('totals', $totalValues);
|
||||
$dataTable->setMetadata('totals', $this->totals);
|
||||
|
||||
return $dataTable;
|
||||
}
|
||||
|
||||
private function hasDataTableMetric(DataTable $dataTable, $metricId)
|
||||
{
|
||||
$firstRow = $dataTable->getFirstRow();
|
||||
|
||||
if (empty($firstRow)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (false === $this->getColumn($firstRow, $metricId)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns column from a given row.
|
||||
* Will work with 2 types of datatable
|
||||
* - raw datatables coming from the archive DB, which columns are int indexed
|
||||
* - datatables processed resulting of API calls, which columns have human readable english names
|
||||
*
|
||||
* @param Row|array $row
|
||||
* @param int $columnIdRaw see consts in Metrics::
|
||||
* @return mixed Value of column, false if not found
|
||||
*/
|
||||
private function getColumn($row, $columnIdRaw)
|
||||
{
|
||||
$columnIdReadable = Metrics::getReadableColumnName($columnIdRaw);
|
||||
|
||||
if ($row instanceof Row) {
|
||||
$raw = $row->getColumn($columnIdRaw);
|
||||
if ($raw !== false) {
|
||||
return $raw;
|
||||
}
|
||||
|
||||
return $row->getColumn($columnIdReadable);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function makeSureToWorkOnFirstLevelDataTable($table)
|
||||
{
|
||||
if (!array_key_exists('idSubtable', $this->request)) {
|
||||
|
|
@ -144,8 +116,8 @@ class ReportTotalsCalculator extends DataTableManipulator
|
|||
$module = $this->apiModule;
|
||||
$action = $this->apiMethod;
|
||||
} else {
|
||||
$module = $firstLevelReport['module'];
|
||||
$action = $firstLevelReport['action'];
|
||||
$module = $firstLevelReport->getModule();
|
||||
$action = $firstLevelReport->getAction();
|
||||
}
|
||||
|
||||
$request = $this->request;
|
||||
|
|
@ -164,33 +136,56 @@ class ReportTotalsCalculator extends DataTableManipulator
|
|||
}
|
||||
}
|
||||
|
||||
return $this->callApiAndReturnDataTable($module, $action, $request);
|
||||
$table = $this->callApiAndReturnDataTable($module, $action, $request);
|
||||
|
||||
if ($table instanceof DataTable\Map) {
|
||||
$table = $table->mergeChildren();
|
||||
}
|
||||
|
||||
return $table;
|
||||
}
|
||||
|
||||
private function sumColumnValueToTotal(Row $row, $metricId, $totalValues)
|
||||
private function sumColumnValueToTotal($columns, $metricId, $metricName)
|
||||
{
|
||||
$value = $this->getColumn($row, $metricId);
|
||||
|
||||
if (false === $value) {
|
||||
|
||||
return $totalValues;
|
||||
$value = false;
|
||||
if (array_key_exists($metricId, $columns)) {
|
||||
$value = $columns[$metricId];
|
||||
}
|
||||
|
||||
$metricName = Metrics::getReadableColumnName($metricId);
|
||||
if ($value === false) {
|
||||
// we do not add $metricId to $possibleMetricNames for a small performance improvement since in most cases
|
||||
// $metricId should be present in $columns so we avoid this foreach loop
|
||||
$possibleMetricNames = array(
|
||||
$metricName,
|
||||
// TODO: this and below is a hack to get report totals to work correctly w/ MultiSites.getAll. can be corrected
|
||||
// when all metrics are described by Metadata classes & internal naming quirks are handled by core system.
|
||||
'Goal_' . $metricName,
|
||||
'Actions_' . $metricName
|
||||
);
|
||||
foreach ($possibleMetricNames as $possibleMetricName) {
|
||||
if (array_key_exists($possibleMetricName, $columns)) {
|
||||
$value = $columns[$possibleMetricName];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (array_key_exists($metricName, $totalValues)) {
|
||||
$totalValues[$metricName] += $value;
|
||||
if ($value === false) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (array_key_exists($metricName, $this->totals)) {
|
||||
$this->totals[$metricName] += $value;
|
||||
} else {
|
||||
$totalValues[$metricName] = $value;
|
||||
$this->totals[$metricName] = $value;
|
||||
}
|
||||
|
||||
return $totalValues;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure to get all rows of the first level table.
|
||||
*
|
||||
* @param array $request
|
||||
* @return array
|
||||
*/
|
||||
protected function manipulateSubtableRequest($request)
|
||||
{
|
||||
|
|
@ -198,6 +193,7 @@ class ReportTotalsCalculator extends DataTableManipulator
|
|||
$request['expanded'] = 0;
|
||||
$request['filter_limit'] = -1;
|
||||
$request['filter_offset'] = 0;
|
||||
$request['filter_sort_column'] = '';
|
||||
|
||||
$parametersToRemove = array('flat');
|
||||
|
||||
|
|
@ -213,38 +209,21 @@ class ReportTotalsCalculator extends DataTableManipulator
|
|||
return $request;
|
||||
}
|
||||
|
||||
private function getReportMetadata()
|
||||
{
|
||||
if (!empty(static::$reportMetadata)) {
|
||||
return static::$reportMetadata;
|
||||
}
|
||||
|
||||
static::$reportMetadata = API::getInstance()->getReportMetadata();
|
||||
|
||||
return static::$reportMetadata;
|
||||
}
|
||||
|
||||
private function findCurrentReport()
|
||||
{
|
||||
foreach ($this->getReportMetadata() as $report) {
|
||||
if ($this->apiMethod == $report['action']
|
||||
&& $this->apiModule == $report['module']) {
|
||||
|
||||
return $report;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function findFirstLevelReport()
|
||||
{
|
||||
foreach ($this->getReportMetadata() as $report) {
|
||||
if (!empty($report['actionToLoadSubTables'])
|
||||
&& $this->apiMethod == $report['actionToLoadSubTables']
|
||||
&& $this->apiModule == $report['module']
|
||||
foreach (Report::getAllReports() as $report) {
|
||||
$actionToLoadSubtables = $report->getActionToLoadSubTables();
|
||||
if ($actionToLoadSubtables == $this->apiMethod
|
||||
&& $this->apiModule == $report->getModule()
|
||||
) {
|
||||
|
||||
return $report;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private function isAllMetricsReport()
|
||||
{
|
||||
return $this->report->getModule() == 'API' && $this->report->getAction() == 'get';
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue