/** * Adds a summary row to the given data table * * @param Piwik_DataTable $table */ public function filter($table) { if ($table->getRowsCount() <= $this->startRowToSummarize + 1) { return; } $table->filter('Sort', array($this->columnToSortByBeforeTruncating, 'desc')); $rows = $table->getRows(); $count = $table->getRowsCount(); $newRow = new Piwik_DataTable_Row(); for ($i = $this->startRowToSummarize; $i < $count; $i++) { if (!isset($rows[$i])) { // case when the last row is a summary row, it is not indexed by $cout but by Piwik_DataTable::ID_SUMMARY_ROW $summaryRow = $table->getRowFromId(Piwik_DataTable::ID_SUMMARY_ROW); //FIXME: I'm not sure why it could return false, but it was reported in: http://forum.piwik.org/read.php?2,89324,page=1#msg-89442 if ($summaryRow) { $newRow->sumRow($summaryRow, $enableCopyMetadata = false); } } else { $newRow->sumRow($rows[$i], $enableCopyMetadata = false); } } $newRow->setColumns(array('label' => $this->labelSummaryRow) + $newRow->getColumns()); if ($this->deleteRows) { $table->filter('Limit', array(0, $this->startRowToSummarize)); } $table->addSummaryRow($newRow); unset($rows); }
/** * Truncates the table after X rows and adds a summary row * * @param Piwik_DataTable $table */ public function filter($table) { $table->filter('AddSummaryRow', array($this->truncateAfter)); $table->filter('ReplaceSummaryRowLabel'); foreach ($table->getRows() as $row) { if ($row->isSubtableLoaded()) { $idSubTable = $row->getIdSubDataTable(); $subTable = Piwik_DataTable_Manager::getInstance()->getTable($idSubTable); $subTable->filter('Truncate', array($this->truncateAfter)); } } }
/** * Hook called after the dataTable has been loaded from the API * Can be used to add, delete or modify the data freshly loaded */ protected function postDataTableLoadedFromAPI() { if (empty($this->dataTable)) { return false; } // First, filters that delete rows foreach ($this->queuedFiltersPriority as $filter) { $filterName = $filter[0]; $filterParameters = $filter[1]; $this->dataTable->filter($filterName, $filterParameters); } if (0 == Piwik_Common::getRequestVar('disable_generic_filters', '0', 'string')) { // Second, generic filters (Sort, Limit, Replace Column Names, etc.) $requestString = $this->getRequestString(); $request = Piwik_API_Request::getRequestArrayFromString($requestString); if (!empty($this->variablesDefault['enable_sort']) && $this->variablesDefault['enable_sort'] === 'false') { $request['filter_sort_column'] = $request['filter_sort_order'] = ''; } $genericFilter = new Piwik_API_DataTableGenericFilter($request); $genericFilter->filter($this->dataTable); } // Finally, apply datatable filters that were queued (should be 'presentation' filters that do not affect the number of rows) foreach ($this->queuedFilters as $filter) { $filterName = $filter[0]; $filterParameters = $filter[1]; $this->dataTable->filter($filterName, $filterParameters); } }
/** * Hook called after the dataTable has been loaded from the API * Can be used to add, delete or modify the data freshly loaded * * @return bool */ protected function postDataTableLoadedFromAPI() { if (empty($this->dataTable)) { return false; } // deal w/ table metadata if ($this->dataTable instanceof Piwik_DataTable) { $this->viewProperties['metadata'] = $this->dataTable->getAllTableMetadata(); if (isset($this->viewProperties['metadata'][Piwik_DataTable::ARCHIVED_DATE_METADATA_NAME])) { $this->viewProperties['metadata'][Piwik_DataTable::ARCHIVED_DATE_METADATA_NAME] = $this->makePrettyArchivedOnText(); } } // First, filters that delete rows foreach ($this->queuedFiltersPriority as $filter) { $filterName = $filter[0]; $filterParameters = $filter[1]; $this->dataTable->filter($filterName, $filterParameters); } if (!$this->areGenericFiltersDisabled()) { // Second, generic filters (Sort, Limit, Replace Column Names, etc.) $requestString = $this->getRequestString(); $request = Piwik_API_Request::getRequestArrayFromString($requestString); if (!empty($this->variablesDefault['enable_sort']) && $this->variablesDefault['enable_sort'] === 'false') { $request['filter_sort_column'] = $request['filter_sort_order'] = ''; } $genericFilter = new Piwik_API_DataTableGenericFilter($request); $genericFilter->filter($this->dataTable); } if (!$this->areQueuedFiltersDisabled()) { // Finally, apply datatable filters that were queued (should be 'presentation' filters that // do not affect the number of rows) foreach ($this->queuedFilters as $filter) { $filterName = $filter[0]; $filterParameters = $filter[1]; $this->dataTable->filter($filterName, $filterParameters); } } return true; }
/** * 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 Piwik_DataTable $datatable * @return bool */ protected function applyGenericFilters($datatable) { if ($datatable instanceof Piwik_DataTable_Array) { $tables = $datatable->getArray(); $filterWasApplied = false; foreach ($tables as $table) { $filterWasApplied = $this->applyGenericFilters($table); } return; } $genericFilters = self::getGenericFiltersInformation(); $filterApplied = false; foreach ($genericFilters as $filterName => $parameters) { $filterParameters = array(); $exceptionRaised = false; foreach ($parameters 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 = Piwik_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; }
/** * Enhance a $dataTable using metadata : * * - remove metrics based on $reportMetadata['metrics'] * - add 0 valued metrics if $dataTable doesn't provide all $reportMetadata['metrics'] * - format metric values to a 'human readable' format * - extract row metadata to a separate Piwik_DataTable_Simple|Piwik_DataTable_Array : $rowsMetadata * - translate metric names to a separate array : $columns * * @param int $idSite enables monetary value formatting based on site currency * @param Piwik_DataTable|Piwik_DataTable_Array $dataTable * @param array $reportMetadata * @param boolean $hasDimension * @return array Piwik_DataTable_Simple|Piwik_DataTable_Array $newReport with human readable format & array $columns list of translated column names & Piwik_DataTable_Simple|Piwik_DataTable_Array $rowsMetadata **/ private function handleTableReport($idSite, $dataTable, &$reportMetadata, $hasDimension) { $columns = $reportMetadata['metrics']; if ($hasDimension) { $columns = array_merge(array('label' => $reportMetadata['dimension']), $columns); if (isset($reportMetadata['processedMetrics'])) { $processedMetricsAdded = $this->getDefaultProcessedMetrics(); foreach ($processedMetricsAdded as $processedMetricId => $processedMetricTranslation) { // this processed metric can be displayed for this report if (isset($reportMetadata['processedMetrics'][$processedMetricId])) { $columns[$processedMetricId] = $processedMetricTranslation; } } } // Display the global Goal metrics if (isset($reportMetadata['metricsGoal'])) { $metricsGoalDisplay = array('revenue'); // Add processed metrics to be displayed for this report foreach ($metricsGoalDisplay as $goalMetricId) { if (isset($reportMetadata['metricsGoal'][$goalMetricId])) { $columns[$goalMetricId] = $reportMetadata['metricsGoal'][$goalMetricId]; } } } if (isset($reportMetadata['processedMetrics'])) { // Add processed metrics $dataTable->filter('AddColumnsProcessedMetrics', array($deleteRowsWithNoVisit = false)); } } // $dataTable is an instance of Piwik_DataTable_Array when multiple periods requested if ($dataTable instanceof Piwik_DataTable_Array) { // Need a new Piwik_DataTable_Array to store the 'human readable' values $newReport = new Piwik_DataTable_Array(); $newReport->setKeyName("prettyDate"); $dataTableMetadata = $dataTable->metadata; $newReport->metadata = $dataTableMetadata; // Need a new Piwik_DataTable_Array to store report metadata $rowsMetadata = new Piwik_DataTable_Array(); $rowsMetadata->setKeyName("prettyDate"); // Process each Piwik_DataTable_Simple entry foreach ($dataTable->getArray() as $label => $simpleDataTable) { list($enhancedSimpleDataTable, $rowMetadata) = $this->handleSimpleDataTable($idSite, $simpleDataTable, $columns, $hasDimension); $period = $dataTableMetadata[$label]['period']->getLocalizedLongString(); $newReport->addTable($enhancedSimpleDataTable, $period); $rowsMetadata->addTable($rowMetadata, $period); } } else { list($newReport, $rowsMetadata) = $this->handleSimpleDataTable($idSite, $dataTable, $columns, $hasDimension); } return array($newReport, $columns, $rowsMetadata); }
/** * Utility function used by getAll. Performs a binary filter of two * DataTables in order to correctly calculate evolution metrics. * * @param Piwik_DataTable|Piwik_DataTable_Array $currentData * @param Piwik_DataTable|Piwik_DataTable_Array $pastData * @param array $fields The array of string fields to calculate evolution * metrics for. */ private function calculateEvolutionPercentages($currentData, $pastData, $fields) { if ($currentData instanceof Piwik_DataTable_Array) { $pastArray = $pastData->getArray(); foreach ($currentData->getArray() as $label => $subTable) { $this->calculateEvolutionPercentages($subTable, current($pastArray), $fields); next($pastArray); } } else { foreach ($fields as $field) { $currentData->filter('Piwik_MultiSites_CalculateEvolutionFilter', array($pastData, $this->evolutionColumnNames[$field], $field, $quotientPrecision = 2)); } } }
/** * 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 string $segment The segment. * @return Piwik_DataTable */ public function getByDayOfWeek($idSite, $period, $date, $segment = false) { Piwik::checkUserHasViewAccess($idSite); // disabled for multiple sites/dates if (Piwik_Archive::isMultipleSites($idSite)) { throw new Exception("VisitTime.getByDayOfWeek does not support multiple sites."); } if (Piwik_Archive::isMultiplePeriod($date, $period)) { throw new Exception("VisitTime.getByDayOfWeek does not support multiple dates."); } // metrics to query $metrics = Piwik_ArchiveProcessing::getCoreMetrics(); // get metric data for every day within the supplied period $oSite = new Piwik_Site($idSite); $oPeriod = Piwik_Archive::makePeriodFromQueryParams($oSite, $period, $date); $dateRange = $oPeriod->getDateStart()->toString() . ',' . $oPeriod->getDateEnd()->toString(); $archive = Piwik_Archive::build($idSite, 'day', $dateRange, $segment); $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', 'Piwik_VisitTime_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 Piwik_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', 'Piwik_VisitTime_translateDayOfWeek')); // set datatable metadata for period start & finish $result->setMetadata('date_start', $oPeriod->getDateStart()); $result->setMetadata('date_end', $oPeriod->getDateEnd()); return $result; }
/** * Performs a binary filter of two * DataTables in order to correctly calculate evolution metrics. * * @param Piwik_DataTable|Piwik_DataTable_Array $currentData * @param Piwik_DataTable|Piwik_DataTable_Array $pastData * @param array $fields The array of string fields to calculate evolution * metrics for. */ private function calculateEvolutionPercentages($currentData, $pastData, $apiMetrics) { if ($currentData instanceof Piwik_DataTable_Array) { $pastArray = $pastData->getArray(); foreach ($currentData->getArray() as $subTable) { $this->calculateEvolutionPercentages($subTable, current($pastArray), $apiMetrics); next($pastArray); } } else { foreach ($apiMetrics as $metricSettings) { $currentData->filter('Piwik_MultiSites_CalculateEvolutionFilter', array($pastData, $metricSettings[self::METRIC_EVOLUTION_COL_NAME_KEY], $metricSettings[self::METRIC_RECORD_NAME_KEY], $quotientPrecision = 2)); } } }
/** * Executes filter and removes all rows below the defined minimum * * @param Piwik_DataTable $table */ function filter($table) { $table->filter('ColumnCallbackDeleteRow', array($this->columnToFilter, array("Piwik_DataTable_Filter_ExcludeLowPopulation", "excludeLowPopulation"))); }
/** * Utility function. Gets row count of a set of tables grouped by the 'name' column. * This is the implementation of the getRowCountsAndSizeBy... functions. */ private function getRowCountsByArchiveName($statuses, $getRowSizeMethod, $forceCache = false, $otherSelects = array(), $otherDataTableColumns = array()) { $extraCols = ''; if (!empty($otherSelects)) { $extraCols = ', ' . implode(', ', $otherSelects); } $cols = array_merge(array('row_count'), $otherDataTableColumns); $dataTable = new Piwik_DataTable(); foreach ($statuses as $status) { $dataTableOptionName = $this->getCachedOptionName($status['Name'], 'byArchiveName'); // if option exists && !$forceCache, use the cached data, otherwise create the $cachedData = Piwik_GetOption($dataTableOptionName); if ($cachedData !== false && !$forceCache) { $table = new Piwik_DataTable(); $table->addRowsFromSerializedArray($cachedData); } else { // otherwise, create data table & cache it $sql = "SELECT name as 'label', COUNT(*) as 'row_count'{$extraCols} FROM {$status['Name']} GROUP BY name"; $table = new Piwik_DataTable(); $table->addRowsFromSimpleArray(Piwik_FetchAll($sql)); $reduceArchiveRowName = array($this, 'reduceArchiveRowName'); $table->filter('GroupBy', array('label', $reduceArchiveRowName)); $serializedTables = $table->getSerialized(); $serializedTable = reset($serializedTables); Piwik_SetOption($dataTableOptionName, $serializedTable); } // add estimated_size column $getEstimatedSize = array($this, $getRowSizeMethod); $table->filter('ColumnCallbackAddColumn', array($cols, 'estimated_size', $getEstimatedSize, array($status))); $dataTable->addDataTable($table); destroy($table); } return $dataTable; }
/** * Removes DataTable rows referencing actions that were never the last action of a visit. * * @param Piwik_DataTable $dataTable */ private function filterNonExitActions($dataTable) { $dataTable->filter('ColumnCallbackDeleteRow', array('exit_nb_visits', 'strlen')); }