From 823c219c73c1a155782c12b5a2689b9b25b9152c Mon Sep 17 00:00:00 2001 From: mattab <matthieu.aubry@gmail.com> Date: Thu, 20 Jun 2013 16:20:26 +1200 Subject: [PATCH] RowEvolution simplified --- core/API/DataTableManipulator/LabelFilter.php | 4 +- core/Metrics.php | 77 ++++++------- core/Piwik.php | 15 ++- plugins/API/API.php | 40 +++---- plugins/API/RowEvolution.php | 104 +++++++++--------- 5 files changed, 113 insertions(+), 127 deletions(-) diff --git a/core/API/DataTableManipulator/LabelFilter.php b/core/API/DataTableManipulator/LabelFilter.php index e8bad21c6a..6830511895 100644 --- a/core/API/DataTableManipulator/LabelFilter.php +++ b/core/API/DataTableManipulator/LabelFilter.php @@ -26,6 +26,7 @@ class Piwik_API_DataTableManipulator_LabelFilter extends Piwik_API_DataTableMani private $labels; private $addLabelIndex; + const FLAG_IS_ROW_EVOLUTION = 'label_index'; /** * Filter a data table by label. @@ -148,9 +149,8 @@ class Piwik_API_DataTableManipulator_LabelFilter extends Piwik_API_DataTableMani $row = $this->doFilterRecursiveDescend($labelVariation, $dataTable); if ($row) { if ($this->addLabelIndex) { - $row->setMetadata('label_index', $labelIndex); + $row->setMetadata(self::FLAG_IS_ROW_EVOLUTION, $labelIndex); } - $result->addRow($row); break; } diff --git a/core/Metrics.php b/core/Metrics.php index bbe43d3efa..3b10a7f377 100644 --- a/core/Metrics.php +++ b/core/Metrics.php @@ -33,11 +33,9 @@ class Piwik_Metrics // Specific to the Actions reports const INDEX_PAGE_NB_HITS = 12; const INDEX_PAGE_SUM_TIME_SPENT = 13; - const INDEX_PAGE_EXIT_NB_UNIQ_VISITORS = 14; const INDEX_PAGE_EXIT_NB_VISITS = 15; const INDEX_PAGE_EXIT_SUM_DAILY_NB_UNIQ_VISITORS = 16; - const INDEX_PAGE_ENTRY_NB_UNIQ_VISITORS = 17; const INDEX_PAGE_ENTRY_SUM_DAILY_NB_UNIQ_VISITORS = 18; const INDEX_PAGE_ENTRY_NB_VISITS = 19; @@ -66,14 +64,12 @@ class Piwik_Metrics const INDEX_GOAL_NB_CONVERSIONS = 1; const INDEX_GOAL_REVENUE = 2; const INDEX_GOAL_NB_VISITS_CONVERTED = 3; - const INDEX_GOAL_ECOMMERCE_REVENUE_SUBTOTAL = 4; const INDEX_GOAL_ECOMMERCE_REVENUE_TAX = 5; const INDEX_GOAL_ECOMMERCE_REVENUE_SHIPPING = 6; const INDEX_GOAL_ECOMMERCE_REVENUE_DISCOUNT = 7; const INDEX_GOAL_ECOMMERCE_ITEMS = 8; - - public static $mappingFromIdToName = array( + static public $mappingFromIdToName = array( Piwik_Metrics::INDEX_NB_UNIQ_VISITORS => 'nb_uniq_visitors', Piwik_Metrics::INDEX_NB_VISITS => 'nb_visits', Piwik_Metrics::INDEX_NB_ACTIONS => 'nb_actions', @@ -113,8 +109,7 @@ class Piwik_Metrics Piwik_Metrics::INDEX_ECOMMERCE_ITEM_PRICE_VIEWED => 'price_viewed', Piwik_Metrics::INDEX_ECOMMERCE_ORDERS => 'orders', ); - - public static $mappingFromIdToNameGoal = array( + static public $mappingFromIdToNameGoal = array( Piwik_Metrics::INDEX_GOAL_NB_CONVERSIONS => 'nb_conversions', Piwik_Metrics::INDEX_GOAL_NB_VISITS_CONVERTED => 'nb_visits_converted', Piwik_Metrics::INDEX_GOAL_REVENUE => 'revenue', @@ -124,8 +119,20 @@ class Piwik_Metrics Piwik_Metrics::INDEX_GOAL_ECOMMERCE_REVENUE_DISCOUNT => 'revenue_discount', Piwik_Metrics::INDEX_GOAL_ECOMMERCE_ITEMS => 'items', ); - - protected static $metricsAggregatedFromLogs = array( + static public $mappingFromNameToId = array( + 'nb_uniq_visitors' => Piwik_Metrics::INDEX_NB_UNIQ_VISITORS, + 'nb_visits' => Piwik_Metrics::INDEX_NB_VISITS, + 'nb_actions' => Piwik_Metrics::INDEX_NB_ACTIONS, + 'max_actions' => Piwik_Metrics::INDEX_MAX_ACTIONS, + 'sum_visit_length' => Piwik_Metrics::INDEX_SUM_VISIT_LENGTH, + 'bounce_count' => Piwik_Metrics::INDEX_BOUNCE_COUNT, + 'nb_visits_converted' => Piwik_Metrics::INDEX_NB_VISITS_CONVERTED, + 'nb_conversions' => Piwik_Metrics::INDEX_NB_CONVERSIONS, + 'revenue' => Piwik_Metrics::INDEX_REVENUE, + 'goals' => Piwik_Metrics::INDEX_GOALS, + 'sum_daily_nb_uniq_visitors' => Piwik_Metrics::INDEX_SUM_DAILY_NB_UNIQ_VISITORS, + ); + static protected $metricsAggregatedFromLogs = array( Piwik_Metrics::INDEX_NB_UNIQ_VISITORS, Piwik_Metrics::INDEX_NB_VISITS, Piwik_Metrics::INDEX_NB_ACTIONS, @@ -135,35 +142,22 @@ class Piwik_Metrics Piwik_Metrics::INDEX_NB_VISITS_CONVERTED, ); - public static function getVisitsMetricNames() + /* Used in DataTable Sort filter */ + + static public function getVisitsMetricNames() { $names = array(); - foreach(self::$metricsAggregatedFromLogs as $metricId) { + foreach (self::$metricsAggregatedFromLogs as $metricId) { $names[$metricId] = self::$mappingFromIdToName[$metricId]; } return $names; } - /* Used in DataTable Sort filter */ - public static function getMappingFromIdToName() + static public function getMappingFromIdToName() { $idToName = array_flip(self::$mappingFromIdToName); return $idToName; } - public static $mappingFromNameToId = array( - 'nb_uniq_visitors' => Piwik_Metrics::INDEX_NB_UNIQ_VISITORS, - 'nb_visits' => Piwik_Metrics::INDEX_NB_VISITS, - 'nb_actions' => Piwik_Metrics::INDEX_NB_ACTIONS, - 'max_actions' => Piwik_Metrics::INDEX_MAX_ACTIONS, - 'sum_visit_length' => Piwik_Metrics::INDEX_SUM_VISIT_LENGTH, - 'bounce_count' => Piwik_Metrics::INDEX_BOUNCE_COUNT, - 'nb_visits_converted' => Piwik_Metrics::INDEX_NB_VISITS_CONVERTED, - 'nb_conversions' => Piwik_Metrics::INDEX_NB_CONVERSIONS, - 'revenue' => Piwik_Metrics::INDEX_REVENUE, - 'goals' => Piwik_Metrics::INDEX_GOALS, - 'sum_daily_nb_uniq_visitors' => Piwik_Metrics::INDEX_SUM_DAILY_NB_UNIQ_VISITORS, - ); - /** * Is a lower value for a given column better? @@ -211,7 +205,7 @@ class Piwik_Metrics return ''; } - public static function getDefaultMetricTranslations() + static public function getDefaultMetricTranslations() { $trans = array( 'label' => 'General_ColumnLabel', @@ -265,7 +259,19 @@ class Piwik_Metrics return $translations; } - public function getDefaultMetricsDocumentation() + static public function getDefaultProcessedMetrics() + { + $translations = array( + // Processed in AddColumnsProcessedMetrics + 'nb_actions_per_visit' => 'General_ColumnActionsPerVisit', + 'avg_time_on_site' => 'General_ColumnAvgTimeOnSite', + 'bounce_rate' => 'General_ColumnBounceRate', + 'conversion_rate' => 'General_ColumnConversionRate', + ); + return array_map('Piwik_Translate', $translations); + } + + static public function getDefaultMetricsDocumentation() { $documentation = array( 'nb_visits' => 'General_ColumnNbVisitsDocumentation', @@ -281,17 +287,4 @@ class Piwik_Metrics ); return array_map('Piwik_Translate', $documentation); } - public function getDefaultProcessedMetrics() - { - $translations = array( - // Processed in AddColumnsProcessedMetrics - 'nb_actions_per_visit' => 'General_ColumnActionsPerVisit', - 'avg_time_on_site' => 'General_ColumnAvgTimeOnSite', - 'bounce_rate' => 'General_ColumnBounceRate', - 'conversion_rate' => 'General_ColumnConversionRate', - ); - return array_map('Piwik_Translate', $translations); - } - - } \ No newline at end of file diff --git a/core/Piwik.php b/core/Piwik.php index b21b501342..f604a551dd 100644 --- a/core/Piwik.php +++ b/core/Piwik.php @@ -1883,12 +1883,15 @@ class Piwik */ static public function getArrayFromApiParameter($columns) { - return $columns === false - ? array() - : (is_array($columns) - ? $columns - : explode(',', $columns) - ); + if(empty($columns)) { + return array(); + } + if(is_array($columns)) { + return $columns; + } + $array = explode(',', $columns); + $array = array_unique($array); + return $array; } /** diff --git a/plugins/API/API.php b/plugins/API/API.php index ad2689afb7..3c25cebf9e 100644 --- a/plugins/API/API.php +++ b/plugins/API/API.php @@ -66,7 +66,6 @@ class Piwik_API extends Piwik_Plugin } } - /** * This API is the <a href='http://piwik.org/docs/analytics-api/metadata/' target='_blank'>Metadata API</a>: it gives information about all other available APIs methods, as well as providing * human readable and more complete outputs than normal API methods. @@ -183,7 +182,7 @@ class Piwik_API_API $segments[] = array( 'type' => 'dimension', 'category' => Piwik_Translate('General_Visit'), - 'name' => Piwik_Translate('General_VisitType') , + 'name' => Piwik_Translate('General_VisitType'), 'segment' => 'visitorType', 'acceptedValues' => 'new, returning, returningCustomer' . ". " . Piwik_Translate('General_VisitTypeExample', '"&segment=visitorType==returning,visitorType==returningCustomer"'), 'sqlSegment' => 'log_visit.visitor_returning', @@ -226,7 +225,7 @@ class Piwik_API_API 'name' => Piwik_Translate('General_EcommerceVisitStatusDesc'), 'segment' => 'visitEcommerceStatus', 'acceptedValues' => implode(", ", self::$visitEcommerceStatus) - . '. '. Piwik_Translate('General_EcommerceVisitStatusEg', '"&segment=visitEcommerceStatus==ordered,visitEcommerceStatus==orderedThenAbandonedCart"'), + . '. ' . Piwik_Translate('General_EcommerceVisitStatusEg', '"&segment=visitEcommerceStatus==ordered,visitEcommerceStatus==orderedThenAbandonedCart"'), 'sqlSegment' => 'log_visit.visit_goal_buyer', 'sqlFilter' => array('Piwik_API_API', 'getVisitEcommerceStatus'), ); @@ -496,7 +495,7 @@ class Piwik_API_API $availableReport['metricsDocumentation'] = $this->hideShowMetrics($availableReport['metricsDocumentation']); } - + // Remove array elements that are false (to clean up API output) foreach ($availableReport as $attributeName => $attributeValue) { if (empty($attributeValue)) { @@ -535,7 +534,6 @@ class Piwik_API_API return array_values($availableReports); // make sure array has contiguous key values } - /** * Add the metadata for the API.get report * In other plugins, this would hook on 'API.getReportMetadata' @@ -610,10 +608,10 @@ class Piwik_API_API /** @var Piwik_DataTable */ $dataTable = $request->process(); } catch (Exception $e) { - throw new Exception("API returned an error: " . $e->getMessage() . " at " . basename($e->getFile()). ":" . $e->getLine() . "\n"); + throw new Exception("API returned an error: " . $e->getMessage() . " at " . basename($e->getFile()) . ":" . $e->getLine() . "\n"); } - list($newReport, $columns, $rowsMetadata) = $this->handleTableReport($idSite, $dataTable, $reportMetadata, isset($reportMetadata['dimension']), $showRawMetrics); + list($newReport, $columns, $rowsMetadata) = $this->handleTableReport($idSite, $dataTable, $reportMetadata, $showRawMetrics); foreach ($columns as $columnId => &$name) { $name = ucfirst($name); } @@ -653,8 +651,9 @@ class Piwik_API_API * @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, $showRawMetrics = false) + private function handleTableReport($idSite, $dataTable, &$reportMetadata, $showRawMetrics = false) { + $hasDimension = isset($reportMetadata['dimension']); $columns = $reportMetadata['metrics']; if ($hasDimension) { @@ -986,7 +985,6 @@ class Piwik_API_API return $mergedDataTable; } - /** * Merge the columns of two data tables. * Manipulates the first table. @@ -1012,7 +1010,6 @@ class Piwik_API_API } } - /** * Given an API report to query (eg. "Referers.getKeywords", and a Label (eg. "free%20software"), * this function will query the API for the previous days/weeks/etc. and will return @@ -1023,7 +1020,7 @@ class Piwik_API_API public function getRowEvolution($idSite, $period, $date, $apiModule, $apiAction, $label = false, $segment = false, $column = false, $language = false, $idGoal = false, $legendAppendMetric = true, $labelUseAbsoluteUrl = true) { $rowEvolution = new Piwik_API_RowEvolution(); - return $rowEvolution->getRowEvolution($idSite, $period, $date, $apiModule, $apiAction, $label, $segment, $column, + return $rowEvolution->getRowEvolution($idSite, $period, $date, $apiModule, $apiAction, $label, $segment, $column, $language, $idGoal, $legendAppendMetric, $labelUseAbsoluteUrl); } @@ -1039,7 +1036,7 @@ class Piwik_API_API } $urls = array_map('urldecode', $urls); - $urls = array_map(array('Piwik_Common','unsanitizeInputValue'), $urls); + $urls = array_map(array('Piwik_Common', 'unsanitizeInputValue'), $urls); $result = array(); foreach ($urls as $url) { @@ -1062,13 +1059,13 @@ class Piwik_API_API $segmentsMetadata = $this->getSegmentsMetadata($idSite, $_hideImplementationData = false); $segmentFound = false; - foreach($segmentsMetadata as $segmentMetadata) { - if($segmentMetadata['segment'] == $segmentName) { + foreach ($segmentsMetadata as $segmentMetadata) { + if ($segmentMetadata['segment'] == $segmentName) { $segmentFound = $segmentMetadata; break; } } - if(empty($segmentFound)) { + if (empty($segmentFound)) { throw new Exception("Requested segment not found."); } @@ -1083,10 +1080,10 @@ class Piwik_API_API // Select non empty fields only // Note: this optimization has only a very minor impact - $requestLastVisits.= "&segment=$segmentName".urlencode('!='); + $requestLastVisits .= "&segment=$segmentName" . urlencode('!='); // By default Live fetches all actions for all visitors, but we'd rather do this only when required - if($this->doesSegmentNeedActionsData($segmentName)) { + if ($this->doesSegmentNeedActionsData($segmentName)) { $requestLastVisits .= "&filter_limit=500"; } else { $requestLastVisits .= "&doNotFetchActions=1"; @@ -1095,7 +1092,7 @@ class Piwik_API_API $request = new Piwik_API_Request($requestLastVisits); $table = $request->process(); - if(empty($table)) { + if (empty($table)) { throw new Exception("There was no data to suggest for $segmentName"); } @@ -1107,14 +1104,14 @@ class Piwik_API_API $values = array_merge($values, $valuesBis); // remove false values (while keeping zeros) - $values = array_filter( $values, 'strlen' ); + $values = array_filter($values, 'strlen'); // we have a list of all values. let's show the most frequently used first. - $values = array_count_values( $values ); + $values = array_count_values($values); arsort($values); $values = array_keys($values); - $values = array_map( array('Piwik_Common', 'unsanitizeInputValue'), $values); + $values = array_map(array('Piwik_Common', 'unsanitizeInputValue'), $values); $values = array_slice($values, 0, $maxSuggestionsToReturn); return $values; @@ -1133,5 +1130,4 @@ class Piwik_API_API $doesSegmentNeedActionsInfo = in_array($segmentName, $segmentsNeedActionsInfo) || $isCustomVariablePage; return $doesSegmentNeedActionsInfo; } - } diff --git a/plugins/API/RowEvolution.php b/plugins/API/RowEvolution.php index 14ea35f36d..2daac7083b 100644 --- a/plugins/API/RowEvolution.php +++ b/plugins/API/RowEvolution.php @@ -30,84 +30,81 @@ class Piwik_API_RowEvolution } $label = Piwik_API_ResponseBuilder::unsanitizeLabelParameter($label); - if ($label) { - $labels = explode(',', $label); - $labels = array_unique($labels); - } else { - $labels = array(); - } + $labels = Piwik::getArrayFromApiParameter($label); + $dataTable = $this->loadRowEvolutionDataFromAPI($idSite, $period, $date, $apiModule, $apiAction, $labels, $segment, $idGoal); if (empty($labels)) { - // if no labels specified, use all possible labels as list - foreach ($dataTable->getArray() as $table) { - $labels = array_merge($labels, $table->getColumn('label')); - } - $labels = array_values(array_unique($labels)); - - // if the filter_limit query param is set, treat it as a request to limit - // the number of labels used - $limit = Piwik_Common::getRequestVar('filter_limit', false); - if ($limit != false - && $limit >= 0 - ) { - $labels = array_slice($labels, 0, $limit); - } - - // set label index metadata - $labelsToIndex = array_flip($labels); - foreach ($dataTable->getArray() as $table) { - foreach ($table->getRows() as $row) { - $label = $row->getColumn('label'); - if (isset($labelsToIndex[$label])) { - $row->setMetadata('label_index', $labelsToIndex[$label]); - } - } - } + $labels = $this->getLabelsFromDataTable($dataTable, $labels); + $dataTable = $this->enrichRowAddMetadataLabelIndex($labels, $dataTable); } + $metadata = $this->getRowEvolutionMetaData($idSite, $period, $date, $apiModule, $apiAction, $language, $idGoal); if (count($labels) != 1) { $data = $this->getMultiRowEvolution( $dataTable, - $idSite, - $period, - $date, + $metadata, $apiModule, $apiAction, $labels, - $segment, $column, - $language, - $idGoal, $legendAppendMetric, $labelUseAbsoluteUrl ); } else { $data = $this->getSingleRowEvolution( $dataTable, - $idSite, - $period, - $date, + $metadata, $apiModule, $apiAction, $labels[0], - $segment, - $language, - $idGoal, $labelUseAbsoluteUrl ); } return $data; } + protected function enrichRowAddMetadataLabelIndex($labels, $dataTable) + { + // set label index metadata + $labelsToIndex = array_flip($labels); + foreach ($dataTable->getArray() as $table) { + foreach ($table->getRows() as $row) { + $label = $row->getColumn('label'); + if (isset($labelsToIndex[$label])) { + $row->setMetadata(Piwik_API_DataTableManipulator_LabelFilter::FLAG_IS_ROW_EVOLUTION, $labelsToIndex[$label]); + } + } + } + return $dataTable; + } + + protected function getLabelsFromDataTable($dataTable, $labels) + { + // if no labels specified, use all possible labels as list + foreach ($dataTable->getArray() as $table) { + $labels = array_merge($labels, $table->getColumn('label')); + } + $labels = array_values(array_unique($labels)); + + // if the filter_limit query param is set, treat it as a request to limit + // the number of labels used + $limit = Piwik_Common::getRequestVar('filter_limit', false); + if ($limit != false + && $limit >= 0 + ) { + $labels = array_slice($labels, 0, $limit); + } + return $labels; + } + /** * Get row evolution for a single label * @return array containing report data, metadata, label, logo */ - private function getSingleRowEvolution($dataTable, $idSite, $period, $date, $apiModule, $apiAction, $label, $segment, $language = false, $idGoal = false, $labelUseAbsoluteUrl = true) + private function getSingleRowEvolution($dataTable, $metadata, $apiModule, $apiAction, $label, $labelUseAbsoluteUrl = true) { - $metadata = $this->getRowEvolutionMetaData($idSite, $period, $date, $apiModule, $apiAction, $language, $idGoal); $metricNames = array_keys($metadata['metrics']); $logo = $actualLabel = false; @@ -127,7 +124,6 @@ class Piwik_API_RowEvolution if (empty($actualLabel)) { $actualLabel = $row->getColumn('label'); } - } // remove all columns that are not in the available metrics. @@ -138,7 +134,6 @@ class Piwik_API_RowEvolution $row->deleteColumn($column); } } - $row->deleteMetadata(); } } @@ -261,7 +256,8 @@ class Piwik_API_RowEvolution if (!empty($idGoal) && $idGoal > 0) { $apiParameters = array('idGoal' => $idGoal); } - $reportMetadata = $this->getMetadata($idSite, $apiModule, $apiAction, $apiParameters, $language, $period, $date, $hideMetricsDoc = false, $showSubtableReports = true); + $reportMetadata = Piwik_API_API::getInstance()->getMetadata($idSite, $apiModule, $apiAction, $apiParameters, $language, + $period, $date, $hideMetricsDoc = false, $showSubtableReports = true); if (empty($reportMetadata)) { throw new Exception("Requested report $apiModule.$apiAction for Website id=$idSite " @@ -349,12 +345,10 @@ class Piwik_API_RowEvolution } /** Get row evolution for a multiple labels */ - private function getMultiRowEvolution($dataTable, $idSite, $period, $date, $apiModule, $apiAction, $labels, $segment, $column, $language = false, $idGoal = false, $legendAppendMetric = true, $labelUseAbsoluteUrl = true) + private function getMultiRowEvolution($dataTable, $metadata, $apiModule, $apiAction, $labels, $column, + $legendAppendMetric = true, + $labelUseAbsoluteUrl = true) { - $actualLabels = $logos = array(); - - $metadata = $this->getRowEvolutionMetaData($idSite, $period, $date, $apiModule, $apiAction, $language, $idGoal); - if (!isset($metadata['metrics'][$column])) { // invalid column => use the first one that's available $metrics = array_keys($metadata['metrics']); @@ -443,7 +437,7 @@ class Piwik_API_RowEvolution } /** - * Returns the row in a datatable by its label_index metadata. + * Returns the row in a datatable by its Piwik_API_DataTableManipulator_LabelFilter::FLAG_IS_ROW_EVOLUTION metadata. * * @param Piwik_DataTable $table * @param int $labelIdx @@ -454,7 +448,7 @@ class Piwik_API_RowEvolution $labelIdx = (int)$labelIdx; foreach ($table->getRows() as $row) { - if ($row->getMetadata('label_index') === $labelIdx) + if ($row->getMetadata(Piwik_API_DataTableManipulator_LabelFilter::FLAG_IS_ROW_EVOLUTION) === $labelIdx) { return $row; } -- GitLab