/** * Computes the output for the given data table * * @param DataTable $table * @return string * @throws Exception */ protected function renderTable($table) { if (!$table instanceof DataTable\Map || $table->getKeyName() != 'date') { throw new Exception("RSS feeds can be generated for one specific website &idSite=X." . "\nPlease specify only one idSite or consider using &format=XML instead."); } $idSite = Common::getRequestVar('idSite', 1, 'int'); $period = Common::getRequestVar('period'); $piwikUrl = SettingsPiwik::getPiwikUrl() . "?module=CoreHome&action=index&idSite=" . $idSite . "&period=" . $period; $out = ""; $moreRecentFirst = array_reverse($table->getDataTables(), true); foreach ($moreRecentFirst as $date => $subtable) { /** @var DataTable $subtable */ $timestamp = $subtable->getMetadata(Archive\DataTableFactory::TABLE_METADATA_PERIOD_INDEX)->getDateStart()->getTimestamp(); $site = $subtable->getMetadata(Archive\DataTableFactory::TABLE_METADATA_SITE_INDEX); $pudDate = date('r', $timestamp); $dateInSiteTimezone = Date::factory($timestamp); if ($site) { $dateInSiteTimezone = $dateInSiteTimezone->setTimezone($site->getTimezone()); } $dateInSiteTimezone = $dateInSiteTimezone->toString('Y-m-d'); $thisPiwikUrl = Common::sanitizeInputValue($piwikUrl . "&date={$dateInSiteTimezone}"); $siteName = $site ? $site->getName() : ''; $title = $siteName . " on " . $date; $out .= "\t<item>\n\t\t<pubDate>{$pudDate}</pubDate>\n\t\t<guid>{$thisPiwikUrl}</guid>\n\t\t<link>{$thisPiwikUrl}</link>\n\t\t<title>{$title}</title>\n\t\t<author>http://piwik.org</author>\n\t\t<description>"; $out .= Common::sanitizeInputValue($this->renderDataTable($subtable)); $out .= "</description>\n\t</item>\n"; } $header = $this->getRssHeader(); $footer = $this->getRssFooter(); return $header . $out . $footer; }
/** * Merge the columns of two data tables. * Manipulates the first table. * * @param DataTable|DataTable\Map $table1 The table to eventually filter. * @param DataTable|DataTable\Map $table2 Whether to delete rows with no visits or not. */ public function mergeDataTables($table1, $table2) { // handle table arrays if ($table1 instanceof DataTable\Map && $table2 instanceof DataTable\Map) { $subTables2 = $table2->getDataTables(); foreach ($table1->getDataTables() as $index => $subTable1) { if (!array_key_exists($index, $subTables2)) { // occurs when archiving starts on dayN and continues into dayN+1, see https://github.com/piwik/piwik/issues/5168#issuecomment-50959925 continue; } $subTable2 = $subTables2[$index]; $this->mergeDataTables($subTable1, $subTable2); } return; } $firstRow2 = $table2->getFirstRow(); if (!$firstRow2 instanceof Row) { return; } $firstRow1 = $table1->getFirstRow(); if (empty($firstRow1)) { $firstRow1 = $table1->addRow(new Row()); } foreach ($firstRow2->getColumns() as $metric => $value) { $firstRow1->setColumn($metric, $value); } }
/** * Apply generic filters to the DataTable object resulting from the API Call. * Disable this feature by setting the parameter disable_generic_filters to 1 in the API call request. * * @param DataTable $datatable * @return bool */ protected function applyGenericFilters($datatable) { if ($datatable instanceof DataTable\Map) { $tables = $datatable->getDataTables(); foreach ($tables as $table) { $this->applyGenericFilters($table); } return; } $genericFilters = self::getGenericFiltersInformation(); $filterApplied = false; foreach ($genericFilters as $filterMeta) { $filterName = $filterMeta[0]; $filterParams = $filterMeta[1]; $filterParameters = array(); $exceptionRaised = false; foreach ($filterParams as $name => $info) { // parameter type to cast to $type = $info[0]; // default value if specified, when the parameter doesn't have a value $defaultValue = null; if (isset($info[1])) { $defaultValue = $info[1]; } // third element in the array, if it exists, overrides the name of the request variable $varName = $name; if (isset($info[2])) { $varName = $info[2]; } try { $value = Common::getRequestVar($name, $defaultValue, $type, $this->request); settype($value, $type); $filterParameters[] = $value; } catch (Exception $e) { $exceptionRaised = true; break; } } if (!$exceptionRaised) { $datatable->filter($filterName, $filterParameters); $filterApplied = true; } } return $filterApplied; }
/** * Utility function that adds a visit percent column to a data table, * regardless of whether the data table is an data table array or just * a data table. * * @param DataTable $dataTable The data table to modify. */ private static function addVisitsPercentColumn($dataTable) { if ($dataTable instanceof DataTable\Map) { foreach ($dataTable->getDataTables() as $table) { self::addVisitsPercentColumn($table); } } else { $totalVisits = array_sum($dataTable->getColumn(Metrics::INDEX_NB_VISITS)); $dataTable->queueFilter('ColumnCallbackAddColumnPercentage', array('nb_visits_percentage', 'nb_visits', $totalVisits)); } }
/** * Utility function that removes the subtable IDs for the subtables of the * getReferrerType report. This avoids infinite recursion in said report (ie, * the grandchildren of the report will be the original report, and it will * recurse when trying to get a flat report). * * @param DataTable $table * @return DataTable Returns $table for convenience. */ private function removeSubtableIds($table) { if ($table instanceof DataTable\Map) { foreach ($table->getDataTables() as $childTable) { $this->removeSubtableIds($childTable); } } else { foreach ($table->getRows() as $row) { $row->removeSubtable(); } } return $table; }
/** * Sets the total visits, actions & revenue for a DataTable returned by * $this->buildDataTable. * * @param DataTable $dataTable * @param array $apiMetrics Metrics info. * @return array Array of three values: total visits, total actions, total revenue */ private function setMetricsTotalsMetadata($dataTable, $apiMetrics) { if ($dataTable instanceof DataTable\Map) { foreach ($dataTable->getDataTables() as $table) { $this->setMetricsTotalsMetadata($table, $apiMetrics); } } else { $totals = array(); foreach ($apiMetrics as $label => $recordName) { $totals[$label] = 0; } foreach ($dataTable->getRows() as $row) { foreach ($apiMetrics as $totalMetadataName => $recordName) { $totals[$totalMetadataName] += $row->getColumn($recordName); } } $dataTable->setMetadataValues($totals); } }
/** * Sets the total evolution metadata for a datatable returned by $this->buildDataTable * given data for the last period. * * @param DataTable|DataTable\Map $dataTable * @param DataTable|DataTable\Map $pastData * @param array $apiMetrics Metrics info. */ private function setPastDataMetadata($dataTable, $pastData, $apiMetrics) { if ($dataTable instanceof DataTable\Map) { $pastArray = $pastData->getDataTables(); foreach ($dataTable->getDataTables() as $subTable) { $this->setPastDataMetadata($subTable, current($pastArray), $apiMetrics); next($pastArray); } } else { // calculate total visits/actions/revenue for past data $this->setMetricsTotalsMetadata($pastData, $apiMetrics); foreach ($apiMetrics as $label => $metricInfo) { // get the names of metadata to set $totalMetadataName = self::getTotalMetadataName($label); $lastPeriodTotalMetadataName = self::getLastPeriodMetadataName($totalMetadataName); $totalEvolutionMetadataName = self::getTotalMetadataName($metricInfo[self::METRIC_EVOLUTION_COL_NAME_KEY]); // set last period total $pastTotal = $pastData->getMetadata($totalMetadataName); $dataTable->setMetadata($lastPeriodTotalMetadataName, $pastTotal); // calculate & set evolution $currentTotal = $dataTable->getMetadata($totalMetadataName); $evolution = CalculateEvolutionFilter::calculate($currentTotal, $pastTotal); $dataTable->setMetadata($totalEvolutionMetadataName, $evolution); } } }
/** * Apply generic filters to the DataTable object resulting from the API Call. * Disable this feature by setting the parameter disable_generic_filters to 1 in the API call request. * * @param DataTable $datatable * @return bool */ protected function applyGenericFilters($datatable) { if ($datatable instanceof DataTable\Map) { $tables = $datatable->getDataTables(); foreach ($tables as $table) { $this->applyGenericFilters($table); } return; } $genericFilters = $this->getGenericFiltersHavingDefaultValues(); $filterApplied = false; foreach ($genericFilters as $filterMeta) { $filterName = $filterMeta[0]; $filterParams = $filterMeta[1]; $filterParameters = array(); $exceptionRaised = false; if (in_array($filterName, $this->disabledFilters)) { continue; } foreach ($filterParams as $name => $info) { if (!is_array($info)) { // hard coded value that cannot be changed via API, see eg $naturalSort = true in 'Sort' $filterParameters[] = $info; } else { // parameter type to cast to $type = $info[0]; // default value if specified, when the parameter doesn't have a value $defaultValue = null; if (isset($info[1])) { $defaultValue = $info[1]; } try { $value = Common::getRequestVar($name, $defaultValue, $type, $this->request); settype($value, $type); $filterParameters[] = $value; } catch (Exception $e) { $exceptionRaised = true; break; } } } if (!$exceptionRaised) { $datatable->filter($filterName, $filterParameters); $filterApplied = true; } } return $filterApplied; }
/** * Sets the total visits, actions & revenue for a DataTable returned by * $this->buildDataTable. * * @param DataTable $dataTable * @param array $apiMetrics Metrics info. * @return array Array of three values: total visits, total actions, total revenue */ private function setMetricsTotalsMetadata($dataTable, $apiMetrics) { if ($dataTable instanceof DataTable\Map) { foreach ($dataTable->getDataTables() as $table) { $this->setMetricsTotalsMetadata($table, $apiMetrics); } } else { $revenueMetric = ''; if (Common::isGoalPluginEnabled()) { $revenueMetric = Archiver::getRecordName(self::GOAL_REVENUE_METRIC); } $totals = array(); foreach ($apiMetrics as $label => $metricInfo) { $totalMetadataName = self::getTotalMetadataName($label); $totals[$totalMetadataName] = 0; } foreach ($dataTable->getRows() as $row) { foreach ($apiMetrics as $label => $metricInfo) { $totalMetadataName = self::getTotalMetadataName($label); $totals[$totalMetadataName] += $row->getColumn($metricInfo[self::METRIC_RECORD_NAME_KEY]); } } foreach ($totals as $name => $value) { $dataTable->setMetadata($name, $value); } } }
/** * Sets the total visits, actions & revenue for a DataTable returned by * $this->buildDataTable. * * @param DataTable $dataTable * @param array $apiMetrics Metrics info. * @return array Array of three values: total visits, total actions, total revenue */ private function setMetricsTotalsMetadata($dataTable, $apiMetrics) { if ($dataTable instanceof DataTable\Map) { foreach ($dataTable->getDataTables() as $table) { $this->setMetricsTotalsMetadata($table, $apiMetrics); } } else { $totals = array(); foreach ($apiMetrics as $label => $metricInfo) { $totalMetadataName = self::getTotalMetadataName($label); $totals[$totalMetadataName] = 0; } foreach ($dataTable->getRows() as $row) { foreach ($apiMetrics as $label => $metricInfo) { $totalMetadataName = self::getTotalMetadataName($label); $totals[$totalMetadataName] += $row->getColumn($metricInfo[self::METRIC_RECORD_NAME_KEY]); } } foreach ($totals as $name => $value) { $dataTable->setMetadata($name, $value); } } }