hide map for Character groups Quest Stations when there are no stations
This commit is contained in:
commit
df14dfafc3
4371 changed files with 1220224 additions and 0 deletions
336
www/analytics/core/Archive/DataCollection.php
Normal file
336
www/analytics/core/Archive/DataCollection.php
Normal file
|
|
@ -0,0 +1,336 @@
|
|||
<?php
|
||||
/**
|
||||
* Piwik - Open source web analytics
|
||||
*
|
||||
* @link http://piwik.org
|
||||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
||||
*
|
||||
*/
|
||||
|
||||
namespace Piwik\Archive;
|
||||
|
||||
use Exception;
|
||||
use Piwik\DataTable;
|
||||
|
||||
/**
|
||||
* This class is used to hold and transform archive data for the Archive class.
|
||||
*
|
||||
* Archive data is loaded into an instance of this type, can be indexed by archive
|
||||
* metadata (such as the site ID, period string, etc.), and can be transformed into
|
||||
* DataTable and Map instances.
|
||||
*/
|
||||
class DataCollection
|
||||
{
|
||||
const METADATA_CONTAINER_ROW_KEY = '_metadata';
|
||||
|
||||
/**
|
||||
* The archive data, indexed first by site ID and then by period date range. Eg,
|
||||
*
|
||||
* array(
|
||||
* '0' => array(
|
||||
* array(
|
||||
* '2012-01-01,2012-01-01' => array(...),
|
||||
* '2012-01-02,2012-01-02' => array(...),
|
||||
* )
|
||||
* ),
|
||||
* '1' => array(
|
||||
* array(
|
||||
* '2012-01-01,2012-01-01' => array(...),
|
||||
* )
|
||||
* )
|
||||
* )
|
||||
*
|
||||
* Archive data can be either a numeric value or a serialized string blob. Every
|
||||
* piece of archive data is associated by it's archive name. For example,
|
||||
* the array(...) above could look like:
|
||||
*
|
||||
* array(
|
||||
* 'nb_visits' => 1,
|
||||
* 'nb_actions' => 2
|
||||
* )
|
||||
*
|
||||
* There is a special element '_metadata' in data rows that holds values treated
|
||||
* as DataTable metadata.
|
||||
*/
|
||||
private $data = array();
|
||||
|
||||
/**
|
||||
* The whole list of metric/record names that were used in the archive query.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $dataNames;
|
||||
|
||||
/**
|
||||
* The type of data that was queried for (ie, "blob" or "numeric").
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $dataType;
|
||||
|
||||
/**
|
||||
* The default values to use for each metric/record name that's being queried
|
||||
* for.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $defaultRow;
|
||||
|
||||
/**
|
||||
* The list of all site IDs that were queried for.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $sitesId;
|
||||
|
||||
/**
|
||||
* The list of all periods that were queried for. Each period is associated with
|
||||
* the period's range string. Eg,
|
||||
*
|
||||
* array(
|
||||
* '2012-01-01,2012-01-31' => new Period(...),
|
||||
* '2012-02-01,2012-02-28' => new Period(...),
|
||||
* )
|
||||
*
|
||||
* @var \Piwik\Period[]
|
||||
*/
|
||||
private $periods;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param array $dataNames @see $this->dataNames
|
||||
* @param string $dataType @see $this->dataType
|
||||
* @param array $sitesId @see $this->sitesId
|
||||
* @param \Piwik\Period[] $periods @see $this->periods
|
||||
* @param array $defaultRow @see $this->defaultRow
|
||||
*/
|
||||
public function __construct($dataNames, $dataType, $sitesId, $periods, $defaultRow = null)
|
||||
{
|
||||
$this->dataNames = $dataNames;
|
||||
$this->dataType = $dataType;
|
||||
|
||||
if ($defaultRow === null) {
|
||||
$defaultRow = array_fill_keys($dataNames, 0);
|
||||
}
|
||||
|
||||
$this->sitesId = $sitesId;
|
||||
|
||||
foreach ($periods as $period) {
|
||||
$this->periods[$period->getRangeString()] = $period;
|
||||
}
|
||||
$this->defaultRow = $defaultRow;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the data for a specific site & period. If there is
|
||||
* no data for the given site ID & period, it is set to the default row.
|
||||
*
|
||||
* @param int $idSite
|
||||
* @param string $period eg, '2012-01-01,2012-01-31'
|
||||
*/
|
||||
public function &get($idSite, $period)
|
||||
{
|
||||
if (!isset($this->data[$idSite][$period])) {
|
||||
$this->data[$idSite][$period] = $this->defaultRow;
|
||||
}
|
||||
return $this->data[$idSite][$period];
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new metadata to the data for specific site & period. If there is no
|
||||
* data for the given site ID & period, it is set to the default row.
|
||||
*
|
||||
* Note: Site ID and period range string are two special types of metadata. Since
|
||||
* the data stored in this class is indexed by site & period, this metadata is not
|
||||
* stored in individual data rows.
|
||||
*
|
||||
* @param int $idSite
|
||||
* @param string $period eg, '2012-01-01,2012-01-31'
|
||||
* @param string $name The metadata name.
|
||||
* @param mixed $value The metadata name.
|
||||
*/
|
||||
public function addMetadata($idSite, $period, $name, $value)
|
||||
{
|
||||
$row = & $this->get($idSite, $period);
|
||||
$row[self::METADATA_CONTAINER_ROW_KEY][$name] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns archive data as an array indexed by metadata.
|
||||
*
|
||||
* @param array $resultIndices An array mapping metadata names to pretty labels
|
||||
* for them. Each archive data row will be indexed
|
||||
* by the metadata specified here.
|
||||
*
|
||||
* Eg, array('site' => 'idSite', 'period' => 'Date')
|
||||
* @return array
|
||||
*/
|
||||
public function getIndexedArray($resultIndices)
|
||||
{
|
||||
$indexKeys = array_keys($resultIndices);
|
||||
|
||||
$result = $this->createOrderedIndex($indexKeys);
|
||||
foreach ($this->data as $idSite => $rowsByPeriod) {
|
||||
foreach ($rowsByPeriod as $period => $row) {
|
||||
// FIXME: This hack works around a strange bug that occurs when getting
|
||||
// archive IDs through ArchiveProcessing instances. When a table
|
||||
// does not already exist, for some reason the archive ID for
|
||||
// today (or from two days ago) will be added to the Archive
|
||||
// instances list. The Archive instance will then select data
|
||||
// for periods outside of the requested set.
|
||||
// working around the bug here, but ideally, we need to figure
|
||||
// out why incorrect idarchives are being selected.
|
||||
if (empty($this->periods[$period])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->putRowInIndex($result, $indexKeys, $row, $idSite, $period);
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns archive data as a DataTable indexed by metadata. Indexed data will
|
||||
* be represented by Map instances.
|
||||
*
|
||||
* @param array $resultIndices An array mapping metadata names to pretty labels
|
||||
* for them. Each archive data row will be indexed
|
||||
* by the metadata specified here.
|
||||
*
|
||||
* Eg, array('site' => 'idSite', 'period' => 'Date')
|
||||
* @return DataTable|DataTable\Map
|
||||
*/
|
||||
public function getDataTable($resultIndices)
|
||||
{
|
||||
$dataTableFactory = new DataTableFactory(
|
||||
$this->dataNames, $this->dataType, $this->sitesId, $this->periods, $this->defaultRow);
|
||||
|
||||
$index = $this->getIndexedArray($resultIndices);
|
||||
return $dataTableFactory->make($index, $resultIndices);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns archive data as a DataTable indexed by metadata. Indexed data will
|
||||
* be represented by Map instances. Each DataTable will have
|
||||
* its subtable IDs set.
|
||||
*
|
||||
* This function will only work if blob data was loaded and only one record
|
||||
* was loaded (not including subtables of the record).
|
||||
*
|
||||
* @param array $resultIndices An array mapping metadata names to pretty labels
|
||||
* for them. Each archive data row will be indexed
|
||||
* by the metadata specified here.
|
||||
*
|
||||
* Eg, array('site' => 'idSite', 'period' => 'Date')
|
||||
* @param int|null $idSubTable The subtable to return.
|
||||
* @param int|null $depth max depth for subtables.
|
||||
* @param bool $addMetadataSubTableId Whether to add the DB subtable ID as metadata
|
||||
* to each datatable, or not.
|
||||
* @throws Exception
|
||||
* @return DataTable|DataTable\Map
|
||||
*/
|
||||
public function getExpandedDataTable($resultIndices, $idSubTable = null, $depth = null, $addMetadataSubTableId = false)
|
||||
{
|
||||
if ($this->dataType != 'blob') {
|
||||
throw new Exception("DataCollection: cannot call getExpandedDataTable with "
|
||||
. "{$this->dataType} data types. Only works with blob data.");
|
||||
}
|
||||
|
||||
if (count($this->dataNames) !== 1) {
|
||||
throw new Exception("DataCollection: cannot call getExpandedDataTable with "
|
||||
. "more than one record.");
|
||||
}
|
||||
|
||||
$dataTableFactory = new DataTableFactory(
|
||||
$this->dataNames, 'blob', $this->sitesId, $this->periods, $this->defaultRow);
|
||||
$dataTableFactory->expandDataTable($depth, $addMetadataSubTableId);
|
||||
$dataTableFactory->useSubtable($idSubTable);
|
||||
|
||||
$index = $this->getIndexedArray($resultIndices);
|
||||
return $dataTableFactory->make($index, $resultIndices);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns metadata for a data row.
|
||||
*
|
||||
* @param array $data The data row.
|
||||
* @return array
|
||||
*/
|
||||
public static function getDataRowMetadata($data)
|
||||
{
|
||||
if (isset($data[self::METADATA_CONTAINER_ROW_KEY])) {
|
||||
return $data[self::METADATA_CONTAINER_ROW_KEY];
|
||||
} else {
|
||||
return array();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all table metadata from a data row.
|
||||
*
|
||||
* @param array $data The data row.
|
||||
*/
|
||||
public static function removeMetadataFromDataRow(&$data)
|
||||
{
|
||||
unset($data[self::METADATA_CONTAINER_ROW_KEY]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an empty index using a list of metadata names. If the 'site' and/or
|
||||
* 'period' metadata names are supplied, empty rows are added for every site/period
|
||||
* that was queried for.
|
||||
*
|
||||
* Using this function ensures consistent ordering in the indexed result.
|
||||
*
|
||||
* @param array $metadataNamesToIndexBy List of metadata names to index archive data by.
|
||||
* @return array
|
||||
*/
|
||||
private function createOrderedIndex($metadataNamesToIndexBy)
|
||||
{
|
||||
$result = array();
|
||||
|
||||
if (!empty($metadataNamesToIndexBy)) {
|
||||
$metadataName = array_shift($metadataNamesToIndexBy);
|
||||
|
||||
if ($metadataName == DataTableFactory::TABLE_METADATA_SITE_INDEX) {
|
||||
$indexKeyValues = array_values($this->sitesId);
|
||||
} else if ($metadataName == DataTableFactory::TABLE_METADATA_PERIOD_INDEX) {
|
||||
$indexKeyValues = array_keys($this->periods);
|
||||
}
|
||||
|
||||
foreach ($indexKeyValues as $key) {
|
||||
$result[$key] = $this->createOrderedIndex($metadataNamesToIndexBy);
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts an archive data row in an index.
|
||||
*/
|
||||
private function putRowInIndex(&$index, $metadataNamesToIndexBy, $row, $idSite, $period)
|
||||
{
|
||||
$currentLevel = & $index;
|
||||
|
||||
foreach ($metadataNamesToIndexBy as $metadataName) {
|
||||
if ($metadataName == DataTableFactory::TABLE_METADATA_SITE_INDEX) {
|
||||
$key = $idSite;
|
||||
} else if ($metadataName == DataTableFactory::TABLE_METADATA_PERIOD_INDEX) {
|
||||
$key = $period;
|
||||
} else {
|
||||
$key = $row[self::METADATA_CONTAINER_ROW_KEY][$metadataName];
|
||||
}
|
||||
|
||||
if (!isset($currentLevel[$key])) {
|
||||
$currentLevel[$key] = array();
|
||||
}
|
||||
|
||||
$currentLevel = & $currentLevel[$key];
|
||||
}
|
||||
|
||||
$currentLevel = $row;
|
||||
}
|
||||
}
|
||||
426
www/analytics/core/Archive/DataTableFactory.php
Normal file
426
www/analytics/core/Archive/DataTableFactory.php
Normal file
|
|
@ -0,0 +1,426 @@
|
|||
<?php
|
||||
/**
|
||||
* Piwik - Open source web analytics
|
||||
*
|
||||
* @link http://piwik.org
|
||||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
||||
*
|
||||
*/
|
||||
|
||||
namespace Piwik\Archive;
|
||||
|
||||
use Piwik\DataTable;
|
||||
use Piwik\DataTable\Row;
|
||||
use Piwik\Site;
|
||||
|
||||
/**
|
||||
* Creates a DataTable or Set instance based on an array
|
||||
* index created by DataCollection.
|
||||
*
|
||||
* This class is only used by DataCollection.
|
||||
*/
|
||||
class DataTableFactory
|
||||
{
|
||||
/**
|
||||
* @see DataCollection::$dataNames.
|
||||
*/
|
||||
private $dataNames;
|
||||
|
||||
/**
|
||||
* @see DataCollection::$dataType.
|
||||
*/
|
||||
private $dataType;
|
||||
|
||||
/**
|
||||
* Whether to expand the DataTables that're created or not. Expanding a DataTable
|
||||
* means creating DataTables using subtable blobs and correctly setting the subtable
|
||||
* IDs of all DataTables.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $expandDataTable = false;
|
||||
|
||||
/**
|
||||
* Whether to add the subtable ID used in the database to the in-memory DataTables
|
||||
* as metadata or not.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $addMetadataSubtableId = false;
|
||||
|
||||
/**
|
||||
* The maximum number of subtable levels to create when creating an expanded
|
||||
* DataTable.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $maxSubtableDepth = null;
|
||||
|
||||
/**
|
||||
* @see DataCollection::$sitesId.
|
||||
*/
|
||||
private $sitesId;
|
||||
|
||||
/**
|
||||
* @see DataCollection::$periods.
|
||||
*/
|
||||
private $periods;
|
||||
|
||||
/**
|
||||
* The ID of the subtable to create a DataTable for. Only relevant for blob data.
|
||||
*
|
||||
* @var int|null
|
||||
*/
|
||||
private $idSubtable = null;
|
||||
|
||||
/**
|
||||
* @see DataCollection::$defaultRow.
|
||||
*/
|
||||
private $defaultRow;
|
||||
|
||||
const TABLE_METADATA_SITE_INDEX = 'site';
|
||||
const TABLE_METADATA_PERIOD_INDEX = 'period';
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct($dataNames, $dataType, $sitesId, $periods, $defaultRow)
|
||||
{
|
||||
$this->dataNames = $dataNames;
|
||||
$this->dataType = $dataType;
|
||||
$this->sitesId = $sitesId;
|
||||
|
||||
//here index period by string only
|
||||
$this->periods = $periods;
|
||||
$this->defaultRow = $defaultRow;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells the factory instance to expand the DataTables that are created by
|
||||
* creating subtables and setting the subtable IDs of rows w/ subtables correctly.
|
||||
*
|
||||
* @param null|int $maxSubtableDepth max depth for subtables.
|
||||
* @param bool $addMetadataSubtableId Whether to add the subtable ID used in the
|
||||
* database to the in-memory DataTables as
|
||||
* metadata or not.
|
||||
*/
|
||||
public function expandDataTable($maxSubtableDepth = null, $addMetadataSubtableId = false)
|
||||
{
|
||||
$this->expandDataTable = true;
|
||||
$this->maxSubtableDepth = $maxSubtableDepth;
|
||||
$this->addMetadataSubtableId = $addMetadataSubtableId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells the factory instance to create a DataTable using a blob with the
|
||||
* supplied subtable ID.
|
||||
*
|
||||
* @param int $idSubtable An in-database subtable ID.
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function useSubtable($idSubtable)
|
||||
{
|
||||
if (count($this->dataNames) !== 1) {
|
||||
throw new \Exception("DataTableFactory: Getting subtables for multiple records in one"
|
||||
. " archive query is not currently supported.");
|
||||
}
|
||||
|
||||
$this->idSubtable = $idSubtable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a DataTable|Set instance using an index of
|
||||
* archive data.
|
||||
*
|
||||
* @param array $index @see DataCollection
|
||||
* @param array $resultIndices an array mapping metadata names with pretty metadata
|
||||
* labels.
|
||||
* @return DataTable|DataTable\Map
|
||||
*/
|
||||
public function make($index, $resultIndices)
|
||||
{
|
||||
if (empty($resultIndices)) {
|
||||
// for numeric data, if there's no index (and thus only 1 site & period in the query),
|
||||
// we want to display every queried metric name
|
||||
if (empty($index)
|
||||
&& $this->dataType == 'numeric'
|
||||
) {
|
||||
$index = $this->defaultRow;
|
||||
}
|
||||
|
||||
$dataTable = $this->createDataTable($index, $keyMetadata = array());
|
||||
} else {
|
||||
$dataTable = $this->createDataTableMapFromIndex($index, $resultIndices, $keyMetadata = array());
|
||||
}
|
||||
|
||||
$this->transformMetadata($dataTable);
|
||||
return $dataTable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a DataTable|Set instance using an array
|
||||
* of blobs.
|
||||
*
|
||||
* If only one record is being queried, a single DataTable will
|
||||
* be returned. Otherwise, a DataTable\Map is returned that indexes
|
||||
* DataTables by record name.
|
||||
*
|
||||
* If expandDataTable was called, and only one record is being queried,
|
||||
* the created DataTable's subtables will be expanded.
|
||||
*
|
||||
* @param array $blobRow
|
||||
* @return DataTable|DataTable\Map
|
||||
*/
|
||||
private function makeFromBlobRow($blobRow)
|
||||
{
|
||||
if ($blobRow === false) {
|
||||
return new DataTable();
|
||||
}
|
||||
|
||||
if (count($this->dataNames) === 1) {
|
||||
return $this->makeDataTableFromSingleBlob($blobRow);
|
||||
} else {
|
||||
return $this->makeIndexedByRecordNameDataTable($blobRow);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a DataTable for one record from an archive data row.
|
||||
*
|
||||
* @see makeFromBlobRow
|
||||
*
|
||||
* @param array $blobRow
|
||||
* @return DataTable
|
||||
*/
|
||||
private function makeDataTableFromSingleBlob($blobRow)
|
||||
{
|
||||
$recordName = reset($this->dataNames);
|
||||
if ($this->idSubtable !== null) {
|
||||
$recordName .= '_' . $this->idSubtable;
|
||||
}
|
||||
|
||||
if (!empty($blobRow[$recordName])) {
|
||||
$table = DataTable::fromSerializedArray($blobRow[$recordName]);
|
||||
} else {
|
||||
$table = new DataTable();
|
||||
}
|
||||
|
||||
// set table metadata
|
||||
$table->setMetadataValues(DataCollection::getDataRowMetadata($blobRow));
|
||||
|
||||
if ($this->expandDataTable) {
|
||||
$table->enableRecursiveFilters();
|
||||
$this->setSubtables($table, $blobRow);
|
||||
}
|
||||
|
||||
return $table;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a DataTable for every record in an archive data row and puts them
|
||||
* in a DataTable\Map instance.
|
||||
*
|
||||
* @param array $blobRow
|
||||
* @return DataTable\Map
|
||||
*/
|
||||
private function makeIndexedByRecordNameDataTable($blobRow)
|
||||
{
|
||||
$table = new DataTable\Map();
|
||||
$table->setKeyName('recordName');
|
||||
|
||||
$tableMetadata = DataCollection::getDataRowMetadata($blobRow);
|
||||
|
||||
foreach ($blobRow as $name => $blob) {
|
||||
$newTable = DataTable::fromSerializedArray($blob);
|
||||
$newTable->setAllTableMetadata($tableMetadata);
|
||||
|
||||
$table->addTable($newTable, $name);
|
||||
}
|
||||
|
||||
return $table;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Set from an array index.
|
||||
*
|
||||
* @param array $index @see DataCollection
|
||||
* @param array $resultIndices @see make
|
||||
* @param array $keyMetadata The metadata to add to the table when it's created.
|
||||
* @return DataTable\Map
|
||||
*/
|
||||
private function createDataTableMapFromIndex($index, $resultIndices, $keyMetadata = array())
|
||||
{
|
||||
$resultIndexLabel = reset($resultIndices);
|
||||
$resultIndex = key($resultIndices);
|
||||
|
||||
array_shift($resultIndices);
|
||||
|
||||
$result = new DataTable\Map();
|
||||
$result->setKeyName($resultIndexLabel);
|
||||
|
||||
foreach ($index as $label => $value) {
|
||||
$keyMetadata[$resultIndex] = $label;
|
||||
|
||||
if (empty($resultIndices)) {
|
||||
$newTable = $this->createDataTable($value, $keyMetadata);
|
||||
} else {
|
||||
$newTable = $this->createDataTableMapFromIndex($value, $resultIndices, $keyMetadata);
|
||||
}
|
||||
|
||||
$result->addTable($newTable, $this->prettifyIndexLabel($resultIndex, $label));
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a DataTable instance from an index row.
|
||||
*
|
||||
* @param array $data An archive data row.
|
||||
* @param array $keyMetadata The metadata to add to the table(s) when created.
|
||||
* @return DataTable|DataTable\Map
|
||||
*/
|
||||
private function createDataTable($data, $keyMetadata)
|
||||
{
|
||||
if ($this->dataType == 'blob') {
|
||||
$result = $this->makeFromBlobRow($data);
|
||||
} else {
|
||||
$result = $this->makeFromMetricsArray($data);
|
||||
}
|
||||
$this->setTableMetadata($keyMetadata, $result);
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates DataTables from $dataTable's subtable blobs (stored in $blobRow) and sets
|
||||
* the subtable IDs of each DataTable row.
|
||||
*
|
||||
* @param DataTable $dataTable
|
||||
* @param array $blobRow An array associating record names (w/ subtable if applicable)
|
||||
* with blob values. This should hold every subtable blob for
|
||||
* the loaded DataTable.
|
||||
* @param int $treeLevel
|
||||
*/
|
||||
private function setSubtables($dataTable, $blobRow, $treeLevel = 0)
|
||||
{
|
||||
if ($this->maxSubtableDepth
|
||||
&& $treeLevel >= $this->maxSubtableDepth
|
||||
) {
|
||||
// unset the subtables so DataTableManager doesn't throw
|
||||
foreach ($dataTable->getRows() as $row) {
|
||||
$row->removeSubtable();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$dataName = reset($this->dataNames);
|
||||
|
||||
foreach ($dataTable->getRows() as $row) {
|
||||
$sid = $row->getIdSubDataTable();
|
||||
if ($sid === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$blobName = $dataName . "_" . $sid;
|
||||
if (isset($blobRow[$blobName])) {
|
||||
$subtable = DataTable::fromSerializedArray($blobRow[$blobName]);
|
||||
$this->setSubtables($subtable, $blobRow, $treeLevel + 1);
|
||||
|
||||
// we edit the subtable ID so that it matches the newly table created in memory
|
||||
// NB: we dont overwrite the datatableid in the case we are displaying the table expanded.
|
||||
if ($this->addMetadataSubtableId) {
|
||||
// this will be written back to the column 'idsubdatatable' just before rendering,
|
||||
// see Renderer/Php.php
|
||||
$row->addMetadata('idsubdatatable_in_db', $row->getIdSubDataTable());
|
||||
}
|
||||
|
||||
$row->setSubtable($subtable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts site IDs and period string ranges into Site instances and
|
||||
* Period instances in DataTable metadata.
|
||||
*/
|
||||
private function transformMetadata($table)
|
||||
{
|
||||
$periods = $this->periods;
|
||||
$table->filter(function ($table) use ($periods) {
|
||||
$table->setMetadata(DataTableFactory::TABLE_METADATA_SITE_INDEX, new Site($table->getMetadata(DataTableFactory::TABLE_METADATA_SITE_INDEX)));
|
||||
$table->setMetadata(DataTableFactory::TABLE_METADATA_PERIOD_INDEX, $periods[$table->getMetadata(DataTableFactory::TABLE_METADATA_PERIOD_INDEX)]);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the pretty version of an index label.
|
||||
*
|
||||
* @param string $labelType eg, 'site', 'period', etc.
|
||||
* @param string $label eg, '0', '1', '2012-01-01,2012-01-31', etc.
|
||||
* @return string
|
||||
*/
|
||||
private function prettifyIndexLabel($labelType, $label)
|
||||
{
|
||||
if ($labelType == self::TABLE_METADATA_PERIOD_INDEX) { // prettify period labels
|
||||
return $this->periods[$label]->getPrettyString();
|
||||
}
|
||||
return $label;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $keyMetadata
|
||||
* @param $result
|
||||
*/
|
||||
private function setTableMetadata($keyMetadata, $result)
|
||||
{
|
||||
if (!isset($keyMetadata[DataTableFactory::TABLE_METADATA_SITE_INDEX])) {
|
||||
$keyMetadata[DataTableFactory::TABLE_METADATA_SITE_INDEX] = reset($this->sitesId);
|
||||
}
|
||||
|
||||
if (!isset($keyMetadata[DataTableFactory::TABLE_METADATA_PERIOD_INDEX])) {
|
||||
reset($this->periods);
|
||||
$keyMetadata[DataTableFactory::TABLE_METADATA_PERIOD_INDEX] = key($this->periods);
|
||||
}
|
||||
|
||||
// Note: $result can be a DataTable\Map
|
||||
$result->filter(function ($table) use ($keyMetadata) {
|
||||
foreach ($keyMetadata as $name => $value) {
|
||||
$table->setMetadata($name, $value);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $data
|
||||
* @return DataTable\Simple
|
||||
*/
|
||||
private function makeFromMetricsArray($data)
|
||||
{
|
||||
$table = new DataTable\Simple();
|
||||
|
||||
if (!empty($data)) {
|
||||
$table->setAllTableMetadata(DataCollection::getDataRowMetadata($data));
|
||||
|
||||
DataCollection::removeMetadataFromDataRow($data);
|
||||
|
||||
$table->addRow(new Row(array(Row::COLUMNS => $data)));
|
||||
} else {
|
||||
// if we're querying numeric data, we couldn't find any, and we're only
|
||||
// looking for one metric, add a row w/ one column w/ value 0. this is to
|
||||
// ensure that the PHP renderer outputs 0 when only one column is queried.
|
||||
// w/o this code, an empty array would be created, and other parts of Piwik
|
||||
// would break.
|
||||
if (count($this->dataNames) == 1
|
||||
&& $this->dataType == 'numeric'
|
||||
) {
|
||||
$name = reset($this->dataNames);
|
||||
$table->addRow(new Row(array(Row::COLUMNS => array($name => 0))));
|
||||
}
|
||||
}
|
||||
|
||||
$result = $table;
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
73
www/analytics/core/Archive/Parameters.php
Normal file
73
www/analytics/core/Archive/Parameters.php
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
<?php
|
||||
/**
|
||||
* Piwik - Open source web analytics
|
||||
*
|
||||
* @link http://piwik.org
|
||||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
||||
*
|
||||
*/
|
||||
|
||||
namespace Piwik\Archive;
|
||||
|
||||
use Exception;
|
||||
use Piwik\Period;
|
||||
use Piwik\Segment;
|
||||
|
||||
class Parameters
|
||||
{
|
||||
/**
|
||||
* The list of site IDs to query archive data for.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $idSites = array();
|
||||
|
||||
/**
|
||||
* The list of Period's to query archive data for.
|
||||
*
|
||||
* @var Period[]
|
||||
*/
|
||||
private $periods = array();
|
||||
|
||||
/**
|
||||
* Segment applied to the visits set.
|
||||
*
|
||||
* @var Segment
|
||||
*/
|
||||
private $segment;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $skipAggregationOfSubTables;
|
||||
|
||||
public function getSegment()
|
||||
{
|
||||
return $this->segment;
|
||||
}
|
||||
|
||||
public function __construct($idSites, $periods, Segment $segment, $skipAggregationOfSubTables)
|
||||
{
|
||||
$this->idSites = $idSites;
|
||||
$this->periods = $periods;
|
||||
$this->segment = $segment;
|
||||
$this->skipAggregationOfSubTables = $skipAggregationOfSubTables;
|
||||
}
|
||||
|
||||
public function getPeriods()
|
||||
{
|
||||
return $this->periods;
|
||||
}
|
||||
|
||||
public function getIdSites()
|
||||
{
|
||||
return $this->idSites;
|
||||
}
|
||||
|
||||
public function isSkipAggregationOfSubTables()
|
||||
{
|
||||
return $this->skipAggregationOfSubTables;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue