/** * @param Row $row * @param DataTable $dataTable * @param string $labelPrefix * @param bool $parentLogo */ private function flattenRow(Row $row, 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); } $label = $labelPrefix . $label; $row->setColumn('label', $label); } $logo = $row->getMetadata('logo'); if ($logo === false && $parentLogo !== false) { $logo = $parentLogo; $row->setMetadata('logo', $logo); } $subTable = $this->loadSubtable($dataTable, $row); $row->removeSubtable(); if ($subTable === null) { if ($this->includeAggregateRows) { $row->setMetadata('is_aggregate', 0); } $dataTable->addRow($row); } else { if ($this->includeAggregateRows) { $row->setMetadata('is_aggregate', 1); $dataTable->addRow($row); } $prefix = $label . $this->recursiveLabelSeparator; foreach ($subTable->getRows() as $row) { $this->flattenRow($row, $dataTable, $prefix, $logo); } } }
private function getColumnValue(Row $row) { $value = $row->getColumn($this->config->primaryColumnToSort); if ($value === false || is_array($value)) { return null; } return $value; }
/** * 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 Archive:: * @param bool|array $mappingIdToName * @return mixed Value of column, false if not found */ public function getColumn($row, $columnIdRaw, $mappingIdToName = false) { if (empty($mappingIdToName)) { $mappingIdToName = Metrics::$mappingFromIdToName; } $columnIdReadable = $mappingIdToName[$columnIdRaw]; if ($row instanceof Row) { $raw = $row->getColumn($columnIdRaw); if ($raw !== false) { return $raw; } return $row->getColumn($columnIdReadable); } if (isset($row[$columnIdRaw])) { return $row[$columnIdRaw]; } if (isset($row[$columnIdReadable])) { return $row[$columnIdReadable]; } return false; }
public function sort(Row $a, Row $b) { foreach ($this->columnsToCheck as $column) { if ($column) { $valA = $a->getColumn($column); $valB = $b->getColumn($column); $sort = $this->sortVal($valA, $valB); if (isset($sort)) { return $sort; } } } return 0; }
/** * @param Row $row * @param DataTable $dataTable * @param string $labelPrefix * @param bool $parentLogo */ private function flattenRow(Row $row, $rowId, DataTable $dataTable, $labelPrefix = '', $parentLogo = false) { $label = $row->getColumn('label'); if ($label !== false) { $label = trim($label); 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); } $logo = $row->getMetadata('logo'); if ($logo === false && $parentLogo !== false) { $logo = $parentLogo; $row->setMetadata('logo', $logo); } /** @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) { if ($this->includeAggregateRows) { $row->setMetadata('is_aggregate', 0); } $dataTable->addRow($row); } else { if ($this->includeAggregateRows) { $row->setMetadata('is_aggregate', 1); $dataTable->addRow($row); } $prefix = $label . $this->recursiveLabelSeparator; foreach ($subTable->getRows() as $rowId => $row) { $this->flattenRow($row, $rowId, $dataTable, $prefix, $logo); } } }
private function getRowFromTable(DataTable $table, DataTable\Row $row) { return $table->getRowFromLabel($row->getColumn('label')); }
protected function enrichWithUniqueVisitorsMetric(Row $row) { // skip unique visitors metrics calculation if calculating for multiple sites is disabled if (!$this->getParams()->isSingleSite() && $this->skipUniqueVisitorsCalculationForMultipleSites) { return; } if ($row->getColumn('nb_uniq_visitors') === false && $row->getColumn('nb_users') === false) { return; } if (!SettingsPiwik::isUniqueVisitorsEnabled($this->getParams()->getPeriod()->getLabel())) { $row->deleteColumn('nb_uniq_visitors'); $row->deleteColumn('nb_users'); return; } $metrics = array(Metrics::INDEX_NB_USERS); if ($this->getParams()->isSingleSite()) { $uniqueVisitorsMetric = Metrics::INDEX_NB_UNIQ_VISITORS; } else { if (!SettingsPiwik::isSameFingerprintAcrossWebsites()) { throw new Exception("Processing unique visitors across websites is enabled for this instance,\n but to process this metric you must first set enable_fingerprinting_across_websites=1\n in the config file, under the [Tracker] section."); } $uniqueVisitorsMetric = Metrics::INDEX_NB_UNIQ_FINGERPRINTS; } $metrics[] = $uniqueVisitorsMetric; $uniques = $this->computeNbUniques($metrics); // see edge case as described in https://github.com/piwik/piwik/issues/9357 where uniq_visitors might be higher // than visits because we archive / process it after nb_visits. Between archiving nb_visits and nb_uniq_visitors // there could have been a new visit leading to a higher nb_unique_visitors than nb_visits which is not possible // by definition. In this case we simply use the visits metric instead of unique visitors metric. $visits = $row->getColumn('nb_visits'); if ($visits !== false && $uniques[$uniqueVisitorsMetric] !== false) { $uniques[$uniqueVisitorsMetric] = min($uniques[$uniqueVisitorsMetric], $visits); } $row->setColumn('nb_uniq_visitors', $uniques[$uniqueVisitorsMetric]); $row->setColumn('nb_users', $uniques[Metrics::INDEX_NB_USERS]); }
/** * Returns the element that should be replaced * * @param Row $row * @param string $columnToFilter * @return mixed */ protected function getElementToReplace($row, $columnToFilter) { return $row->getColumn($columnToFilter); }
/** * Returns a summary for a visit's referral. * * @param Row $visit * @return bool|mixed|string * @ignore */ public static function getReferrerSummaryForVisit($visit) { $referrerType = $visit->getColumn('referrerType'); if ($referrerType === false || $referrerType == 'direct') { $result = Piwik::translate('Referrers_DirectEntry'); } else { if ($referrerType == 'search') { $result = $visit->getColumn('referrerName'); $keyword = $visit->getColumn('referrerKeyword'); if ($keyword !== false && $keyword != APIReferrers::getKeywordNotDefinedString()) { $result .= ' (' . $keyword . ')'; } } else { if ($referrerType == 'campaign') { $result = Piwik::translate('Referrers_ColumnCampaign') . ' (' . $visit->getColumn('referrerName') . ')'; } else { $result = $visit->getColumn('referrerName'); } } } return $result; }
protected function enrichWithUniqueVisitorsMetric(Row $row) { // skip unique visitors metrics calculation if calculating for multiple sites is disabled if (!$this->getParams()->isSingleSite() && $this->skipUniqueVisitorsCalculationForMultipleSites) { return; } if ($row->getColumn('nb_uniq_visitors') === false && $row->getColumn('nb_users') === false) { return; } if (!SettingsPiwik::isUniqueVisitorsEnabled($this->getParams()->getPeriod()->getLabel())) { $row->deleteColumn('nb_uniq_visitors'); $row->deleteColumn('nb_users'); return; } $metrics = array(Metrics::INDEX_NB_USERS); if ($this->getParams()->isSingleSite()) { $uniqueVisitorsMetric = Metrics::INDEX_NB_UNIQ_VISITORS; } else { if (!SettingsPiwik::isSameFingerprintAcrossWebsites()) { throw new Exception("Processing unique visitors across websites is enabled for this instance,\n but to process this metric you must first set enable_fingerprinting_across_websites=1\n in the config file, under the [Tracker] section."); } $uniqueVisitorsMetric = Metrics::INDEX_NB_UNIQ_FINGERPRINTS; } $metrics[] = $uniqueVisitorsMetric; $uniques = $this->computeNbUniques($metrics); $row->setColumn('nb_uniq_visitors', $uniques[$uniqueVisitorsMetric]); $row->setColumn('nb_users', $uniques[Metrics::INDEX_NB_USERS]); }
protected function getColumnValue(Row $row) { $value = $row->getColumn($this->columnToSort); if ($value === false || is_array($value)) { return null; } return $value; }
/** * 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 * @params null|array $columnAggregationOps * @throws \Exception */ protected function aggregateRowWithLabel(Row $row, $columnAggregationOps) { $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, $columnAggregationOps); // 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 $subTable = $row->getSubtable(); if ($subTable) { $subTable->metadata[self::COLUMN_AGGREGATION_OPS_METADATA_NAME] = $columnAggregationOps; $rowFound->sumSubtable($subTable); } } }
/** * Sums the metadata in `$rowToSum` with the metadata in `$this` row. * * @param Row $rowToSum */ public function sumRowMetadata($rowToSum) { if (!empty($rowToSum->c[self::METADATA]) && !$this->isSummaryRow()) { // We shall update metadata, and keep the metadata with the _most visits or pageviews_, rather than first or last seen $visits = max($rowToSum->getColumn(Metrics::INDEX_PAGE_NB_HITS) || $rowToSum->getColumn(Metrics::INDEX_NB_VISITS), $rowToSum->getColumn('nb_actions') || $rowToSum->getColumn('nb_visits')); if ($visits && $visits > $this->maxVisitsSummed || empty($this->c[self::METADATA])) { $this->maxVisitsSummed = $visits; $this->c[self::METADATA] = $rowToSum->c[self::METADATA]; } } }
/** * public for Insights use. */ public function getPastRowFromCurrent(Row $row) { return $this->pastData->getRowFromLabel($row->getColumn('label')); }
private function mergeChildren_checkRow(Row $row, $expectedLabel, $expectedColumnValue) { $this->assertEquals($expectedLabel, $row->getColumn('label')); $this->assertEquals($expectedColumnValue, $row->getColumn('col1')); }
private function assertColumnSavesValue($expectedValue, $columnName, $valueToSet) { $this->row->setColumn($columnName, $valueToSet); $this->assertSame($expectedValue, $this->row->getColumn($columnName)); }
/** * Sums the metadata in `$rowToSum` with the metadata in `$this` row. * * @param Row $rowToSum * @param array $aggregationOperations */ public function sumRowMetadata($rowToSum, $aggregationOperations = array()) { if (!empty($rowToSum->metadata) && !$this->isSummaryRow()) { $aggregatedMetadata = array(); if (is_array($aggregationOperations)) { // we need to aggregate value before value is overwritten by maybe another row foreach ($aggregationOperations as $columnn => $operation) { $thisMetadata = $this->getMetadata($columnn); $sumMetadata = $rowToSum->getMetadata($columnn); if ($thisMetadata === false && $sumMetadata === false) { continue; } $aggregatedMetadata[$columnn] = $this->getColumnValuesMerged($operation, $thisMetadata, $sumMetadata); } } // We shall update metadata, and keep the metadata with the _most visits or pageviews_, rather than first or last seen $visits = max($rowToSum->getColumn(Metrics::INDEX_PAGE_NB_HITS) || $rowToSum->getColumn(Metrics::INDEX_NB_VISITS), $rowToSum->getColumn('nb_actions') || $rowToSum->getColumn('nb_visits')); if ($visits && $visits > $this->maxVisitsSummed || empty($this->metadata)) { $this->maxVisitsSummed = $visits; $this->metadata = $rowToSum->metadata; } foreach ($aggregatedMetadata as $column => $value) { // we need to make sure aggregated value is used, and not metadata from $rowToSum $this->setMetadata($column, $value); } } }
protected function enrichWithUniqueVisitorsMetric(Row $row) { // skip unique visitors metrics calculation if calculating for multiple sites is disabled if (!$this->getParams()->isSingleSite() && $this->skipUniqueVisitorsCalculationForMultipleSites) { return; } if ($row->getColumn('nb_uniq_visitors') !== false || $row->getColumn('nb_users') !== false) { if (SettingsPiwik::isUniqueVisitorsEnabled($this->getParams()->getPeriod()->getLabel())) { $metrics = array(Metrics::INDEX_NB_UNIQ_VISITORS, Metrics::INDEX_NB_USERS); $uniques = $this->computeNbUniques($metrics); $row->setColumn('nb_uniq_visitors', $uniques[Metrics::INDEX_NB_UNIQ_VISITORS]); $row->setColumn('nb_users', $uniques[Metrics::INDEX_NB_USERS]); } else { $row->deleteColumn('nb_uniq_visitors'); $row->deleteColumn('nb_users'); } } }
/** * Helper method that will access a metric in a {@link Piwik\DataTable\Row} or array either by * its name or by its special numerical index value. * * @param Row|array $row * @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 mixed The metric value or false if none exists. */ public static function getMetric($row, $columnName, $mappingNameToId = null) { if ($row instanceof Row) { $value = $row->getColumn($columnName); if ($value === false) { if (empty($mappingNameToId)) { $mappingNameToId = Metrics::getMappingFromNameToId(); } if (isset($mappingNameToId[$columnName])) { return $row->getColumn($mappingNameToId[$columnName]); } } return $value; } elseif (!empty($row)) { if (array_key_exists($columnName, $row)) { return $row[$columnName]; } else { if (empty($mappingNameToId)) { $mappingNameToId = Metrics::getMappingFromNameToId(); } if (isset($mappingNameToId[$columnName])) { $columnName = $mappingNameToId[$columnName]; if (array_key_exists($columnName, $row)) { return $row[$columnName]; } } } } return null; }
/** * @expectedException \Exception * @expectedExceptionMessage Unknown operation 'foobarinvalid' */ public function testSumRow_ShouldThrowExceptionIfInvalidOperationIsGiven() { $row1 = new Row(array(Row::COLUMNS => array('test_int' => 145))); $finalRow = new Row(array(Row::COLUMNS => array('test_int' => 5))); $finalRow->sumRow($row1, $copyMetadata = true, $operation = array('test_int' => 'fooBarInvalid')); $this->assertEquals(array(5, 145), $finalRow->getColumn('test_int')); }
/** * Returns the divisor to use when calculating the new column value. Can * be overridden by descendent classes to customize behavior. * * @param Row $row The row being modified. * @return int|float */ protected function getDivisor($row) { if (!is_null($this->totalValueUsedAsDivisor)) { return $this->totalValueUsedAsDivisor; } else { if ($this->getDivisorFromSummaryRow) { $summaryRow = $this->table->getRowFromId(DataTable::ID_SUMMARY_ROW); return $summaryRow->getColumn($this->columnNameUsedAsDivisor); } else { return $row->getColumn($this->columnNameUsedAsDivisor); } } }
/** * 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; }
protected function enrichWithUniqueVisitorsMetric(Row $row) { if (!$this->getParams()->isSingleSite()) { // we only compute unique visitors for a single site return; } if ($row->getColumn('nb_uniq_visitors') !== false) { if (SettingsPiwik::isUniqueVisitorsEnabled($this->getParams()->getPeriod()->getLabel())) { $uniqueVisitors = (double) $this->computeNbUniqVisitors(); $row->setColumn('nb_uniq_visitors', $uniqueVisitors); } else { $row->deleteColumn('nb_uniq_visitors'); } } }
/** * 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; }
/** * Utility function. Returns the current row in the past DataTable. * * @param Row $row The row in the 'current' DataTable. * @return bool|Row */ protected function getPastRowFromCurrent($row) { return $this->pastDataTable->getRowFromLabel($row->getColumn('label')); }
private function handleGeoLocation(DataTable\Row $visit) { // realtime map only checks for latitude $hasLatitude = $visit->getColumn('latitude') !== false; if ($hasLatitude) { $this->profile['hasLatLong'] = true; } $countryCode = $visit->getColumn('countryCode'); if (!isset($this->countries[$countryCode])) { $this->countries[$countryCode] = 0; } ++$this->countries[$countryCode]; $continentCode = $visit->getColumn('continentCode'); if (!isset($this->continents[$continentCode])) { $this->continents[$continentCode] = 0; } ++$this->continents[$continentCode]; if ($countryCode && !array_key_exists($countryCode, $this->cities)) { $this->cities[$countryCode] = array(); } $city = $visit->getColumn('city'); if (!empty($city)) { $this->cities[$countryCode][] = $city; } }
/** * @param $columnRow * @param $pivotColumn * @return false|mixed */ private function getColumnValue(Row $columnRow, $pivotColumn) { $value = $columnRow->getColumn($pivotColumn); if (empty($value) && !empty($this->metricIndexValue)) { $value = $columnRow->getColumn($this->metricIndexValue); } return $value; }
/** * @param Row $lastGroupFromPreviousPage */ private function prependGroupIfFirstSiteBelongsToAGroupButGroupIsMissingInRows($lastGroupFromPreviousPage) { if ($lastGroupFromPreviousPage && !empty($this->rows)) { // the result starts with a row that does belong to a group, we make sure to show this group before that site $group = reset($this->rows)->getMetadata('group'); if ($group && $lastGroupFromPreviousPage->getColumn('label') === $group) { array_unshift($this->rows, $lastGroupFromPreviousPage); // we do not remove the last item as it could result in errors, instead we show $limit+1 entries } } }