/** * See {@link Limit}. * * @param DataTable $table */ public function filter($table) { $table->setMetadata(DataTable::TOTAL_ROWS_BEFORE_LIMIT_METADATA_NAME, $table->getRowsCount()); if ($this->keepSummaryRow) { $summaryRow = $table->getRowFromId(DataTable::ID_SUMMARY_ROW); } // we delete from 0 to offset if ($this->offset > 0) { $table->deleteRowsOffset(0, $this->offset); } // at this point the array has offset less elements. We delete from limit to the end if ($this->limit >= 0) { $table->deleteRowsOffset($this->limit); } if ($this->keepSummaryRow && !empty($summaryRow)) { $table->addSummaryRow($summaryRow); } }
/** * Initializes the DataTables created by the archiveDay function. */ private function initActionsTables() { $this->actionsTablesByType = array(); foreach (self::$actionTypes as $type) { $dataTable = new DataTable(); $dataTable->setMaximumAllowedRows(ArchivingHelper::$maximumRowsInDataTableLevelZero); if ($type == Action::TYPE_PAGE_URL || $type == Action::TYPE_PAGE_TITLE) { // for page urls and page titles, performance metrics exist and have to be aggregated correctly $dataTable->setMetadata(DataTable::COLUMN_AGGREGATION_OPS_METADATA_NAME, self::$columnsAggregationOperation); } $this->actionsTablesByType[$type] = $dataTable; } }
/** * @param $data * @return DataTable * @throws Exception */ private function makeVisitorTableFromArray($data) { $dataTable = new DataTable(); $dataTable->addRowsFromSimpleArray($data); if (!empty($data[0])) { $columnsToNotAggregate = array_map(function () { return 'skip'; }, $data[0]); $dataTable->setMetadata(DataTable::COLUMN_AGGREGATION_OPS_METADATA_NAME, $columnsToNotAggregate); } return $dataTable; }
private function createGroupSubtable(DataTable $sites) { $table = new DataTable(); $processedMetrics = $sites->getMetadata(DataTable::EXTRA_PROCESSED_METRICS_METADATA_NAME); $table->setMetadata(DataTable::EXTRA_PROCESSED_METRICS_METADATA_NAME, $processedMetrics); return $table; }
/** * 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) { $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, $this->isAggregateSubTables()); } return $table; }
/** * Returns datatable describing the number of visits for each day of the week. * * @param string $idSite The site ID. Cannot refer to multiple sites. * @param string $period The period type: day, week, year, range... * @param string $date The start date of the period. Cannot refer to multiple dates. * @param bool|string $segment The segment. * @throws Exception * @return DataTable */ public function getByDayOfWeek($idSite, $period, $date, $segment = false) { Piwik::checkUserHasViewAccess($idSite); // metrics to query $metrics = Metrics::getVisitsMetricNames(); unset($metrics[Metrics::INDEX_MAX_ACTIONS]); // disabled for multiple dates if (Period::isMultiplePeriod($date, $period)) { throw new Exception("VisitTime.getByDayOfWeek does not support multiple dates."); } // get metric data for every day within the supplied period $oPeriod = Period\Factory::makePeriodFromQueryParams(Site::getTimezoneFor($idSite), $period, $date); $dateRange = $oPeriod->getDateStart()->toString() . ',' . $oPeriod->getDateEnd()->toString(); $archive = Archive::build($idSite, 'day', $dateRange, $segment); // disabled for multiple sites if (count($archive->getParams()->getIdSites()) > 1) { throw new Exception("VisitTime.getByDayOfWeek does not support multiple sites."); } $dataTable = $archive->getDataTableFromNumeric($metrics)->mergeChildren(); // if there's no data for this report, don't bother w/ anything else if ($dataTable->getRowsCount() == 0) { return $dataTable; } // group by the day of the week (see below for dayOfWeekFromDate function) $dataTable->filter('GroupBy', array('label', __NAMESPACE__ . '\\dayOfWeekFromDate')); // create new datatable w/ empty rows, then add calculated datatable $rows = array(); foreach (array(1, 2, 3, 4, 5, 6, 7) as $day) { $rows[] = array('label' => $day, 'nb_visits' => 0); } $result = new DataTable(); $result->addRowsFromSimpleArray($rows); $result->addDataTable($dataTable); // set day of week integer as metadata $result->filter('ColumnCallbackAddMetadata', array('label', 'day_of_week')); // translate labels $result->filter('ColumnCallbackReplace', array('label', __NAMESPACE__ . '\\translateDayOfWeek')); // set datatable metadata for period start & finish $result->setMetadata('date_start', $oPeriod->getDateStart()); $result->setMetadata('date_end', $oPeriod->getDateEnd()); return $result; }
/** * Common filters for Page URLs and Page Titles * * @param DataTable|DataTable\Simple|DataTable\Map $dataTable */ protected function filterPageDatatable($dataTable) { $columnsToRemove = array('bounce_rate'); $dataTable->queueFilter('ColumnDelete', array($columnsToRemove)); // Average time on page = total time on page / number visits on that page $dataTable->queueFilter('ColumnCallbackAddColumnQuotient', array('avg_time_on_page', 'sum_time_spent', 'nb_visits', 0)); // Bounce rate = single page visits on this page / visits started on this page $dataTable->queueFilter('ColumnCallbackAddColumnPercentage', array('bounce_rate', 'entry_bounce_count', 'entry_nb_visits', 0)); // % Exit = Number of visits that finished on this page / visits on this page $dataTable->queueFilter('ColumnCallbackAddColumnPercentage', array('exit_rate', 'exit_nb_visits', 'nb_visits', 0)); // Handle performance analytics $hasTimeGeneration = array_sum($dataTable->getColumn(Metrics::INDEX_PAGE_SUM_TIME_GENERATION)) > 0; if ($hasTimeGeneration) { // Average generation time = total generation time / number of pageviews $precisionAvgTimeGeneration = 3; $dataTable->queueFilter('ColumnCallbackAddColumnQuotient', array('avg_time_generation', 'sum_time_generation', 'nb_hits_with_time_generation', $precisionAvgTimeGeneration)); $dataTable->queueFilter('ColumnDelete', array(array('sum_time_generation'))); } else { // No generation time: remove it from the API output and add it to empty_columns metadata, so that // the columns can also be removed from the view $dataTable->filter('ColumnDelete', array(array(Metrics::INDEX_PAGE_SUM_TIME_GENERATION, Metrics::INDEX_PAGE_NB_HITS_WITH_TIME_GENERATION, Metrics::INDEX_PAGE_MIN_TIME_GENERATION, Metrics::INDEX_PAGE_MAX_TIME_GENERATION))); if ($dataTable instanceof DataTable) { $emptyColumns = $dataTable->getMetadata(DataTable::EMPTY_COLUMNS_METADATA_NAME); if (!is_array($emptyColumns)) { $emptyColumns = array(); } $emptyColumns[] = 'sum_time_generation'; $emptyColumns[] = 'avg_time_generation'; $emptyColumns[] = 'min_time_generation'; $emptyColumns[] = 'max_time_generation'; $dataTable->setMetadata(DataTable::EMPTY_COLUMNS_METADATA_NAME, $emptyColumns); } } }
/** * 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); } } }
/** * Sets the number of total visits in tha pastTable on the dataTable as metadata. * * @param DataTable $dataTable * @param DataTable $pastTable */ private function setPastTotalVisitsMetadata($dataTable, $pastTable) { if ($pastTable instanceof DataTable) { $total = 0; $metric = 'nb_visits'; foreach ($pastTable->getRows() as $row) { $total += $row->getColumn($metric); } $dataTable->setMetadata(self::getTotalMetadataName($metric . '_lastdate'), $total); } }
private function loadLastVisitorDetailsFromDatabase($idSite, $period, $date, $segment = false, $countVisitorsToFetch = 100, $visitorId = false, $minTimestamp = false, $filterSortOrder = false) { $where = $whereBind = array(); list($whereClause, $idSites) = $this->getIdSitesWhereClause($idSite); $where[] = $whereClause; $whereBind = $idSites; if (strtolower($filterSortOrder) !== 'asc') { $filterSortOrder = 'DESC'; } $orderBy = "idsite, visit_last_action_time " . $filterSortOrder; $orderByParent = "sub.visit_last_action_time " . $filterSortOrder; if (!empty($visitorId)) { $where[] = "log_visit.idvisitor = ? "; $whereBind[] = @Common::hex2bin($visitorId); } if (!empty($minTimestamp)) { $where[] = "log_visit.visit_last_action_time > ? "; $whereBind[] = date("Y-m-d H:i:s", $minTimestamp); } // If no other filter, only look at the last 24 hours of stats if (empty($visitorId) && empty($countVisitorsToFetch) && empty($period) && empty($date)) { $period = 'day'; $date = 'yesterdaySameTime'; } // SQL Filter with provided period if (!empty($period) && !empty($date)) { $currentSite = new Site($idSite); $currentTimezone = $currentSite->getTimezone(); $dateString = $date; if ($period == 'range') { $processedPeriod = new Range('range', $date); if ($parsedDate = Range::parseDateRange($date)) { $dateString = $parsedDate[2]; } } else { $processedDate = Date::factory($date); if ($date == 'today' || $date == 'now' || $processedDate->toString() == Date::factory('now', $currentTimezone)->toString()) { $processedDate = $processedDate->subDay(1); } $processedPeriod = Period\Factory::build($period, $processedDate); } $dateStart = $processedPeriod->getDateStart()->setTimezone($currentTimezone); $where[] = "log_visit.visit_last_action_time >= ?"; $whereBind[] = $dateStart->toString('Y-m-d H:i:s'); if (!in_array($date, array('now', 'today', 'yesterdaySameTime')) && strpos($date, 'last') === false && strpos($date, 'previous') === false && Date::factory($dateString)->toString('Y-m-d') != Date::factory('now', $currentTimezone)->toString()) { $dateEnd = $processedPeriod->getDateEnd()->setTimezone($currentTimezone); $where[] = " log_visit.visit_last_action_time <= ?"; $dateEndString = $dateEnd->addDay(1)->toString('Y-m-d H:i:s'); $whereBind[] = $dateEndString; } } if (count($where) > 0) { $where = join("\n\t\t\t\tAND ", $where); } else { $where = false; } $segment = new Segment($segment, $idSite); // Subquery to use the indexes for ORDER BY $select = "log_visit.*"; $from = "log_visit"; $subQuery = $segment->getSelectQuery($select, $from, $where, $whereBind, $orderBy); $sqlLimit = $countVisitorsToFetch >= 1 ? " LIMIT 0, " . (int) $countVisitorsToFetch : ""; // Group by idvisit so that a visitor converting 2 goals only appears once $sql = "\n\t\t\tSELECT sub.* FROM (\n\t\t\t\t" . $subQuery['sql'] . "\n\t\t\t\t{$sqlLimit}\n\t\t\t) AS sub\n\t\t\tGROUP BY sub.idvisit\n\t\t\tORDER BY {$orderByParent}\n\t\t"; try { $data = Db::fetchAll($sql, $subQuery['bind']); } catch (Exception $e) { echo $e->getMessage(); exit; } $dataTable = new DataTable(); $dataTable->addRowsFromSimpleArray($data); // $dataTable->disableFilter('Truncate'); if (!empty($data[0])) { $columnsToNotAggregate = array_map(function () { return 'skip'; }, $data[0]); $dataTable->setMetadata(DataTable::COLUMN_AGGREGATION_OPS_METADATA_NAME, $columnsToNotAggregate); } return $dataTable; }
private function getTableWithTotal($total) { $table = new DataTable(); $table->setMetadata('totals', array('nb_visits' => $total)); return $table; }
private function setSitesTable($numSites) { $sites = new DataTable(); $sites->addRowsFromSimpleArray($this->buildSitesArray(range(1, $numSites))); $sites->setMetadata('last_period_date', Period\Factory::build('day', '2012-12-12')); $this->dashboard->setSitesTable($sites); return $sites; }
private function addMoversAndShakersMetadata(DataTable $dataTable, $totalValue, $lastTotalValue) { $totalEvolution = $this->getTotalEvolution($totalValue, $lastTotalValue); $dataTable->setMetadata('lastTotalValue', $lastTotalValue); $dataTable->setMetadata('evolutionTotal', $totalEvolution); $dataTable->setMetadata('evolutionDifference', $totalValue - $lastTotalValue); }
/** * 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); } } }
/** * See {@link ColumnCallbackAddColumn}. * * @param DataTable $table The table to filter. */ public function filter($table) { $columns = $this->columns; $functionParams = $this->functionParameters; $functionToApply = $this->functionToApply; $extraProcessedMetrics = $table->getMetadata(DataTable::EXTRA_PROCESSED_METRICS_METADATA_NAME); if (empty($extraProcessedMetrics)) { $extraProcessedMetrics = array(); } $metric = new CallableProcessedMetric($this->columnToAdd, function (DataTable\Row $row) use($columns, $functionParams, $functionToApply) { $columnValues = array(); foreach ($columns as $column) { $columnValues[] = $row->getColumn($column); } $parameters = array_merge($columnValues, $functionParams); return call_user_func_array($functionToApply, $parameters); }, $columns); $extraProcessedMetrics[] = $metric; $table->setMetadata(DataTable::EXTRA_PROCESSED_METRICS_METADATA_NAME, $extraProcessedMetrics); foreach ($table->getRows() as $row) { $row->setColumn($this->columnToAdd, $metric->compute($row)); $this->filterSubTable($row); } }