Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/matomo-org/matomo.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
authormattab <matthieu.aubry@gmail.com>2013-11-13 05:51:14 +0400
committermattab <matthieu.aubry@gmail.com>2013-11-13 05:51:14 +0400
commitf1972940abaeabfd1b9110475a623be228c6a39c (patch)
treec8d949b0408b15da7815efdab5c6394e0d2e3423 /core
parent9caddfb2031715684138e7ea5ef119b512a10da6 (diff)
Refs #4278 Rewriting aggregateNumericMetrics() to use DataTable aggregation only (code reuse)
Diffstat (limited to 'core')
-rw-r--r--core/API/DataTableManipulator.php2
-rw-r--r--core/Archive.php2
-rw-r--r--core/Archive/Parameters.php16
-rw-r--r--core/ArchiveProcessor.php206
-rw-r--r--core/ArchiveProcessor/Parameters.php28
-rw-r--r--core/ArchiveProcessor/PluginsArchiver.php12
-rw-r--r--core/DataTable.php89
-rw-r--r--core/DataTable/Row.php7
-rw-r--r--core/Tracker/Request.php18
9 files changed, 217 insertions, 163 deletions
diff --git a/core/API/DataTableManipulator.php b/core/API/DataTableManipulator.php
index 774863f539..b85a28a707 100644
--- a/core/API/DataTableManipulator.php
+++ b/core/API/DataTableManipulator.php
@@ -55,7 +55,7 @@ abstract class DataTableManipulator
/**
* This method can be used by subclasses to iterate over data tables that might be
- * data table arrays. It calls back the template method self::doManipulate for each table.
+ * data table maps. It calls back the template method self::doManipulate for each table.
* This way, data table arrays can be handled in a transparent fashion.
*
* @param DataTable\Map|DataTable $dataTable
diff --git a/core/Archive.php b/core/Archive.php
index d041963d3c..b95544dfbc 100644
--- a/core/Archive.php
+++ b/core/Archive.php
@@ -392,7 +392,7 @@ class Archive
* loaded. Those subtables, however, will NOT have their subtables loaded.
* @param bool $addMetadataSubtableId Whether to add the database subtable ID as metadata to each datatable,
* or not.
- * @return DataTable
+ * @return DataTable|DataTable\Map
*/
public function getDataTableExpanded($name, $idSubtable = null, $depth = null, $addMetadataSubtableId = true)
{
diff --git a/core/Archive/Parameters.php b/core/Archive/Parameters.php
index 093dc1b3d3..f4a9345d0d 100644
--- a/core/Archive/Parameters.php
+++ b/core/Archive/Parameters.php
@@ -45,8 +45,8 @@ class Parameters
public function __construct($idSites, $periods, Segment $segment)
{
- $this->idSites = $this->getAsNonEmptyArray($idSites, 'idSites');
- $this->periods = $this->getAsNonEmptyArray($periods, 'periods');
+ $this->idSites = $idSites;
+ $this->periods = $periods;
$this->segment = $segment;
}
@@ -60,17 +60,5 @@ class Parameters
return $this->idSites;
}
- private function getAsNonEmptyArray($array, $paramName)
- {
- if (!is_array($array)) {
- $array = array($array);
- }
-
- if (empty($array)) {
- throw new Exception("Archive::__construct: \$$paramName is empty.");
- }
-
- return $array;
- }
}
diff --git a/core/ArchiveProcessor.php b/core/ArchiveProcessor.php
index 489ad4dbeb..441bd149e2 100644
--- a/core/ArchiveProcessor.php
+++ b/core/ArchiveProcessor.php
@@ -16,6 +16,7 @@ use Piwik\ArchiveProcessor\Parameters;
use Piwik\DataAccess\ArchiveWriter;
use Piwik\DataAccess\LogAggregator;
use Piwik\DataTable\Manager;
+use Piwik\DataTable\Map;
use Piwik\Db;
use Piwik\Period;
@@ -133,14 +134,13 @@ class ArchiveProcessor
protected function getArchive()
{
if(empty($this->archive)) {
- $subPeriods = $this->params->getPeriod()->getSubperiods();
- $idSite = $this->params->getSite()->getId();
- $this->archive = Archive::factory($this->params->getSegment(), $subPeriods, array($idSite));
+ $subPeriods = $this->params->getSubPeriods();
+ $idSites = $this->params->getIdSites();
+ $this->archive = Archive::factory($this->params->getSegment(), $subPeriods, $idSites);
}
return $this->archive;
}
-
public function setNumberOfVisits($visits, $visitsConverted)
{
$this->numberOfVisits = $visits;
@@ -175,7 +175,7 @@ class ArchiveProcessor
* These columns will be renamed as per this mapping.
* @var array
*/
- protected static $invalidSummedColumnNameToRenamedName = array(
+ protected static $columnsToRenameAfterAggregation = array(
Metrics::INDEX_NB_UNIQ_VISITORS => Metrics::INDEX_SUM_DAILY_NB_UNIQ_VISITORS
);
@@ -189,8 +189,8 @@ class ArchiveProcessor
* @param int $maximumRowsInDataTableLevelZero Maximum number of rows allowed in the top level DataTable.
* @param int $maximumRowsInSubDataTable Maximum number of rows allowed in each subtable.
* @param string $columnToSortByBeforeTruncation The name of the column to sort by before truncating a DataTable.
- * @param array $columnAggregationOperations Operations for aggregating columns, @see Row::sumRow().
- * @param array $invalidSummedColumnNameToRenamedName For columns that must change names when summed because they
+ * @param array $columnsAggregationOperation Operations for aggregating columns, @see Row::sumRow().
+ * @param array $columnsToRenameAfterAggregation For columns that must change names when summed because they
* cannot be summed, eg,
* `array('nb_uniq_visitors' => 'sum_daily_nb_uniq_visitors')`.
* @return array Returns the row counts of each aggregated report before truncation, eg,
@@ -209,8 +209,8 @@ class ArchiveProcessor
$maximumRowsInDataTableLevelZero = null,
$maximumRowsInSubDataTable = null,
$columnToSortByBeforeTruncation = null,
- &$columnAggregationOperations = null,
- $invalidSummedColumnNameToRenamedName = null)
+ &$columnsAggregationOperation = null,
+ $columnsToRenameAfterAggregation = null)
{
// We clean up below all tables created during this function call (and recursive calls)
$latestUsedTableId = Manager::getInstance()->getMostRecentTableId();
@@ -219,7 +219,7 @@ class ArchiveProcessor
}
$nameToCount = array();
foreach ($recordNames as $recordName) {
- $table = $this->aggregateDataTableRecord($recordName, $invalidSummedColumnNameToRenamedName, $columnAggregationOperations);
+ $table = $this->aggregateDataTableRecord($recordName, $columnsAggregationOperation, $columnsToRenameAfterAggregation);
$nameToCount[$recordName]['level0'] = $table->getRowsCount();
$nameToCount[$recordName]['recursive'] = $table->getRowsCountRecursive();
@@ -254,26 +254,18 @@ class ArchiveProcessor
*/
public function aggregateNumericMetrics($columns, $operationToApply = false)
{
- if (!is_array($columns)) {
- $columns = array($columns);
- }
- $data = $this->getArchive()->getNumeric($columns);
- $operationForColumn = $this->getOperationForColumns($columns, $operationToApply);
- $results = $this->aggregateDataArray($data, $operationForColumn);
- $results = $this->defaultColumnsToZero($columns, $results);
- $this->enrichWithUniqueVisitorsMetric($results);
+ $metrics = $this->getAggregatedNumericMetrics($columns, $operationToApply);
- foreach ($results as $name => $value) {
- $this->archiveWriter->insertRecord($name, $value);
+ foreach($metrics as $column => $value) {
+ $this->archiveWriter->insertRecord($column, $value);
}
-
// if asked for only one field to sum
- if (count($results) == 1) {
- return reset($results);
+ if (count($metrics) == 1) {
+ return reset($metrics);
}
// returns the array of records once summed
- return $results;
+ return $metrics;
}
public function getNumberOfVisits()
@@ -345,33 +337,14 @@ class ArchiveProcessor
* All these DataTables are then added together, and the resulting DataTable is returned.
*
* @param string $name
- * @param array $invalidSummedColumnNameToRenamedName columns in the array (old name, new name) to be renamed as the sum operation is not valid on them (eg. nb_uniq_visitors->sum_daily_nb_uniq_visitors)
- * @param array $columnAggregationOperations Operations for aggregating columns, @see Row::sumRow()
+ * @param array $columnsAggregationOperation Operations for aggregating columns, @see Row::sumRow()
+ * @param array $columnsToRenameAfterAggregation columns in the array (old name, new name) to be renamed as the sum operation is not valid on them (eg. nb_uniq_visitors->sum_daily_nb_uniq_visitors)
* @return DataTable
*/
- protected function aggregateDataTableRecord($name, $invalidSummedColumnNameToRenamedName, $columnAggregationOperations = null)
+ protected function aggregateDataTableRecord($name, $columnsAggregationOperation = null, $columnsToRenameAfterAggregation = null)
{
- $table = new DataTable();
- if (!empty($columnAggregationOperations)) {
- $table->setMetadata(DataTable::COLUMN_AGGREGATION_OPS_METADATA_NAME, $columnAggregationOperations);
- }
-
- $data = $this->getArchive()->getDataTableExpanded($name, $idSubTable = null, $depth = null, $addMetadataSubtableId = false);
- if ($data instanceof DataTable\Map) {
- // as $date => $tableToSum
- foreach ($data->getDataTables() as $tableToSum) {
- $table->addDataTable($tableToSum);
- }
- } else {
- $table->addDataTable($data);
- }
-
- if (is_null($invalidSummedColumnNameToRenamedName)) {
- $invalidSummedColumnNameToRenamedName = self::$invalidSummedColumnNameToRenamedName;
- }
- foreach ($invalidSummedColumnNameToRenamedName as $oldName => $newName) {
- $table->renameColumn($oldName, $newName);
- }
+ $dataTable = $this->getArchive()->getDataTableExpanded($name, $idSubTable = null, $depth = null, $addMetadataSubtableId = false);
+ $table = $this->getAggregatedDataTableMap($dataTable, $columnsAggregationOperation, $columnsToRenameAfterAggregation);
return $table;
}
@@ -388,64 +361,9 @@ class ArchiveProcessor
return $operationForColumn;
}
- protected function aggregateDataArray(array $data, array $operationForColumn)
- {
- $results = array();
- foreach ($data as $row) {
- if (!is_array($row)) {
- // this is not a data array to aggregate
- return $data;
- }
- foreach ($row as $name => $value) {
- $operation = $operationForColumn[$name];
- switch ($operation) {
- case 'sum':
- if (!isset($results[$name])) {
- $results[$name] = 0;
- }
- $results[$name] += $value;
- break;
-
- case 'max':
- if (!isset($results[$name])) {
- $results[$name] = 0;
- }
- $results[$name] = max($results[$name], $value);
- break;
-
- case 'min':
- if (!isset($results[$name])) {
- $results[$name] = $value;
- }
- $results[$name] = min($results[$name], $value);
- break;
-
- case false:
- // do nothing if the operation is not known (eg. nb_uniq_visitors should be not be aggregated)
- break;
-
- default:
- throw new Exception("Operation not applicable.");
- break;
- }
- }
- }
- return $results;
- }
-
- protected function defaultColumnsToZero($columns, $results)
- {
- foreach ($columns as $name) {
- if (!isset($results[$name])) {
- $results[$name] = 0;
- }
- }
- return $results;
- }
-
protected function enrichWithUniqueVisitorsMetric(&$results)
{
- if (array_key_exists('nb_uniq_visitors', $results)) {
+ if (isset($results['nb_uniq_visitors'])) {
if (SettingsPiwik::isUniqueVisitorsEnabled($this->getParams()->getPeriod()->getLabel())) {
$results['nb_uniq_visitors'] = (float)$this->computeNbUniqVisitors();
} else {
@@ -462,9 +380,6 @@ class ArchiveProcessor
if (strpos($column, 'min_') === 0) {
return 'min';
}
- if ($column === 'nb_uniq_visitors') {
- return false;
- }
return 'sum';
}
@@ -483,4 +398,81 @@ class ArchiveProcessor
$data = $query->fetch();
return $data[Metrics::INDEX_NB_UNIQ_VISITORS];
}
+
+ /**
+ * If the DataTable is a Map, sums all DataTable in the map and return the DataTable.
+ *
+ *
+ * @param $data DataTable|DataTable\Map
+ * @param $columnsToRenameAfterAggregation array
+ * @return DataTable
+ */
+ protected function getAggregatedDataTableMap($data, $columnsAggregationOperation, $columnsToRenameAfterAggregation = null)
+ {
+ $table = new DataTable();
+ if (!empty($columnsAggregationOperation)) {
+ $table->setMetadata(DataTable::COLUMN_AGGREGATION_OPS_METADATA_NAME, $columnsAggregationOperation);
+ }
+ if ($data instanceof DataTable\Map) {
+ // as $date => $tableToSum
+ $this->aggregatedDataTableMapsAsOne($data, $table);
+ } else {
+ $table->addDataTable($data);
+ }
+
+ // Rename columns after aggregation
+ if (is_null($columnsToRenameAfterAggregation)) {
+ $columnsToRenameAfterAggregation = self::$columnsToRenameAfterAggregation;
+ }
+ foreach ($columnsToRenameAfterAggregation as $oldName => $newName) {
+ $table->renameColumn($oldName, $newName);
+ }
+ return $table;
+ }
+
+ /**
+ * Aggregates the DataTable\Map into the destination $aggregated
+ * @param $map
+ * @param $aggregated
+ */
+ protected function aggregatedDataTableMapsAsOne(Map $map, DataTable $aggregated)
+ {
+ foreach ($map->getDataTables() as $tableToAggregate) {
+ if($tableToAggregate instanceof Map) {
+ $this->aggregatedDataTableMapsAsOne($tableToAggregate, $aggregated);
+ } else {
+ $aggregated->addDataTable($tableToAggregate);
+ }
+ }
+ }
+
+ protected function getAggregatedNumericMetrics($columns, $operationToApply)
+ {
+ if (!is_array($columns)) {
+ $columns = array($columns);
+ }
+ $operationForColumn = $this->getOperationForColumns($columns, $operationToApply);
+
+ $dataTable = $this->getArchive()->getDataTableFromNumeric($columns);
+
+ $results = $this->getAggregatedDataTableMap($dataTable, $operationForColumn);
+
+ if ($results->getRowsCount() > 1) {
+ throw new Exception("A DataTable is an unexpected state:" . var_export($results, true));
+ }
+ $rowMetrics = $results->getFirstRow();
+ if ($rowMetrics === false) {
+ $metrics = array();
+ } else {
+ $metrics = $rowMetrics->getColumns();
+ }
+ $this->enrichWithUniqueVisitorsMetric($metrics);
+
+ foreach ($columns as $name) {
+ if (!isset($metrics[$name])) {
+ $metrics[$name] = 0;
+ }
+ }
+ return $metrics;
+ }
} \ No newline at end of file
diff --git a/core/ArchiveProcessor/Parameters.php b/core/ArchiveProcessor/Parameters.php
index abcd242f1a..f662ebd276 100644
--- a/core/ArchiveProcessor/Parameters.php
+++ b/core/ArchiveProcessor/Parameters.php
@@ -73,6 +73,28 @@ class Parameters
}
/**
+ * Returns the array of Period which make up this archive.
+ *
+ * @return \Piwik\Period[]
+ */
+ public function getSubPeriods()
+ {
+ if($this->getPeriod()->getLabel() == 'day') {
+ return array( $this->getPeriod() );
+ }
+ return $this->getPeriod()->getSubperiods();
+ }
+
+ /**
+ * @return array
+ */
+ public function getIdSites()
+ {
+ $idSite = $this->getSite()->getId();
+ return array($idSite);
+ }
+
+ /**
* Returns the site we are computing statistics for.
*
* @return Site
@@ -117,9 +139,11 @@ class Parameters
/**
* @return bool
*/
- public function isDayArchive()
+ public function isSingleSiteDayArchive()
{
- return $this->getPeriod()->getLabel() == 'day';
+ $oneSite = count($this->getIdSites()) == 1;
+ $oneDay = $this->getPeriod()->getLabel() == 'day';
+ return $oneDay && $oneSite;
}
public function logStatusDebug($isTemporary)
diff --git a/core/ArchiveProcessor/PluginsArchiver.php b/core/ArchiveProcessor/PluginsArchiver.php
index 31e399f3c1..228ac7cb15 100644
--- a/core/ArchiveProcessor/PluginsArchiver.php
+++ b/core/ArchiveProcessor/PluginsArchiver.php
@@ -48,7 +48,7 @@ class PluginsArchiver
$this->archiveProcessor = new ArchiveProcessor($this->params, $this->archiveWriter);
- $this->isArchiveDay = $this->params->isDayArchive();
+ $this->isSingleSiteDayArchive = $this->params->isSingleSiteDayArchive();
}
/**
@@ -58,7 +58,7 @@ class PluginsArchiver
*/
public function callAggregateCoreMetrics()
{
- if($this->isArchiveDay) {
+ if($this->isSingleSiteDayArchive) {
$metrics = $this->aggregateDayVisitsMetrics();
} else {
$metrics = $this->aggregateMultipleVisitsMetrics();
@@ -91,7 +91,7 @@ class PluginsArchiver
$archiver = new $archiverClass($this->archiveProcessor);
if($this->shouldProcessReportsForPlugin($pluginName)) {
- if($this->isArchiveDay) {
+ if($this->isSingleSiteDayArchive) {
$archiver->aggregateDayReport();
} else {
$archiver->aggregateMultipleReports();
@@ -99,7 +99,7 @@ class PluginsArchiver
}
}
- if (!$this->isArchiveDay && $visits) {
+ if (!$this->isSingleSiteDayArchive && $visits) {
ArchiveSelector::purgeOutdatedArchives($this->params->getPeriod()->getDateStart());
}
}
@@ -150,8 +150,8 @@ class PluginsArchiver
return true;
}
if (Rules::shouldProcessReportsAllPlugins(
- $this->archiveProcessor->getParams()->getSegment(),
- $this->archiveProcessor->getParams()->getPeriod()->getLabel())) {
+ $this->params->getSegment(),
+ $this->params->getPeriod()->getLabel())) {
return true;
}
diff --git a/core/DataTable.php b/core/DataTable.php
index 6fc0b61e54..d27564f14b 100644
--- a/core/DataTable.php
+++ b/core/DataTable.php
@@ -19,6 +19,7 @@ use Piwik\DataTable\Manager;
use Piwik\DataTable\Renderer\Html;
use Piwik\DataTable\Row;
use Piwik\DataTable\Row\DataTableSummaryRow;
+use Piwik\DataTable\Simple;
use ReflectionClass;
/**
@@ -472,28 +473,15 @@ class DataTable implements DataTableInterface
*/
public function addDataTable(DataTable $tableToSum)
{
- foreach ($tableToSum->getRows() as $row) {
- $labelToLookFor = $row->getColumn('label');
- $rowFound = $this->getRowFromLabel($labelToLookFor);
- if ($rowFound === false) {
- if ($labelToLookFor === self::LABEL_SUMMARY_ROW) {
- $this->addSummaryRow($row);
- } else {
- $this->addRow($row);
- }
- } else {
- $rowFound->sumRow($row, $copyMeta = true, $this->getMetadata(self::COLUMN_AGGREGATION_OPS_METADATA_NAME));
-
- // if the row to add has a subtable whereas the current row doesn't
- // we simply add it (cloning the subtable)
- // if the row has the subtable already
- // then we have to recursively sum the subtables
- if (($idSubTable = $row->getIdSubDataTable()) !== null) {
- $subTable = Manager::getInstance()->getTable($idSubTable);
- $subTable->metadata[self::COLUMN_AGGREGATION_OPS_METADATA_NAME]
- = $this->getMetadata(self::COLUMN_AGGREGATION_OPS_METADATA_NAME);
- $rowFound->sumSubtable($subTable);
- }
+ if($tableToSum instanceof Simple) {
+ if($tableToSum->getRowsCount() > 1) {
+ throw new Exception("Did not expect a Simple table with more than one row in addDataTable()");
+ }
+ $row = $tableToSum->getFirstRow();
+ $this->aggregateRowFromSimpleTable($row);
+ } else {
+ foreach ($tableToSum->getRows() as $row) {
+ $this->aggregateRowWithLabel($row);
}
}
}
@@ -1480,8 +1468,7 @@ class DataTable implements DataTableInterface
}
/**
- * Returns a new DataTable in which the rows of this table are replaced with its subtable's
- * rows.
+ * Returns a new DataTable in which the rows of this table are replaced with the aggregatated rows of all its subtable's.
*
* @param string|bool $labelColumn If supplied the label of the parent row will be added to
* a new column in each subtable row.
@@ -1569,4 +1556,58 @@ class DataTable implements DataTableInterface
$result->addRowsFromSerializedArray($data);
return $result;
}
+
+ /**
+ * Aggregates the $row columns to this table.
+ *
+ * $row must have a column "label". The $row will be summed to this table's row with the same label.
+ *
+ * @param $row
+ * @throws \Exception
+ */
+ protected function aggregateRowWithLabel(Row $row)
+ {
+ $labelToLookFor = $row->getColumn('label');
+ if ($labelToLookFor === false) {
+ throw new Exception("Label column not found in the table to add in addDataTable()");
+ }
+ $rowFound = $this->getRowFromLabel($labelToLookFor);
+ if ($rowFound === false) {
+ if ($labelToLookFor === self::LABEL_SUMMARY_ROW) {
+ $this->addSummaryRow($row);
+ } else {
+ $this->addRow($row);
+ }
+ } else {
+ $rowFound->sumRow($row, $copyMeta = true, $this->getMetadata(self::COLUMN_AGGREGATION_OPS_METADATA_NAME));
+
+ // if the row to add has a subtable whereas the current row doesn't
+ // we simply add it (cloning the subtable)
+ // if the row has the subtable already
+ // then we have to recursively sum the subtables
+ if (($idSubTable = $row->getIdSubDataTable()) !== null) {
+ $subTable = Manager::getInstance()->getTable($idSubTable);
+ $subTable->metadata[self::COLUMN_AGGREGATION_OPS_METADATA_NAME]
+ = $this->getMetadata(self::COLUMN_AGGREGATION_OPS_METADATA_NAME);
+ $rowFound->sumSubtable($subTable);
+ }
+ }
+ }
+
+ /**
+ * @param $row
+ */
+ protected function aggregateRowFromSimpleTable($row)
+ {
+ if ($row === false) {
+ return;
+
+ }
+ $thisRow = $this->getFirstRow();
+ if ($thisRow === false) {
+ $thisRow = new Row;
+ $this->addRow($thisRow);
+ }
+ $thisRow->sumRow($row, $copyMeta = true, $this->getMetadata(self::COLUMN_AGGREGATION_OPS_METADATA_NAME));
+ }
} \ No newline at end of file
diff --git a/core/DataTable/Row.php b/core/DataTable/Row.php
index ecfb8ef82f..a8b3b24707 100644
--- a/core/DataTable/Row.php
+++ b/core/DataTable/Row.php
@@ -469,7 +469,11 @@ class Row
if ($columnToSumName == Metrics::INDEX_MAX_ACTIONS) {
$operation = 'max';
}
+ if(empty($operation)) {
+ throw new Exception("Unknown aggregation operation for column $columnToSumName.");
+ }
$newValue = $this->getColumnValuesMerged($operation, $thisColumnValue, $columnToSumValue);
+
$this->setColumn($columnToSumName, $newValue);
}
}
@@ -500,9 +504,10 @@ class Row
}
break;
case 'sum':
- default:
$newValue = $this->sumRowArray($thisColumnValue, $columnToSumValue);
break;
+ default:
+ throw new Exception("Unknown operation '$operation'.");
}
return $newValue;
}
diff --git a/core/Tracker/Request.php b/core/Tracker/Request.php
index 720f70f8ce..13f81eab98 100644
--- a/core/Tracker/Request.php
+++ b/core/Tracker/Request.php
@@ -1,4 +1,13 @@
<?php
+/**
+ * Piwik - Open source web analytics
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ * @category Piwik
+ * @package Piwik
+ */
namespace Piwik\Tracker;
use Exception;
@@ -10,14 +19,9 @@ use Piwik\Piwik;
use Piwik\Tracker;
/**
- * Piwik - Open source web analytics
+ * The Request object holding the http parameters for this tracking request. Use getParam() to fetch a named parameter.
*
- * @link http://piwik.org
- * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- *
- * @category Piwik
- * @package Piwik
- * @api
+ * @package Piwik\Tracker
*/
class Request
{