update Piwik to version 2.16 (fixes #91)

This commit is contained in:
oliver 2016-04-10 18:55:57 +02:00
commit d885a4baa9
5833 changed files with 418860 additions and 226988 deletions

View file

@ -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)
{

View file

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

View file

@ -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';
}
}